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",
650                 "Roo.app", "Roo.ux",
651                 "Roo.bootstrap",
652                 "Roo.bootstrap.dash");
653 /*
654  * Based on:
655  * Ext JS Library 1.1.1
656  * Copyright(c) 2006-2007, Ext JS, LLC.
657  *
658  * Originally Released Under LGPL - original licence link has changed is not relivant.
659  *
660  * Fork - LGPL
661  * <script type="text/javascript">
662  */
663
664 (function() {    
665     // wrappedn so fnCleanup is not in global scope...
666     if(Roo.isIE) {
667         function fnCleanUp() {
668             var p = Function.prototype;
669             delete p.createSequence;
670             delete p.defer;
671             delete p.createDelegate;
672             delete p.createCallback;
673             delete p.createInterceptor;
674
675             window.detachEvent("onunload", fnCleanUp);
676         }
677         window.attachEvent("onunload", fnCleanUp);
678     }
679 })();
680
681
682 /**
683  * @class Function
684  * These functions are available on every Function object (any JavaScript function).
685  */
686 Roo.apply(Function.prototype, {
687      /**
688      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
689      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
690      * Will create a function that is bound to those 2 args.
691      * @return {Function} The new function
692     */
693     createCallback : function(/*args...*/){
694         // make args available, in function below
695         var args = arguments;
696         var method = this;
697         return function() {
698             return method.apply(window, args);
699         };
700     },
701
702     /**
703      * Creates a delegate (callback) that sets the scope to obj.
704      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
705      * Will create a function that is automatically scoped to this.
706      * @param {Object} obj (optional) The object for which the scope is set
707      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
708      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
709      *                                             if a number the args are inserted at the specified position
710      * @return {Function} The new function
711      */
712     createDelegate : function(obj, args, appendArgs){
713         var method = this;
714         return function() {
715             var callArgs = args || arguments;
716             if(appendArgs === true){
717                 callArgs = Array.prototype.slice.call(arguments, 0);
718                 callArgs = callArgs.concat(args);
719             }else if(typeof appendArgs == "number"){
720                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
721                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
722                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
723             }
724             return method.apply(obj || window, callArgs);
725         };
726     },
727
728     /**
729      * Calls this function after the number of millseconds specified.
730      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
731      * @param {Object} obj (optional) The object for which the scope is set
732      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
733      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
734      *                                             if a number the args are inserted at the specified position
735      * @return {Number} The timeout id that can be used with clearTimeout
736      */
737     defer : function(millis, obj, args, appendArgs){
738         var fn = this.createDelegate(obj, args, appendArgs);
739         if(millis){
740             return setTimeout(fn, millis);
741         }
742         fn();
743         return 0;
744     },
745     /**
746      * Create a combined function call sequence of the original function + the passed function.
747      * The resulting function returns the results of the original function.
748      * The passed fcn is called with the parameters of the original function
749      * @param {Function} fcn The function to sequence
750      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
751      * @return {Function} The new function
752      */
753     createSequence : function(fcn, scope){
754         if(typeof fcn != "function"){
755             return this;
756         }
757         var method = this;
758         return function() {
759             var retval = method.apply(this || window, arguments);
760             fcn.apply(scope || this || window, arguments);
761             return retval;
762         };
763     },
764
765     /**
766      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
767      * The resulting function returns the results of the original function.
768      * The passed fcn is called with the parameters of the original function.
769      * @addon
770      * @param {Function} fcn The function to call before the original
771      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
772      * @return {Function} The new function
773      */
774     createInterceptor : function(fcn, scope){
775         if(typeof fcn != "function"){
776             return this;
777         }
778         var method = this;
779         return function() {
780             fcn.target = this;
781             fcn.method = method;
782             if(fcn.apply(scope || this || window, arguments) === false){
783                 return;
784             }
785             return method.apply(this || window, arguments);
786         };
787     }
788 });
789 /*
790  * Based on:
791  * Ext JS Library 1.1.1
792  * Copyright(c) 2006-2007, Ext JS, LLC.
793  *
794  * Originally Released Under LGPL - original licence link has changed is not relivant.
795  *
796  * Fork - LGPL
797  * <script type="text/javascript">
798  */
799
800 Roo.applyIf(String, {
801     
802     /** @scope String */
803     
804     /**
805      * Escapes the passed string for ' and \
806      * @param {String} string The string to escape
807      * @return {String} The escaped string
808      * @static
809      */
810     escape : function(string) {
811         return string.replace(/('|\\)/g, "\\$1");
812     },
813
814     /**
815      * Pads the left side of a string with a specified character.  This is especially useful
816      * for normalizing number and date strings.  Example usage:
817      * <pre><code>
818 var s = String.leftPad('123', 5, '0');
819 // s now contains the string: '00123'
820 </code></pre>
821      * @param {String} string The original string
822      * @param {Number} size The total length of the output string
823      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
824      * @return {String} The padded string
825      * @static
826      */
827     leftPad : function (val, size, ch) {
828         var result = new String(val);
829         if(ch === null || ch === undefined || ch === '') {
830             ch = " ";
831         }
832         while (result.length < size) {
833             result = ch + result;
834         }
835         return result;
836     },
837
838     /**
839      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
840      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
841      * <pre><code>
842 var cls = 'my-class', text = 'Some text';
843 var s = String.format('<div class="{0}">{1}</div>', cls, text);
844 // s now contains the string: '<div class="my-class">Some text</div>'
845 </code></pre>
846      * @param {String} string The tokenized string to be formatted
847      * @param {String} value1 The value to replace token {0}
848      * @param {String} value2 Etc...
849      * @return {String} The formatted string
850      * @static
851      */
852     format : function(format){
853         var args = Array.prototype.slice.call(arguments, 1);
854         return format.replace(/\{(\d+)\}/g, function(m, i){
855             return Roo.util.Format.htmlEncode(args[i]);
856         });
857     }
858 });
859
860 /**
861  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
862  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
863  * they are already different, the first value passed in is returned.  Note that this method returns the new value
864  * but does not change the current string.
865  * <pre><code>
866 // alternate sort directions
867 sort = sort.toggle('ASC', 'DESC');
868
869 // instead of conditional logic:
870 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
871 </code></pre>
872  * @param {String} value The value to compare to the current string
873  * @param {String} other The new value to use if the string already equals the first value passed in
874  * @return {String} The new value
875  */
876  
877 String.prototype.toggle = function(value, other){
878     return this == value ? other : value;
879 };/*
880  * Based on:
881  * Ext JS Library 1.1.1
882  * Copyright(c) 2006-2007, Ext JS, LLC.
883  *
884  * Originally Released Under LGPL - original licence link has changed is not relivant.
885  *
886  * Fork - LGPL
887  * <script type="text/javascript">
888  */
889
890  /**
891  * @class Number
892  */
893 Roo.applyIf(Number.prototype, {
894     /**
895      * Checks whether or not the current number is within a desired range.  If the number is already within the
896      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
897      * exceeded.  Note that this method returns the constrained value but does not change the current number.
898      * @param {Number} min The minimum number in the range
899      * @param {Number} max The maximum number in the range
900      * @return {Number} The constrained value if outside the range, otherwise the current value
901      */
902     constrain : function(min, max){
903         return Math.min(Math.max(this, min), max);
904     }
905 });/*
906  * Based on:
907  * Ext JS Library 1.1.1
908  * Copyright(c) 2006-2007, Ext JS, LLC.
909  *
910  * Originally Released Under LGPL - original licence link has changed is not relivant.
911  *
912  * Fork - LGPL
913  * <script type="text/javascript">
914  */
915  /**
916  * @class Array
917  */
918 Roo.applyIf(Array.prototype, {
919     /**
920      * Checks whether or not the specified object exists in the array.
921      * @param {Object} o The object to check for
922      * @return {Number} The index of o in the array (or -1 if it is not found)
923      */
924     indexOf : function(o){
925        for (var i = 0, len = this.length; i < len; i++){
926               if(this[i] == o) return i;
927        }
928            return -1;
929     },
930
931     /**
932      * Removes the specified object from the array.  If the object is not found nothing happens.
933      * @param {Object} o The object to remove
934      */
935     remove : function(o){
936        var index = this.indexOf(o);
937        if(index != -1){
938            this.splice(index, 1);
939        }
940     },
941     /**
942      * Map (JS 1.6 compatibility)
943      * @param {Function} function  to call
944      */
945     map : function(fun )
946     {
947         var len = this.length >>> 0;
948         if (typeof fun != "function")
949             throw new TypeError();
950
951         var res = new Array(len);
952         var thisp = arguments[1];
953         for (var i = 0; i < len; i++)
954         {
955             if (i in this)
956                 res[i] = fun.call(thisp, this[i], i, this);
957         }
958
959         return res;
960     }
961     
962 });
963
964
965  /*
966  * Based on:
967  * Ext JS Library 1.1.1
968  * Copyright(c) 2006-2007, Ext JS, LLC.
969  *
970  * Originally Released Under LGPL - original licence link has changed is not relivant.
971  *
972  * Fork - LGPL
973  * <script type="text/javascript">
974  */
975
976 /**
977  * @class Date
978  *
979  * The date parsing and format syntax is a subset of
980  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
981  * supported will provide results equivalent to their PHP versions.
982  *
983  * Following is the list of all currently supported formats:
984  *<pre>
985 Sample date:
986 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
987
988 Format  Output      Description
989 ------  ----------  --------------------------------------------------------------
990   d      10         Day of the month, 2 digits with leading zeros
991   D      Wed        A textual representation of a day, three letters
992   j      10         Day of the month without leading zeros
993   l      Wednesday  A full textual representation of the day of the week
994   S      th         English ordinal day of month suffix, 2 chars (use with j)
995   w      3          Numeric representation of the day of the week
996   z      9          The julian date, or day of the year (0-365)
997   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
998   F      January    A full textual representation of the month
999   m      01         Numeric representation of a month, with leading zeros
1000   M      Jan        Month name abbreviation, three letters
1001   n      1          Numeric representation of a month, without leading zeros
1002   t      31         Number of days in the given month
1003   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1004   Y      2007       A full numeric representation of a year, 4 digits
1005   y      07         A two digit representation of a year
1006   a      pm         Lowercase Ante meridiem and Post meridiem
1007   A      PM         Uppercase Ante meridiem and Post meridiem
1008   g      3          12-hour format of an hour without leading zeros
1009   G      15         24-hour format of an hour without leading zeros
1010   h      03         12-hour format of an hour with leading zeros
1011   H      15         24-hour format of an hour with leading zeros
1012   i      05         Minutes with leading zeros
1013   s      01         Seconds, with leading zeros
1014   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1015   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1016   T      CST        Timezone setting of the machine running the code
1017   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1018 </pre>
1019  *
1020  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1021  * <pre><code>
1022 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1023 document.write(dt.format('Y-m-d'));                         //2007-01-10
1024 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1025 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1026  </code></pre>
1027  *
1028  * Here are some standard date/time patterns that you might find helpful.  They
1029  * are not part of the source of Date.js, but to use them you can simply copy this
1030  * block of code into any script that is included after Date.js and they will also become
1031  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1032  * <pre><code>
1033 Date.patterns = {
1034     ISO8601Long:"Y-m-d H:i:s",
1035     ISO8601Short:"Y-m-d",
1036     ShortDate: "n/j/Y",
1037     LongDate: "l, F d, Y",
1038     FullDateTime: "l, F d, Y g:i:s A",
1039     MonthDay: "F d",
1040     ShortTime: "g:i A",
1041     LongTime: "g:i:s A",
1042     SortableDateTime: "Y-m-d\\TH:i:s",
1043     UniversalSortableDateTime: "Y-m-d H:i:sO",
1044     YearMonth: "F, Y"
1045 };
1046 </code></pre>
1047  *
1048  * Example usage:
1049  * <pre><code>
1050 var dt = new Date();
1051 document.write(dt.format(Date.patterns.ShortDate));
1052  </code></pre>
1053  */
1054
1055 /*
1056  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1057  * They generate precompiled functions from date formats instead of parsing and
1058  * processing the pattern every time you format a date.  These functions are available
1059  * on every Date object (any javascript function).
1060  *
1061  * The original article and download are here:
1062  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1063  *
1064  */
1065  
1066  
1067  // was in core
1068 /**
1069  Returns the number of milliseconds between this date and date
1070  @param {Date} date (optional) Defaults to now
1071  @return {Number} The diff in milliseconds
1072  @member Date getElapsed
1073  */
1074 Date.prototype.getElapsed = function(date) {
1075         return Math.abs((date || new Date()).getTime()-this.getTime());
1076 };
1077 // was in date file..
1078
1079
1080 // private
1081 Date.parseFunctions = {count:0};
1082 // private
1083 Date.parseRegexes = [];
1084 // private
1085 Date.formatFunctions = {count:0};
1086
1087 // private
1088 Date.prototype.dateFormat = function(format) {
1089     if (Date.formatFunctions[format] == null) {
1090         Date.createNewFormat(format);
1091     }
1092     var func = Date.formatFunctions[format];
1093     return this[func]();
1094 };
1095
1096
1097 /**
1098  * Formats a date given the supplied format string
1099  * @param {String} format The format string
1100  * @return {String} The formatted date
1101  * @method
1102  */
1103 Date.prototype.format = Date.prototype.dateFormat;
1104
1105 // private
1106 Date.createNewFormat = function(format) {
1107     var funcName = "format" + Date.formatFunctions.count++;
1108     Date.formatFunctions[format] = funcName;
1109     var code = "Date.prototype." + funcName + " = function(){return ";
1110     var special = false;
1111     var ch = '';
1112     for (var i = 0; i < format.length; ++i) {
1113         ch = format.charAt(i);
1114         if (!special && ch == "\\") {
1115             special = true;
1116         }
1117         else if (special) {
1118             special = false;
1119             code += "'" + String.escape(ch) + "' + ";
1120         }
1121         else {
1122             code += Date.getFormatCode(ch);
1123         }
1124     }
1125     /** eval:var:zzzzzzzzzzzzz */
1126     eval(code.substring(0, code.length - 3) + ";}");
1127 };
1128
1129 // private
1130 Date.getFormatCode = function(character) {
1131     switch (character) {
1132     case "d":
1133         return "String.leftPad(this.getDate(), 2, '0') + ";
1134     case "D":
1135         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1136     case "j":
1137         return "this.getDate() + ";
1138     case "l":
1139         return "Date.dayNames[this.getDay()] + ";
1140     case "S":
1141         return "this.getSuffix() + ";
1142     case "w":
1143         return "this.getDay() + ";
1144     case "z":
1145         return "this.getDayOfYear() + ";
1146     case "W":
1147         return "this.getWeekOfYear() + ";
1148     case "F":
1149         return "Date.monthNames[this.getMonth()] + ";
1150     case "m":
1151         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1152     case "M":
1153         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1154     case "n":
1155         return "(this.getMonth() + 1) + ";
1156     case "t":
1157         return "this.getDaysInMonth() + ";
1158     case "L":
1159         return "(this.isLeapYear() ? 1 : 0) + ";
1160     case "Y":
1161         return "this.getFullYear() + ";
1162     case "y":
1163         return "('' + this.getFullYear()).substring(2, 4) + ";
1164     case "a":
1165         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1166     case "A":
1167         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1168     case "g":
1169         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1170     case "G":
1171         return "this.getHours() + ";
1172     case "h":
1173         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1174     case "H":
1175         return "String.leftPad(this.getHours(), 2, '0') + ";
1176     case "i":
1177         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1178     case "s":
1179         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1180     case "O":
1181         return "this.getGMTOffset() + ";
1182     case "P":
1183         return "this.getGMTColonOffset() + ";
1184     case "T":
1185         return "this.getTimezone() + ";
1186     case "Z":
1187         return "(this.getTimezoneOffset() * -60) + ";
1188     default:
1189         return "'" + String.escape(character) + "' + ";
1190     }
1191 };
1192
1193 /**
1194  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1195  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1196  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1197  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1198  * string or the parse operation will fail.
1199  * Example Usage:
1200 <pre><code>
1201 //dt = Fri May 25 2007 (current date)
1202 var dt = new Date();
1203
1204 //dt = Thu May 25 2006 (today's month/day in 2006)
1205 dt = Date.parseDate("2006", "Y");
1206
1207 //dt = Sun Jan 15 2006 (all date parts specified)
1208 dt = Date.parseDate("2006-1-15", "Y-m-d");
1209
1210 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1211 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1212 </code></pre>
1213  * @param {String} input The unparsed date as a string
1214  * @param {String} format The format the date is in
1215  * @return {Date} The parsed date
1216  * @static
1217  */
1218 Date.parseDate = function(input, format) {
1219     if (Date.parseFunctions[format] == null) {
1220         Date.createParser(format);
1221     }
1222     var func = Date.parseFunctions[format];
1223     return Date[func](input);
1224 };
1225 /**
1226  * @private
1227  */
1228 Date.createParser = function(format) {
1229     var funcName = "parse" + Date.parseFunctions.count++;
1230     var regexNum = Date.parseRegexes.length;
1231     var currentGroup = 1;
1232     Date.parseFunctions[format] = funcName;
1233
1234     var code = "Date." + funcName + " = function(input){\n"
1235         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1236         + "var d = new Date();\n"
1237         + "y = d.getFullYear();\n"
1238         + "m = d.getMonth();\n"
1239         + "d = d.getDate();\n"
1240         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1241         + "if (results && results.length > 0) {";
1242     var regex = "";
1243
1244     var special = false;
1245     var ch = '';
1246     for (var i = 0; i < format.length; ++i) {
1247         ch = format.charAt(i);
1248         if (!special && ch == "\\") {
1249             special = true;
1250         }
1251         else if (special) {
1252             special = false;
1253             regex += String.escape(ch);
1254         }
1255         else {
1256             var obj = Date.formatCodeToRegex(ch, currentGroup);
1257             currentGroup += obj.g;
1258             regex += obj.s;
1259             if (obj.g && obj.c) {
1260                 code += obj.c;
1261             }
1262         }
1263     }
1264
1265     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1266         + "{v = new Date(y, m, d, h, i, s);}\n"
1267         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1268         + "{v = new Date(y, m, d, h, i);}\n"
1269         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1270         + "{v = new Date(y, m, d, h);}\n"
1271         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1272         + "{v = new Date(y, m, d);}\n"
1273         + "else if (y >= 0 && m >= 0)\n"
1274         + "{v = new Date(y, m);}\n"
1275         + "else if (y >= 0)\n"
1276         + "{v = new Date(y);}\n"
1277         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1278         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1279         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1280         + ";}";
1281
1282     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1283     /** eval:var:zzzzzzzzzzzzz */
1284     eval(code);
1285 };
1286
1287 // private
1288 Date.formatCodeToRegex = function(character, currentGroup) {
1289     switch (character) {
1290     case "D":
1291         return {g:0,
1292         c:null,
1293         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1294     case "j":
1295         return {g:1,
1296             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1297             s:"(\\d{1,2})"}; // day of month without leading zeroes
1298     case "d":
1299         return {g:1,
1300             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1301             s:"(\\d{2})"}; // day of month with leading zeroes
1302     case "l":
1303         return {g:0,
1304             c:null,
1305             s:"(?:" + Date.dayNames.join("|") + ")"};
1306     case "S":
1307         return {g:0,
1308             c:null,
1309             s:"(?:st|nd|rd|th)"};
1310     case "w":
1311         return {g:0,
1312             c:null,
1313             s:"\\d"};
1314     case "z":
1315         return {g:0,
1316             c:null,
1317             s:"(?:\\d{1,3})"};
1318     case "W":
1319         return {g:0,
1320             c:null,
1321             s:"(?:\\d{2})"};
1322     case "F":
1323         return {g:1,
1324             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1325             s:"(" + Date.monthNames.join("|") + ")"};
1326     case "M":
1327         return {g:1,
1328             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1329             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1330     case "n":
1331         return {g:1,
1332             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1333             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1334     case "m":
1335         return {g:1,
1336             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1337             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1338     case "t":
1339         return {g:0,
1340             c:null,
1341             s:"\\d{1,2}"};
1342     case "L":
1343         return {g:0,
1344             c:null,
1345             s:"(?:1|0)"};
1346     case "Y":
1347         return {g:1,
1348             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1349             s:"(\\d{4})"};
1350     case "y":
1351         return {g:1,
1352             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1353                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1354             s:"(\\d{1,2})"};
1355     case "a":
1356         return {g:1,
1357             c:"if (results[" + currentGroup + "] == 'am') {\n"
1358                 + "if (h == 12) { h = 0; }\n"
1359                 + "} else { if (h < 12) { h += 12; }}",
1360             s:"(am|pm)"};
1361     case "A":
1362         return {g:1,
1363             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1364                 + "if (h == 12) { h = 0; }\n"
1365                 + "} else { if (h < 12) { h += 12; }}",
1366             s:"(AM|PM)"};
1367     case "g":
1368     case "G":
1369         return {g:1,
1370             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1371             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1372     case "h":
1373     case "H":
1374         return {g:1,
1375             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1376             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1377     case "i":
1378         return {g:1,
1379             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1380             s:"(\\d{2})"};
1381     case "s":
1382         return {g:1,
1383             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1384             s:"(\\d{2})"};
1385     case "O":
1386         return {g:1,
1387             c:[
1388                 "o = results[", currentGroup, "];\n",
1389                 "var sn = o.substring(0,1);\n", // get + / - sign
1390                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1391                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1392                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1393                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1394             ].join(""),
1395             s:"([+\-]\\d{2,4})"};
1396     
1397     
1398     case "P":
1399         return {g:1,
1400                 c:[
1401                    "o = results[", currentGroup, "];\n",
1402                    "var sn = o.substring(0,1);\n",
1403                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1404                    "var mn = o.substring(4,6) % 60;\n",
1405                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1406                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1407             ].join(""),
1408             s:"([+\-]\\d{4})"};
1409     case "T":
1410         return {g:0,
1411             c:null,
1412             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1413     case "Z":
1414         return {g:1,
1415             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1416                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1417             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1418     default:
1419         return {g:0,
1420             c:null,
1421             s:String.escape(character)};
1422     }
1423 };
1424
1425 /**
1426  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1427  * @return {String} The abbreviated timezone name (e.g. 'CST')
1428  */
1429 Date.prototype.getTimezone = function() {
1430     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1431 };
1432
1433 /**
1434  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1435  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1436  */
1437 Date.prototype.getGMTOffset = function() {
1438     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1439         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1440         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1441 };
1442
1443 /**
1444  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1445  * @return {String} 2-characters representing hours and 2-characters representing minutes
1446  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1447  */
1448 Date.prototype.getGMTColonOffset = function() {
1449         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1450                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1451                 + ":"
1452                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1453 }
1454
1455 /**
1456  * Get the numeric day number of the year, adjusted for leap year.
1457  * @return {Number} 0 through 364 (365 in leap years)
1458  */
1459 Date.prototype.getDayOfYear = function() {
1460     var num = 0;
1461     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1462     for (var i = 0; i < this.getMonth(); ++i) {
1463         num += Date.daysInMonth[i];
1464     }
1465     return num + this.getDate() - 1;
1466 };
1467
1468 /**
1469  * Get the string representation of the numeric week number of the year
1470  * (equivalent to the format specifier 'W').
1471  * @return {String} '00' through '52'
1472  */
1473 Date.prototype.getWeekOfYear = function() {
1474     // Skip to Thursday of this week
1475     var now = this.getDayOfYear() + (4 - this.getDay());
1476     // Find the first Thursday of the year
1477     var jan1 = new Date(this.getFullYear(), 0, 1);
1478     var then = (7 - jan1.getDay() + 4);
1479     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1480 };
1481
1482 /**
1483  * Whether or not the current date is in a leap year.
1484  * @return {Boolean} True if the current date is in a leap year, else false
1485  */
1486 Date.prototype.isLeapYear = function() {
1487     var year = this.getFullYear();
1488     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1489 };
1490
1491 /**
1492  * Get the first day of the current month, adjusted for leap year.  The returned value
1493  * is the numeric day index within the week (0-6) which can be used in conjunction with
1494  * the {@link #monthNames} array to retrieve the textual day name.
1495  * Example:
1496  *<pre><code>
1497 var dt = new Date('1/10/2007');
1498 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1499 </code></pre>
1500  * @return {Number} The day number (0-6)
1501  */
1502 Date.prototype.getFirstDayOfMonth = function() {
1503     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1504     return (day < 0) ? (day + 7) : day;
1505 };
1506
1507 /**
1508  * Get the last day of the current month, adjusted for leap year.  The returned value
1509  * is the numeric day index within the week (0-6) which can be used in conjunction with
1510  * the {@link #monthNames} array to retrieve the textual day name.
1511  * Example:
1512  *<pre><code>
1513 var dt = new Date('1/10/2007');
1514 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1515 </code></pre>
1516  * @return {Number} The day number (0-6)
1517  */
1518 Date.prototype.getLastDayOfMonth = function() {
1519     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1520     return (day < 0) ? (day + 7) : day;
1521 };
1522
1523
1524 /**
1525  * Get the first date of this date's month
1526  * @return {Date}
1527  */
1528 Date.prototype.getFirstDateOfMonth = function() {
1529     return new Date(this.getFullYear(), this.getMonth(), 1);
1530 };
1531
1532 /**
1533  * Get the last date of this date's month
1534  * @return {Date}
1535  */
1536 Date.prototype.getLastDateOfMonth = function() {
1537     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1538 };
1539 /**
1540  * Get the number of days in the current month, adjusted for leap year.
1541  * @return {Number} The number of days in the month
1542  */
1543 Date.prototype.getDaysInMonth = function() {
1544     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1545     return Date.daysInMonth[this.getMonth()];
1546 };
1547
1548 /**
1549  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1550  * @return {String} 'st, 'nd', 'rd' or 'th'
1551  */
1552 Date.prototype.getSuffix = function() {
1553     switch (this.getDate()) {
1554         case 1:
1555         case 21:
1556         case 31:
1557             return "st";
1558         case 2:
1559         case 22:
1560             return "nd";
1561         case 3:
1562         case 23:
1563             return "rd";
1564         default:
1565             return "th";
1566     }
1567 };
1568
1569 // private
1570 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1571
1572 /**
1573  * An array of textual month names.
1574  * Override these values for international dates, for example...
1575  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1576  * @type Array
1577  * @static
1578  */
1579 Date.monthNames =
1580    ["January",
1581     "February",
1582     "March",
1583     "April",
1584     "May",
1585     "June",
1586     "July",
1587     "August",
1588     "September",
1589     "October",
1590     "November",
1591     "December"];
1592
1593 /**
1594  * An array of textual day names.
1595  * Override these values for international dates, for example...
1596  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1597  * @type Array
1598  * @static
1599  */
1600 Date.dayNames =
1601    ["Sunday",
1602     "Monday",
1603     "Tuesday",
1604     "Wednesday",
1605     "Thursday",
1606     "Friday",
1607     "Saturday"];
1608
1609 // private
1610 Date.y2kYear = 50;
1611 // private
1612 Date.monthNumbers = {
1613     Jan:0,
1614     Feb:1,
1615     Mar:2,
1616     Apr:3,
1617     May:4,
1618     Jun:5,
1619     Jul:6,
1620     Aug:7,
1621     Sep:8,
1622     Oct:9,
1623     Nov:10,
1624     Dec:11};
1625
1626 /**
1627  * Creates and returns a new Date instance with the exact same date value as the called instance.
1628  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1629  * variable will also be changed.  When the intention is to create a new variable that will not
1630  * modify the original instance, you should create a clone.
1631  *
1632  * Example of correctly cloning a date:
1633  * <pre><code>
1634 //wrong way:
1635 var orig = new Date('10/1/2006');
1636 var copy = orig;
1637 copy.setDate(5);
1638 document.write(orig);  //returns 'Thu Oct 05 2006'!
1639
1640 //correct way:
1641 var orig = new Date('10/1/2006');
1642 var copy = orig.clone();
1643 copy.setDate(5);
1644 document.write(orig);  //returns 'Thu Oct 01 2006'
1645 </code></pre>
1646  * @return {Date} The new Date instance
1647  */
1648 Date.prototype.clone = function() {
1649         return new Date(this.getTime());
1650 };
1651
1652 /**
1653  * Clears any time information from this date
1654  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1655  @return {Date} this or the clone
1656  */
1657 Date.prototype.clearTime = function(clone){
1658     if(clone){
1659         return this.clone().clearTime();
1660     }
1661     this.setHours(0);
1662     this.setMinutes(0);
1663     this.setSeconds(0);
1664     this.setMilliseconds(0);
1665     return this;
1666 };
1667
1668 // private
1669 // safari setMonth is broken
1670 if(Roo.isSafari){
1671     Date.brokenSetMonth = Date.prototype.setMonth;
1672         Date.prototype.setMonth = function(num){
1673                 if(num <= -1){
1674                         var n = Math.ceil(-num);
1675                         var back_year = Math.ceil(n/12);
1676                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1677                         this.setFullYear(this.getFullYear() - back_year);
1678                         return Date.brokenSetMonth.call(this, month);
1679                 } else {
1680                         return Date.brokenSetMonth.apply(this, arguments);
1681                 }
1682         };
1683 }
1684
1685 /** Date interval constant 
1686 * @static 
1687 * @type String */
1688 Date.MILLI = "ms";
1689 /** Date interval constant 
1690 * @static 
1691 * @type String */
1692 Date.SECOND = "s";
1693 /** Date interval constant 
1694 * @static 
1695 * @type String */
1696 Date.MINUTE = "mi";
1697 /** Date interval constant 
1698 * @static 
1699 * @type String */
1700 Date.HOUR = "h";
1701 /** Date interval constant 
1702 * @static 
1703 * @type String */
1704 Date.DAY = "d";
1705 /** Date interval constant 
1706 * @static 
1707 * @type String */
1708 Date.MONTH = "mo";
1709 /** Date interval constant 
1710 * @static 
1711 * @type String */
1712 Date.YEAR = "y";
1713
1714 /**
1715  * Provides a convenient method of performing basic date arithmetic.  This method
1716  * does not modify the Date instance being called - it creates and returns
1717  * a new Date instance containing the resulting date value.
1718  *
1719  * Examples:
1720  * <pre><code>
1721 //Basic usage:
1722 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1723 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1724
1725 //Negative values will subtract correctly:
1726 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1727 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1728
1729 //You can even chain several calls together in one line!
1730 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1731 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1732  </code></pre>
1733  *
1734  * @param {String} interval   A valid date interval enum value
1735  * @param {Number} value      The amount to add to the current date
1736  * @return {Date} The new Date instance
1737  */
1738 Date.prototype.add = function(interval, value){
1739   var d = this.clone();
1740   if (!interval || value === 0) return d;
1741   switch(interval.toLowerCase()){
1742     case Date.MILLI:
1743       d.setMilliseconds(this.getMilliseconds() + value);
1744       break;
1745     case Date.SECOND:
1746       d.setSeconds(this.getSeconds() + value);
1747       break;
1748     case Date.MINUTE:
1749       d.setMinutes(this.getMinutes() + value);
1750       break;
1751     case Date.HOUR:
1752       d.setHours(this.getHours() + value);
1753       break;
1754     case Date.DAY:
1755       d.setDate(this.getDate() + value);
1756       break;
1757     case Date.MONTH:
1758       var day = this.getDate();
1759       if(day > 28){
1760           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1761       }
1762       d.setDate(day);
1763       d.setMonth(this.getMonth() + value);
1764       break;
1765     case Date.YEAR:
1766       d.setFullYear(this.getFullYear() + value);
1767       break;
1768   }
1769   return d;
1770 };
1771 /*
1772  * Based on:
1773  * Ext JS Library 1.1.1
1774  * Copyright(c) 2006-2007, Ext JS, LLC.
1775  *
1776  * Originally Released Under LGPL - original licence link has changed is not relivant.
1777  *
1778  * Fork - LGPL
1779  * <script type="text/javascript">
1780  */
1781
1782 /**
1783  * @class Roo.lib.Dom
1784  * @static
1785  * 
1786  * Dom utils (from YIU afaik)
1787  * 
1788  **/
1789 Roo.lib.Dom = {
1790     /**
1791      * Get the view width
1792      * @param {Boolean} full True will get the full document, otherwise it's the view width
1793      * @return {Number} The width
1794      */
1795      
1796     getViewWidth : function(full) {
1797         return full ? this.getDocumentWidth() : this.getViewportWidth();
1798     },
1799     /**
1800      * Get the view height
1801      * @param {Boolean} full True will get the full document, otherwise it's the view height
1802      * @return {Number} The height
1803      */
1804     getViewHeight : function(full) {
1805         return full ? this.getDocumentHeight() : this.getViewportHeight();
1806     },
1807
1808     getDocumentHeight: function() {
1809         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1810         return Math.max(scrollHeight, this.getViewportHeight());
1811     },
1812
1813     getDocumentWidth: function() {
1814         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1815         return Math.max(scrollWidth, this.getViewportWidth());
1816     },
1817
1818     getViewportHeight: function() {
1819         var height = self.innerHeight;
1820         var mode = document.compatMode;
1821
1822         if ((mode || Roo.isIE) && !Roo.isOpera) {
1823             height = (mode == "CSS1Compat") ?
1824                      document.documentElement.clientHeight :
1825                      document.body.clientHeight;
1826         }
1827
1828         return height;
1829     },
1830
1831     getViewportWidth: function() {
1832         var width = self.innerWidth;
1833         var mode = document.compatMode;
1834
1835         if (mode || Roo.isIE) {
1836             width = (mode == "CSS1Compat") ?
1837                     document.documentElement.clientWidth :
1838                     document.body.clientWidth;
1839         }
1840         return width;
1841     },
1842
1843     isAncestor : function(p, c) {
1844         p = Roo.getDom(p);
1845         c = Roo.getDom(c);
1846         if (!p || !c) {
1847             return false;
1848         }
1849
1850         if (p.contains && !Roo.isSafari) {
1851             return p.contains(c);
1852         } else if (p.compareDocumentPosition) {
1853             return !!(p.compareDocumentPosition(c) & 16);
1854         } else {
1855             var parent = c.parentNode;
1856             while (parent) {
1857                 if (parent == p) {
1858                     return true;
1859                 }
1860                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1861                     return false;
1862                 }
1863                 parent = parent.parentNode;
1864             }
1865             return false;
1866         }
1867     },
1868
1869     getRegion : function(el) {
1870         return Roo.lib.Region.getRegion(el);
1871     },
1872
1873     getY : function(el) {
1874         return this.getXY(el)[1];
1875     },
1876
1877     getX : function(el) {
1878         return this.getXY(el)[0];
1879     },
1880
1881     getXY : function(el) {
1882         var p, pe, b, scroll, bd = document.body;
1883         el = Roo.getDom(el);
1884         var fly = Roo.lib.AnimBase.fly;
1885         if (el.getBoundingClientRect) {
1886             b = el.getBoundingClientRect();
1887             scroll = fly(document).getScroll();
1888             return [b.left + scroll.left, b.top + scroll.top];
1889         }
1890         var x = 0, y = 0;
1891
1892         p = el;
1893
1894         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1895
1896         while (p) {
1897
1898             x += p.offsetLeft;
1899             y += p.offsetTop;
1900
1901             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1902                 hasAbsolute = true;
1903             }
1904
1905             if (Roo.isGecko) {
1906                 pe = fly(p);
1907
1908                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1909                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1910
1911
1912                 x += bl;
1913                 y += bt;
1914
1915
1916                 if (p != el && pe.getStyle('overflow') != 'visible') {
1917                     x += bl;
1918                     y += bt;
1919                 }
1920             }
1921             p = p.offsetParent;
1922         }
1923
1924         if (Roo.isSafari && hasAbsolute) {
1925             x -= bd.offsetLeft;
1926             y -= bd.offsetTop;
1927         }
1928
1929         if (Roo.isGecko && !hasAbsolute) {
1930             var dbd = fly(bd);
1931             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1932             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1933         }
1934
1935         p = el.parentNode;
1936         while (p && p != bd) {
1937             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1938                 x -= p.scrollLeft;
1939                 y -= p.scrollTop;
1940             }
1941             p = p.parentNode;
1942         }
1943         return [x, y];
1944     },
1945  
1946   
1947
1948
1949     setXY : function(el, xy) {
1950         el = Roo.fly(el, '_setXY');
1951         el.position();
1952         var pts = el.translatePoints(xy);
1953         if (xy[0] !== false) {
1954             el.dom.style.left = pts.left + "px";
1955         }
1956         if (xy[1] !== false) {
1957             el.dom.style.top = pts.top + "px";
1958         }
1959     },
1960
1961     setX : function(el, x) {
1962         this.setXY(el, [x, false]);
1963     },
1964
1965     setY : function(el, y) {
1966         this.setXY(el, [false, y]);
1967     }
1968 };
1969 /*
1970  * Portions of this file are based on pieces of Yahoo User Interface Library
1971  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1972  * YUI licensed under the BSD License:
1973  * http://developer.yahoo.net/yui/license.txt
1974  * <script type="text/javascript">
1975  *
1976  */
1977
1978 Roo.lib.Event = function() {
1979     var loadComplete = false;
1980     var listeners = [];
1981     var unloadListeners = [];
1982     var retryCount = 0;
1983     var onAvailStack = [];
1984     var counter = 0;
1985     var lastError = null;
1986
1987     return {
1988         POLL_RETRYS: 200,
1989         POLL_INTERVAL: 20,
1990         EL: 0,
1991         TYPE: 1,
1992         FN: 2,
1993         WFN: 3,
1994         OBJ: 3,
1995         ADJ_SCOPE: 4,
1996         _interval: null,
1997
1998         startInterval: function() {
1999             if (!this._interval) {
2000                 var self = this;
2001                 var callback = function() {
2002                     self._tryPreloadAttach();
2003                 };
2004                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2005
2006             }
2007         },
2008
2009         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2010             onAvailStack.push({ id:         p_id,
2011                 fn:         p_fn,
2012                 obj:        p_obj,
2013                 override:   p_override,
2014                 checkReady: false    });
2015
2016             retryCount = this.POLL_RETRYS;
2017             this.startInterval();
2018         },
2019
2020
2021         addListener: function(el, eventName, fn) {
2022             el = Roo.getDom(el);
2023             if (!el || !fn) {
2024                 return false;
2025             }
2026
2027             if ("unload" == eventName) {
2028                 unloadListeners[unloadListeners.length] =
2029                 [el, eventName, fn];
2030                 return true;
2031             }
2032
2033             var wrappedFn = function(e) {
2034                 return fn(Roo.lib.Event.getEvent(e));
2035             };
2036
2037             var li = [el, eventName, fn, wrappedFn];
2038
2039             var index = listeners.length;
2040             listeners[index] = li;
2041
2042             this.doAdd(el, eventName, wrappedFn, false);
2043             return true;
2044
2045         },
2046
2047
2048         removeListener: function(el, eventName, fn) {
2049             var i, len;
2050
2051             el = Roo.getDom(el);
2052
2053             if(!fn) {
2054                 return this.purgeElement(el, false, eventName);
2055             }
2056
2057
2058             if ("unload" == eventName) {
2059
2060                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2061                     var li = unloadListeners[i];
2062                     if (li &&
2063                         li[0] == el &&
2064                         li[1] == eventName &&
2065                         li[2] == fn) {
2066                         unloadListeners.splice(i, 1);
2067                         return true;
2068                     }
2069                 }
2070
2071                 return false;
2072             }
2073
2074             var cacheItem = null;
2075
2076
2077             var index = arguments[3];
2078
2079             if ("undefined" == typeof index) {
2080                 index = this._getCacheIndex(el, eventName, fn);
2081             }
2082
2083             if (index >= 0) {
2084                 cacheItem = listeners[index];
2085             }
2086
2087             if (!el || !cacheItem) {
2088                 return false;
2089             }
2090
2091             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2092
2093             delete listeners[index][this.WFN];
2094             delete listeners[index][this.FN];
2095             listeners.splice(index, 1);
2096
2097             return true;
2098
2099         },
2100
2101
2102         getTarget: function(ev, resolveTextNode) {
2103             ev = ev.browserEvent || ev;
2104             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2105             var t = ev.target || ev.srcElement;
2106             return this.resolveTextNode(t);
2107         },
2108
2109
2110         resolveTextNode: function(node) {
2111             if (Roo.isSafari && node && 3 == node.nodeType) {
2112                 return node.parentNode;
2113             } else {
2114                 return node;
2115             }
2116         },
2117
2118
2119         getPageX: function(ev) {
2120             ev = ev.browserEvent || ev;
2121             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2122             var x = ev.pageX;
2123             if (!x && 0 !== x) {
2124                 x = ev.clientX || 0;
2125
2126                 if (Roo.isIE) {
2127                     x += this.getScroll()[1];
2128                 }
2129             }
2130
2131             return x;
2132         },
2133
2134
2135         getPageY: function(ev) {
2136             ev = ev.browserEvent || ev;
2137             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2138             var y = ev.pageY;
2139             if (!y && 0 !== y) {
2140                 y = ev.clientY || 0;
2141
2142                 if (Roo.isIE) {
2143                     y += this.getScroll()[0];
2144                 }
2145             }
2146
2147
2148             return y;
2149         },
2150
2151
2152         getXY: function(ev) {
2153             ev = ev.browserEvent || ev;
2154             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2155             return [this.getPageX(ev), this.getPageY(ev)];
2156         },
2157
2158
2159         getRelatedTarget: function(ev) {
2160             ev = ev.browserEvent || ev;
2161             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2162             var t = ev.relatedTarget;
2163             if (!t) {
2164                 if (ev.type == "mouseout") {
2165                     t = ev.toElement;
2166                 } else if (ev.type == "mouseover") {
2167                     t = ev.fromElement;
2168                 }
2169             }
2170
2171             return this.resolveTextNode(t);
2172         },
2173
2174
2175         getTime: function(ev) {
2176             ev = ev.browserEvent || ev;
2177             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2178             if (!ev.time) {
2179                 var t = new Date().getTime();
2180                 try {
2181                     ev.time = t;
2182                 } catch(ex) {
2183                     this.lastError = ex;
2184                     return t;
2185                 }
2186             }
2187
2188             return ev.time;
2189         },
2190
2191
2192         stopEvent: function(ev) {
2193             this.stopPropagation(ev);
2194             this.preventDefault(ev);
2195         },
2196
2197
2198         stopPropagation: function(ev) {
2199             ev = ev.browserEvent || ev;
2200             if (ev.stopPropagation) {
2201                 ev.stopPropagation();
2202             } else {
2203                 ev.cancelBubble = true;
2204             }
2205         },
2206
2207
2208         preventDefault: function(ev) {
2209             ev = ev.browserEvent || ev;
2210             if(ev.preventDefault) {
2211                 ev.preventDefault();
2212             } else {
2213                 ev.returnValue = false;
2214             }
2215         },
2216
2217
2218         getEvent: function(e) {
2219             var ev = e || window.event;
2220             if (!ev) {
2221                 var c = this.getEvent.caller;
2222                 while (c) {
2223                     ev = c.arguments[0];
2224                     if (ev && Event == ev.constructor) {
2225                         break;
2226                     }
2227                     c = c.caller;
2228                 }
2229             }
2230             return ev;
2231         },
2232
2233
2234         getCharCode: function(ev) {
2235             ev = ev.browserEvent || ev;
2236             return ev.charCode || ev.keyCode || 0;
2237         },
2238
2239
2240         _getCacheIndex: function(el, eventName, fn) {
2241             for (var i = 0,len = listeners.length; i < len; ++i) {
2242                 var li = listeners[i];
2243                 if (li &&
2244                     li[this.FN] == fn &&
2245                     li[this.EL] == el &&
2246                     li[this.TYPE] == eventName) {
2247                     return i;
2248                 }
2249             }
2250
2251             return -1;
2252         },
2253
2254
2255         elCache: {},
2256
2257
2258         getEl: function(id) {
2259             return document.getElementById(id);
2260         },
2261
2262
2263         clearCache: function() {
2264         },
2265
2266
2267         _load: function(e) {
2268             loadComplete = true;
2269             var EU = Roo.lib.Event;
2270
2271
2272             if (Roo.isIE) {
2273                 EU.doRemove(window, "load", EU._load);
2274             }
2275         },
2276
2277
2278         _tryPreloadAttach: function() {
2279
2280             if (this.locked) {
2281                 return false;
2282             }
2283
2284             this.locked = true;
2285
2286
2287             var tryAgain = !loadComplete;
2288             if (!tryAgain) {
2289                 tryAgain = (retryCount > 0);
2290             }
2291
2292
2293             var notAvail = [];
2294             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2295                 var item = onAvailStack[i];
2296                 if (item) {
2297                     var el = this.getEl(item.id);
2298
2299                     if (el) {
2300                         if (!item.checkReady ||
2301                             loadComplete ||
2302                             el.nextSibling ||
2303                             (document && document.body)) {
2304
2305                             var scope = el;
2306                             if (item.override) {
2307                                 if (item.override === true) {
2308                                     scope = item.obj;
2309                                 } else {
2310                                     scope = item.override;
2311                                 }
2312                             }
2313                             item.fn.call(scope, item.obj);
2314                             onAvailStack[i] = null;
2315                         }
2316                     } else {
2317                         notAvail.push(item);
2318                     }
2319                 }
2320             }
2321
2322             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2323
2324             if (tryAgain) {
2325
2326                 this.startInterval();
2327             } else {
2328                 clearInterval(this._interval);
2329                 this._interval = null;
2330             }
2331
2332             this.locked = false;
2333
2334             return true;
2335
2336         },
2337
2338
2339         purgeElement: function(el, recurse, eventName) {
2340             var elListeners = this.getListeners(el, eventName);
2341             if (elListeners) {
2342                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2343                     var l = elListeners[i];
2344                     this.removeListener(el, l.type, l.fn);
2345                 }
2346             }
2347
2348             if (recurse && el && el.childNodes) {
2349                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2350                     this.purgeElement(el.childNodes[i], recurse, eventName);
2351                 }
2352             }
2353         },
2354
2355
2356         getListeners: function(el, eventName) {
2357             var results = [], searchLists;
2358             if (!eventName) {
2359                 searchLists = [listeners, unloadListeners];
2360             } else if (eventName == "unload") {
2361                 searchLists = [unloadListeners];
2362             } else {
2363                 searchLists = [listeners];
2364             }
2365
2366             for (var j = 0; j < searchLists.length; ++j) {
2367                 var searchList = searchLists[j];
2368                 if (searchList && searchList.length > 0) {
2369                     for (var i = 0,len = searchList.length; i < len; ++i) {
2370                         var l = searchList[i];
2371                         if (l && l[this.EL] === el &&
2372                             (!eventName || eventName === l[this.TYPE])) {
2373                             results.push({
2374                                 type:   l[this.TYPE],
2375                                 fn:     l[this.FN],
2376                                 obj:    l[this.OBJ],
2377                                 adjust: l[this.ADJ_SCOPE],
2378                                 index:  i
2379                             });
2380                         }
2381                     }
2382                 }
2383             }
2384
2385             return (results.length) ? results : null;
2386         },
2387
2388
2389         _unload: function(e) {
2390
2391             var EU = Roo.lib.Event, i, j, l, len, index;
2392
2393             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2394                 l = unloadListeners[i];
2395                 if (l) {
2396                     var scope = window;
2397                     if (l[EU.ADJ_SCOPE]) {
2398                         if (l[EU.ADJ_SCOPE] === true) {
2399                             scope = l[EU.OBJ];
2400                         } else {
2401                             scope = l[EU.ADJ_SCOPE];
2402                         }
2403                     }
2404                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2405                     unloadListeners[i] = null;
2406                     l = null;
2407                     scope = null;
2408                 }
2409             }
2410
2411             unloadListeners = null;
2412
2413             if (listeners && listeners.length > 0) {
2414                 j = listeners.length;
2415                 while (j) {
2416                     index = j - 1;
2417                     l = listeners[index];
2418                     if (l) {
2419                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2420                                 l[EU.FN], index);
2421                     }
2422                     j = j - 1;
2423                 }
2424                 l = null;
2425
2426                 EU.clearCache();
2427             }
2428
2429             EU.doRemove(window, "unload", EU._unload);
2430
2431         },
2432
2433
2434         getScroll: function() {
2435             var dd = document.documentElement, db = document.body;
2436             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2437                 return [dd.scrollTop, dd.scrollLeft];
2438             } else if (db) {
2439                 return [db.scrollTop, db.scrollLeft];
2440             } else {
2441                 return [0, 0];
2442             }
2443         },
2444
2445
2446         doAdd: function () {
2447             if (window.addEventListener) {
2448                 return function(el, eventName, fn, capture) {
2449                     el.addEventListener(eventName, fn, (capture));
2450                 };
2451             } else if (window.attachEvent) {
2452                 return function(el, eventName, fn, capture) {
2453                     el.attachEvent("on" + eventName, fn);
2454                 };
2455             } else {
2456                 return function() {
2457                 };
2458             }
2459         }(),
2460
2461
2462         doRemove: function() {
2463             if (window.removeEventListener) {
2464                 return function (el, eventName, fn, capture) {
2465                     el.removeEventListener(eventName, fn, (capture));
2466                 };
2467             } else if (window.detachEvent) {
2468                 return function (el, eventName, fn) {
2469                     el.detachEvent("on" + eventName, fn);
2470                 };
2471             } else {
2472                 return function() {
2473                 };
2474             }
2475         }()
2476     };
2477     
2478 }();
2479 (function() {     
2480    
2481     var E = Roo.lib.Event;
2482     E.on = E.addListener;
2483     E.un = E.removeListener;
2484
2485     if (document && document.body) {
2486         E._load();
2487     } else {
2488         E.doAdd(window, "load", E._load);
2489     }
2490     E.doAdd(window, "unload", E._unload);
2491     E._tryPreloadAttach();
2492 })();
2493
2494 /*
2495  * Portions of this file are based on pieces of Yahoo User Interface Library
2496  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2497  * YUI licensed under the BSD License:
2498  * http://developer.yahoo.net/yui/license.txt
2499  * <script type="text/javascript">
2500  *
2501  */
2502
2503 (function() {
2504     /**
2505      * @class Roo.lib.Ajax
2506      *
2507      */
2508     Roo.lib.Ajax = {
2509         /**
2510          * @static 
2511          */
2512         request : function(method, uri, cb, data, options) {
2513             if(options){
2514                 var hs = options.headers;
2515                 if(hs){
2516                     for(var h in hs){
2517                         if(hs.hasOwnProperty(h)){
2518                             this.initHeader(h, hs[h], false);
2519                         }
2520                     }
2521                 }
2522                 if(options.xmlData){
2523                     this.initHeader('Content-Type', 'text/xml', false);
2524                     method = 'POST';
2525                     data = options.xmlData;
2526                 }
2527             }
2528
2529             return this.asyncRequest(method, uri, cb, data);
2530         },
2531
2532         serializeForm : function(form) {
2533             if(typeof form == 'string') {
2534                 form = (document.getElementById(form) || document.forms[form]);
2535             }
2536
2537             var el, name, val, disabled, data = '', hasSubmit = false;
2538             for (var i = 0; i < form.elements.length; i++) {
2539                 el = form.elements[i];
2540                 disabled = form.elements[i].disabled;
2541                 name = form.elements[i].name;
2542                 val = form.elements[i].value;
2543
2544                 if (!disabled && name){
2545                     switch (el.type)
2546                             {
2547                         case 'select-one':
2548                         case 'select-multiple':
2549                             for (var j = 0; j < el.options.length; j++) {
2550                                 if (el.options[j].selected) {
2551                                     if (Roo.isIE) {
2552                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2553                                     }
2554                                     else {
2555                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2556                                     }
2557                                 }
2558                             }
2559                             break;
2560                         case 'radio':
2561                         case 'checkbox':
2562                             if (el.checked) {
2563                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2564                             }
2565                             break;
2566                         case 'file':
2567
2568                         case undefined:
2569
2570                         case 'reset':
2571
2572                         case 'button':
2573
2574                             break;
2575                         case 'submit':
2576                             if(hasSubmit == false) {
2577                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2578                                 hasSubmit = true;
2579                             }
2580                             break;
2581                         default:
2582                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2583                             break;
2584                     }
2585                 }
2586             }
2587             data = data.substr(0, data.length - 1);
2588             return data;
2589         },
2590
2591         headers:{},
2592
2593         hasHeaders:false,
2594
2595         useDefaultHeader:true,
2596
2597         defaultPostHeader:'application/x-www-form-urlencoded',
2598
2599         useDefaultXhrHeader:true,
2600
2601         defaultXhrHeader:'XMLHttpRequest',
2602
2603         hasDefaultHeaders:true,
2604
2605         defaultHeaders:{},
2606
2607         poll:{},
2608
2609         timeout:{},
2610
2611         pollInterval:50,
2612
2613         transactionId:0,
2614
2615         setProgId:function(id)
2616         {
2617             this.activeX.unshift(id);
2618         },
2619
2620         setDefaultPostHeader:function(b)
2621         {
2622             this.useDefaultHeader = b;
2623         },
2624
2625         setDefaultXhrHeader:function(b)
2626         {
2627             this.useDefaultXhrHeader = b;
2628         },
2629
2630         setPollingInterval:function(i)
2631         {
2632             if (typeof i == 'number' && isFinite(i)) {
2633                 this.pollInterval = i;
2634             }
2635         },
2636
2637         createXhrObject:function(transactionId)
2638         {
2639             var obj,http;
2640             try
2641             {
2642
2643                 http = new XMLHttpRequest();
2644
2645                 obj = { conn:http, tId:transactionId };
2646             }
2647             catch(e)
2648             {
2649                 for (var i = 0; i < this.activeX.length; ++i) {
2650                     try
2651                     {
2652
2653                         http = new ActiveXObject(this.activeX[i]);
2654
2655                         obj = { conn:http, tId:transactionId };
2656                         break;
2657                     }
2658                     catch(e) {
2659                     }
2660                 }
2661             }
2662             finally
2663             {
2664                 return obj;
2665             }
2666         },
2667
2668         getConnectionObject:function()
2669         {
2670             var o;
2671             var tId = this.transactionId;
2672
2673             try
2674             {
2675                 o = this.createXhrObject(tId);
2676                 if (o) {
2677                     this.transactionId++;
2678                 }
2679             }
2680             catch(e) {
2681             }
2682             finally
2683             {
2684                 return o;
2685             }
2686         },
2687
2688         asyncRequest:function(method, uri, callback, postData)
2689         {
2690             var o = this.getConnectionObject();
2691
2692             if (!o) {
2693                 return null;
2694             }
2695             else {
2696                 o.conn.open(method, uri, true);
2697
2698                 if (this.useDefaultXhrHeader) {
2699                     if (!this.defaultHeaders['X-Requested-With']) {
2700                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2701                     }
2702                 }
2703
2704                 if(postData && this.useDefaultHeader){
2705                     this.initHeader('Content-Type', this.defaultPostHeader);
2706                 }
2707
2708                  if (this.hasDefaultHeaders || this.hasHeaders) {
2709                     this.setHeader(o);
2710                 }
2711
2712                 this.handleReadyState(o, callback);
2713                 o.conn.send(postData || null);
2714
2715                 return o;
2716             }
2717         },
2718
2719         handleReadyState:function(o, callback)
2720         {
2721             var oConn = this;
2722
2723             if (callback && callback.timeout) {
2724                 
2725                 this.timeout[o.tId] = window.setTimeout(function() {
2726                     oConn.abort(o, callback, true);
2727                 }, callback.timeout);
2728             }
2729
2730             this.poll[o.tId] = window.setInterval(
2731                     function() {
2732                         if (o.conn && o.conn.readyState == 4) {
2733                             window.clearInterval(oConn.poll[o.tId]);
2734                             delete oConn.poll[o.tId];
2735
2736                             if(callback && callback.timeout) {
2737                                 window.clearTimeout(oConn.timeout[o.tId]);
2738                                 delete oConn.timeout[o.tId];
2739                             }
2740
2741                             oConn.handleTransactionResponse(o, callback);
2742                         }
2743                     }
2744                     , this.pollInterval);
2745         },
2746
2747         handleTransactionResponse:function(o, callback, isAbort)
2748         {
2749
2750             if (!callback) {
2751                 this.releaseObject(o);
2752                 return;
2753             }
2754
2755             var httpStatus, responseObject;
2756
2757             try
2758             {
2759                 if (o.conn.status !== undefined && o.conn.status != 0) {
2760                     httpStatus = o.conn.status;
2761                 }
2762                 else {
2763                     httpStatus = 13030;
2764                 }
2765             }
2766             catch(e) {
2767
2768
2769                 httpStatus = 13030;
2770             }
2771
2772             if (httpStatus >= 200 && httpStatus < 300) {
2773                 responseObject = this.createResponseObject(o, callback.argument);
2774                 if (callback.success) {
2775                     if (!callback.scope) {
2776                         callback.success(responseObject);
2777                     }
2778                     else {
2779
2780
2781                         callback.success.apply(callback.scope, [responseObject]);
2782                     }
2783                 }
2784             }
2785             else {
2786                 switch (httpStatus) {
2787
2788                     case 12002:
2789                     case 12029:
2790                     case 12030:
2791                     case 12031:
2792                     case 12152:
2793                     case 13030:
2794                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2795                         if (callback.failure) {
2796                             if (!callback.scope) {
2797                                 callback.failure(responseObject);
2798                             }
2799                             else {
2800                                 callback.failure.apply(callback.scope, [responseObject]);
2801                             }
2802                         }
2803                         break;
2804                     default:
2805                         responseObject = this.createResponseObject(o, callback.argument);
2806                         if (callback.failure) {
2807                             if (!callback.scope) {
2808                                 callback.failure(responseObject);
2809                             }
2810                             else {
2811                                 callback.failure.apply(callback.scope, [responseObject]);
2812                             }
2813                         }
2814                 }
2815             }
2816
2817             this.releaseObject(o);
2818             responseObject = null;
2819         },
2820
2821         createResponseObject:function(o, callbackArg)
2822         {
2823             var obj = {};
2824             var headerObj = {};
2825
2826             try
2827             {
2828                 var headerStr = o.conn.getAllResponseHeaders();
2829                 var header = headerStr.split('\n');
2830                 for (var i = 0; i < header.length; i++) {
2831                     var delimitPos = header[i].indexOf(':');
2832                     if (delimitPos != -1) {
2833                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2834                     }
2835                 }
2836             }
2837             catch(e) {
2838             }
2839
2840             obj.tId = o.tId;
2841             obj.status = o.conn.status;
2842             obj.statusText = o.conn.statusText;
2843             obj.getResponseHeader = headerObj;
2844             obj.getAllResponseHeaders = headerStr;
2845             obj.responseText = o.conn.responseText;
2846             obj.responseXML = o.conn.responseXML;
2847
2848             if (typeof callbackArg !== undefined) {
2849                 obj.argument = callbackArg;
2850             }
2851
2852             return obj;
2853         },
2854
2855         createExceptionObject:function(tId, callbackArg, isAbort)
2856         {
2857             var COMM_CODE = 0;
2858             var COMM_ERROR = 'communication failure';
2859             var ABORT_CODE = -1;
2860             var ABORT_ERROR = 'transaction aborted';
2861
2862             var obj = {};
2863
2864             obj.tId = tId;
2865             if (isAbort) {
2866                 obj.status = ABORT_CODE;
2867                 obj.statusText = ABORT_ERROR;
2868             }
2869             else {
2870                 obj.status = COMM_CODE;
2871                 obj.statusText = COMM_ERROR;
2872             }
2873
2874             if (callbackArg) {
2875                 obj.argument = callbackArg;
2876             }
2877
2878             return obj;
2879         },
2880
2881         initHeader:function(label, value, isDefault)
2882         {
2883             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2884
2885             if (headerObj[label] === undefined) {
2886                 headerObj[label] = value;
2887             }
2888             else {
2889
2890
2891                 headerObj[label] = value + "," + headerObj[label];
2892             }
2893
2894             if (isDefault) {
2895                 this.hasDefaultHeaders = true;
2896             }
2897             else {
2898                 this.hasHeaders = true;
2899             }
2900         },
2901
2902
2903         setHeader:function(o)
2904         {
2905             if (this.hasDefaultHeaders) {
2906                 for (var prop in this.defaultHeaders) {
2907                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2908                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2909                     }
2910                 }
2911             }
2912
2913             if (this.hasHeaders) {
2914                 for (var prop in this.headers) {
2915                     if (this.headers.hasOwnProperty(prop)) {
2916                         o.conn.setRequestHeader(prop, this.headers[prop]);
2917                     }
2918                 }
2919                 this.headers = {};
2920                 this.hasHeaders = false;
2921             }
2922         },
2923
2924         resetDefaultHeaders:function() {
2925             delete this.defaultHeaders;
2926             this.defaultHeaders = {};
2927             this.hasDefaultHeaders = false;
2928         },
2929
2930         abort:function(o, callback, isTimeout)
2931         {
2932             if(this.isCallInProgress(o)) {
2933                 o.conn.abort();
2934                 window.clearInterval(this.poll[o.tId]);
2935                 delete this.poll[o.tId];
2936                 if (isTimeout) {
2937                     delete this.timeout[o.tId];
2938                 }
2939
2940                 this.handleTransactionResponse(o, callback, true);
2941
2942                 return true;
2943             }
2944             else {
2945                 return false;
2946             }
2947         },
2948
2949
2950         isCallInProgress:function(o)
2951         {
2952             if (o && o.conn) {
2953                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2954             }
2955             else {
2956
2957                 return false;
2958             }
2959         },
2960
2961
2962         releaseObject:function(o)
2963         {
2964
2965             o.conn = null;
2966
2967             o = null;
2968         },
2969
2970         activeX:[
2971         'MSXML2.XMLHTTP.3.0',
2972         'MSXML2.XMLHTTP',
2973         'Microsoft.XMLHTTP'
2974         ]
2975
2976
2977     };
2978 })();/*
2979  * Portions of this file are based on pieces of Yahoo User Interface Library
2980  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2981  * YUI licensed under the BSD License:
2982  * http://developer.yahoo.net/yui/license.txt
2983  * <script type="text/javascript">
2984  *
2985  */
2986
2987 Roo.lib.Region = function(t, r, b, l) {
2988     this.top = t;
2989     this[1] = t;
2990     this.right = r;
2991     this.bottom = b;
2992     this.left = l;
2993     this[0] = l;
2994 };
2995
2996
2997 Roo.lib.Region.prototype = {
2998     contains : function(region) {
2999         return ( region.left >= this.left &&
3000                  region.right <= this.right &&
3001                  region.top >= this.top &&
3002                  region.bottom <= this.bottom    );
3003
3004     },
3005
3006     getArea : function() {
3007         return ( (this.bottom - this.top) * (this.right - this.left) );
3008     },
3009
3010     intersect : function(region) {
3011         var t = Math.max(this.top, region.top);
3012         var r = Math.min(this.right, region.right);
3013         var b = Math.min(this.bottom, region.bottom);
3014         var l = Math.max(this.left, region.left);
3015
3016         if (b >= t && r >= l) {
3017             return new Roo.lib.Region(t, r, b, l);
3018         } else {
3019             return null;
3020         }
3021     },
3022     union : function(region) {
3023         var t = Math.min(this.top, region.top);
3024         var r = Math.max(this.right, region.right);
3025         var b = Math.max(this.bottom, region.bottom);
3026         var l = Math.min(this.left, region.left);
3027
3028         return new Roo.lib.Region(t, r, b, l);
3029     },
3030
3031     adjust : function(t, l, b, r) {
3032         this.top += t;
3033         this.left += l;
3034         this.right += r;
3035         this.bottom += b;
3036         return this;
3037     }
3038 };
3039
3040 Roo.lib.Region.getRegion = function(el) {
3041     var p = Roo.lib.Dom.getXY(el);
3042
3043     var t = p[1];
3044     var r = p[0] + el.offsetWidth;
3045     var b = p[1] + el.offsetHeight;
3046     var l = p[0];
3047
3048     return new Roo.lib.Region(t, r, b, l);
3049 };
3050 /*
3051  * Portions of this file are based on pieces of Yahoo User Interface Library
3052  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3053  * YUI licensed under the BSD License:
3054  * http://developer.yahoo.net/yui/license.txt
3055  * <script type="text/javascript">
3056  *
3057  */
3058 //@@dep Roo.lib.Region
3059
3060
3061 Roo.lib.Point = function(x, y) {
3062     if (x instanceof Array) {
3063         y = x[1];
3064         x = x[0];
3065     }
3066     this.x = this.right = this.left = this[0] = x;
3067     this.y = this.top = this.bottom = this[1] = y;
3068 };
3069
3070 Roo.lib.Point.prototype = new Roo.lib.Region();
3071 /*
3072  * Portions of this file are based on pieces of Yahoo User Interface Library
3073  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3074  * YUI licensed under the BSD License:
3075  * http://developer.yahoo.net/yui/license.txt
3076  * <script type="text/javascript">
3077  *
3078  */
3079  
3080 (function() {   
3081
3082     Roo.lib.Anim = {
3083         scroll : function(el, args, duration, easing, cb, scope) {
3084             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3085         },
3086
3087         motion : function(el, args, duration, easing, cb, scope) {
3088             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3089         },
3090
3091         color : function(el, args, duration, easing, cb, scope) {
3092             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3093         },
3094
3095         run : function(el, args, duration, easing, cb, scope, type) {
3096             type = type || Roo.lib.AnimBase;
3097             if (typeof easing == "string") {
3098                 easing = Roo.lib.Easing[easing];
3099             }
3100             var anim = new type(el, args, duration, easing);
3101             anim.animateX(function() {
3102                 Roo.callback(cb, scope);
3103             });
3104             return anim;
3105         }
3106     };
3107 })();/*
3108  * Portions of this file are based on pieces of Yahoo User Interface Library
3109  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3110  * YUI licensed under the BSD License:
3111  * http://developer.yahoo.net/yui/license.txt
3112  * <script type="text/javascript">
3113  *
3114  */
3115
3116 (function() {    
3117     var libFlyweight;
3118     
3119     function fly(el) {
3120         if (!libFlyweight) {
3121             libFlyweight = new Roo.Element.Flyweight();
3122         }
3123         libFlyweight.dom = el;
3124         return libFlyweight;
3125     }
3126
3127     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3128     
3129    
3130     
3131     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3132         if (el) {
3133             this.init(el, attributes, duration, method);
3134         }
3135     };
3136
3137     Roo.lib.AnimBase.fly = fly;
3138     
3139     
3140     
3141     Roo.lib.AnimBase.prototype = {
3142
3143         toString: function() {
3144             var el = this.getEl();
3145             var id = el.id || el.tagName;
3146             return ("Anim " + id);
3147         },
3148
3149         patterns: {
3150             noNegatives:        /width|height|opacity|padding/i,
3151             offsetAttribute:  /^((width|height)|(top|left))$/,
3152             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3153             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3154         },
3155
3156
3157         doMethod: function(attr, start, end) {
3158             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3159         },
3160
3161
3162         setAttribute: function(attr, val, unit) {
3163             if (this.patterns.noNegatives.test(attr)) {
3164                 val = (val > 0) ? val : 0;
3165             }
3166
3167             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3168         },
3169
3170
3171         getAttribute: function(attr) {
3172             var el = this.getEl();
3173             var val = fly(el).getStyle(attr);
3174
3175             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3176                 return parseFloat(val);
3177             }
3178
3179             var a = this.patterns.offsetAttribute.exec(attr) || [];
3180             var pos = !!( a[3] );
3181             var box = !!( a[2] );
3182
3183
3184             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3185                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3186             } else {
3187                 val = 0;
3188             }
3189
3190             return val;
3191         },
3192
3193
3194         getDefaultUnit: function(attr) {
3195             if (this.patterns.defaultUnit.test(attr)) {
3196                 return 'px';
3197             }
3198
3199             return '';
3200         },
3201
3202         animateX : function(callback, scope) {
3203             var f = function() {
3204                 this.onComplete.removeListener(f);
3205                 if (typeof callback == "function") {
3206                     callback.call(scope || this, this);
3207                 }
3208             };
3209             this.onComplete.addListener(f, this);
3210             this.animate();
3211         },
3212
3213
3214         setRuntimeAttribute: function(attr) {
3215             var start;
3216             var end;
3217             var attributes = this.attributes;
3218
3219             this.runtimeAttributes[attr] = {};
3220
3221             var isset = function(prop) {
3222                 return (typeof prop !== 'undefined');
3223             };
3224
3225             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3226                 return false;
3227             }
3228
3229             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3230
3231
3232             if (isset(attributes[attr]['to'])) {
3233                 end = attributes[attr]['to'];
3234             } else if (isset(attributes[attr]['by'])) {
3235                 if (start.constructor == Array) {
3236                     end = [];
3237                     for (var i = 0, len = start.length; i < len; ++i) {
3238                         end[i] = start[i] + attributes[attr]['by'][i];
3239                     }
3240                 } else {
3241                     end = start + attributes[attr]['by'];
3242                 }
3243             }
3244
3245             this.runtimeAttributes[attr].start = start;
3246             this.runtimeAttributes[attr].end = end;
3247
3248
3249             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3250         },
3251
3252
3253         init: function(el, attributes, duration, method) {
3254
3255             var isAnimated = false;
3256
3257
3258             var startTime = null;
3259
3260
3261             var actualFrames = 0;
3262
3263
3264             el = Roo.getDom(el);
3265
3266
3267             this.attributes = attributes || {};
3268
3269
3270             this.duration = duration || 1;
3271
3272
3273             this.method = method || Roo.lib.Easing.easeNone;
3274
3275
3276             this.useSeconds = true;
3277
3278
3279             this.currentFrame = 0;
3280
3281
3282             this.totalFrames = Roo.lib.AnimMgr.fps;
3283
3284
3285             this.getEl = function() {
3286                 return el;
3287             };
3288
3289
3290             this.isAnimated = function() {
3291                 return isAnimated;
3292             };
3293
3294
3295             this.getStartTime = function() {
3296                 return startTime;
3297             };
3298
3299             this.runtimeAttributes = {};
3300
3301
3302             this.animate = function() {
3303                 if (this.isAnimated()) {
3304                     return false;
3305                 }
3306
3307                 this.currentFrame = 0;
3308
3309                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3310
3311                 Roo.lib.AnimMgr.registerElement(this);
3312             };
3313
3314
3315             this.stop = function(finish) {
3316                 if (finish) {
3317                     this.currentFrame = this.totalFrames;
3318                     this._onTween.fire();
3319                 }
3320                 Roo.lib.AnimMgr.stop(this);
3321             };
3322
3323             var onStart = function() {
3324                 this.onStart.fire();
3325
3326                 this.runtimeAttributes = {};
3327                 for (var attr in this.attributes) {
3328                     this.setRuntimeAttribute(attr);
3329                 }
3330
3331                 isAnimated = true;
3332                 actualFrames = 0;
3333                 startTime = new Date();
3334             };
3335
3336
3337             var onTween = function() {
3338                 var data = {
3339                     duration: new Date() - this.getStartTime(),
3340                     currentFrame: this.currentFrame
3341                 };
3342
3343                 data.toString = function() {
3344                     return (
3345                             'duration: ' + data.duration +
3346                             ', currentFrame: ' + data.currentFrame
3347                             );
3348                 };
3349
3350                 this.onTween.fire(data);
3351
3352                 var runtimeAttributes = this.runtimeAttributes;
3353
3354                 for (var attr in runtimeAttributes) {
3355                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3356                 }
3357
3358                 actualFrames += 1;
3359             };
3360
3361             var onComplete = function() {
3362                 var actual_duration = (new Date() - startTime) / 1000 ;
3363
3364                 var data = {
3365                     duration: actual_duration,
3366                     frames: actualFrames,
3367                     fps: actualFrames / actual_duration
3368                 };
3369
3370                 data.toString = function() {
3371                     return (
3372                             'duration: ' + data.duration +
3373                             ', frames: ' + data.frames +
3374                             ', fps: ' + data.fps
3375                             );
3376                 };
3377
3378                 isAnimated = false;
3379                 actualFrames = 0;
3380                 this.onComplete.fire(data);
3381             };
3382
3383
3384             this._onStart = new Roo.util.Event(this);
3385             this.onStart = new Roo.util.Event(this);
3386             this.onTween = new Roo.util.Event(this);
3387             this._onTween = new Roo.util.Event(this);
3388             this.onComplete = new Roo.util.Event(this);
3389             this._onComplete = new Roo.util.Event(this);
3390             this._onStart.addListener(onStart);
3391             this._onTween.addListener(onTween);
3392             this._onComplete.addListener(onComplete);
3393         }
3394     };
3395 })();
3396 /*
3397  * Portions of this file are based on pieces of Yahoo User Interface Library
3398  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3399  * YUI licensed under the BSD License:
3400  * http://developer.yahoo.net/yui/license.txt
3401  * <script type="text/javascript">
3402  *
3403  */
3404
3405 Roo.lib.AnimMgr = new function() {
3406
3407     var thread = null;
3408
3409
3410     var queue = [];
3411
3412
3413     var tweenCount = 0;
3414
3415
3416     this.fps = 1000;
3417
3418
3419     this.delay = 1;
3420
3421
3422     this.registerElement = function(tween) {
3423         queue[queue.length] = tween;
3424         tweenCount += 1;
3425         tween._onStart.fire();
3426         this.start();
3427     };
3428
3429
3430     this.unRegister = function(tween, index) {
3431         tween._onComplete.fire();
3432         index = index || getIndex(tween);
3433         if (index != -1) {
3434             queue.splice(index, 1);
3435         }
3436
3437         tweenCount -= 1;
3438         if (tweenCount <= 0) {
3439             this.stop();
3440         }
3441     };
3442
3443
3444     this.start = function() {
3445         if (thread === null) {
3446             thread = setInterval(this.run, this.delay);
3447         }
3448     };
3449
3450
3451     this.stop = function(tween) {
3452         if (!tween) {
3453             clearInterval(thread);
3454
3455             for (var i = 0, len = queue.length; i < len; ++i) {
3456                 if (queue[0].isAnimated()) {
3457                     this.unRegister(queue[0], 0);
3458                 }
3459             }
3460
3461             queue = [];
3462             thread = null;
3463             tweenCount = 0;
3464         }
3465         else {
3466             this.unRegister(tween);
3467         }
3468     };
3469
3470
3471     this.run = function() {
3472         for (var i = 0, len = queue.length; i < len; ++i) {
3473             var tween = queue[i];
3474             if (!tween || !tween.isAnimated()) {
3475                 continue;
3476             }
3477
3478             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3479             {
3480                 tween.currentFrame += 1;
3481
3482                 if (tween.useSeconds) {
3483                     correctFrame(tween);
3484                 }
3485                 tween._onTween.fire();
3486             }
3487             else {
3488                 Roo.lib.AnimMgr.stop(tween, i);
3489             }
3490         }
3491     };
3492
3493     var getIndex = function(anim) {
3494         for (var i = 0, len = queue.length; i < len; ++i) {
3495             if (queue[i] == anim) {
3496                 return i;
3497             }
3498         }
3499         return -1;
3500     };
3501
3502
3503     var correctFrame = function(tween) {
3504         var frames = tween.totalFrames;
3505         var frame = tween.currentFrame;
3506         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3507         var elapsed = (new Date() - tween.getStartTime());
3508         var tweak = 0;
3509
3510         if (elapsed < tween.duration * 1000) {
3511             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3512         } else {
3513             tweak = frames - (frame + 1);
3514         }
3515         if (tweak > 0 && isFinite(tweak)) {
3516             if (tween.currentFrame + tweak >= frames) {
3517                 tweak = frames - (frame + 1);
3518             }
3519
3520             tween.currentFrame += tweak;
3521         }
3522     };
3523 };
3524
3525     /*
3526  * Portions of this file are based on pieces of Yahoo User Interface Library
3527  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3528  * YUI licensed under the BSD License:
3529  * http://developer.yahoo.net/yui/license.txt
3530  * <script type="text/javascript">
3531  *
3532  */
3533 Roo.lib.Bezier = new function() {
3534
3535         this.getPosition = function(points, t) {
3536             var n = points.length;
3537             var tmp = [];
3538
3539             for (var i = 0; i < n; ++i) {
3540                 tmp[i] = [points[i][0], points[i][1]];
3541             }
3542
3543             for (var j = 1; j < n; ++j) {
3544                 for (i = 0; i < n - j; ++i) {
3545                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3546                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3547                 }
3548             }
3549
3550             return [ tmp[0][0], tmp[0][1] ];
3551
3552         };
3553     };/*
3554  * Portions of this file are based on pieces of Yahoo User Interface Library
3555  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3556  * YUI licensed under the BSD License:
3557  * http://developer.yahoo.net/yui/license.txt
3558  * <script type="text/javascript">
3559  *
3560  */
3561 (function() {
3562
3563     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3564         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3565     };
3566
3567     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3568
3569     var fly = Roo.lib.AnimBase.fly;
3570     var Y = Roo.lib;
3571     var superclass = Y.ColorAnim.superclass;
3572     var proto = Y.ColorAnim.prototype;
3573
3574     proto.toString = function() {
3575         var el = this.getEl();
3576         var id = el.id || el.tagName;
3577         return ("ColorAnim " + id);
3578     };
3579
3580     proto.patterns.color = /color$/i;
3581     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3582     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3583     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3584     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3585
3586
3587     proto.parseColor = function(s) {
3588         if (s.length == 3) {
3589             return s;
3590         }
3591
3592         var c = this.patterns.hex.exec(s);
3593         if (c && c.length == 4) {
3594             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3595         }
3596
3597         c = this.patterns.rgb.exec(s);
3598         if (c && c.length == 4) {
3599             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3600         }
3601
3602         c = this.patterns.hex3.exec(s);
3603         if (c && c.length == 4) {
3604             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3605         }
3606
3607         return null;
3608     };
3609     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3610     proto.getAttribute = function(attr) {
3611         var el = this.getEl();
3612         if (this.patterns.color.test(attr)) {
3613             var val = fly(el).getStyle(attr);
3614
3615             if (this.patterns.transparent.test(val)) {
3616                 var parent = el.parentNode;
3617                 val = fly(parent).getStyle(attr);
3618
3619                 while (parent && this.patterns.transparent.test(val)) {
3620                     parent = parent.parentNode;
3621                     val = fly(parent).getStyle(attr);
3622                     if (parent.tagName.toUpperCase() == 'HTML') {
3623                         val = '#fff';
3624                     }
3625                 }
3626             }
3627         } else {
3628             val = superclass.getAttribute.call(this, attr);
3629         }
3630
3631         return val;
3632     };
3633     proto.getAttribute = function(attr) {
3634         var el = this.getEl();
3635         if (this.patterns.color.test(attr)) {
3636             var val = fly(el).getStyle(attr);
3637
3638             if (this.patterns.transparent.test(val)) {
3639                 var parent = el.parentNode;
3640                 val = fly(parent).getStyle(attr);
3641
3642                 while (parent && this.patterns.transparent.test(val)) {
3643                     parent = parent.parentNode;
3644                     val = fly(parent).getStyle(attr);
3645                     if (parent.tagName.toUpperCase() == 'HTML') {
3646                         val = '#fff';
3647                     }
3648                 }
3649             }
3650         } else {
3651             val = superclass.getAttribute.call(this, attr);
3652         }
3653
3654         return val;
3655     };
3656
3657     proto.doMethod = function(attr, start, end) {
3658         var val;
3659
3660         if (this.patterns.color.test(attr)) {
3661             val = [];
3662             for (var i = 0, len = start.length; i < len; ++i) {
3663                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3664             }
3665
3666             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3667         }
3668         else {
3669             val = superclass.doMethod.call(this, attr, start, end);
3670         }
3671
3672         return val;
3673     };
3674
3675     proto.setRuntimeAttribute = function(attr) {
3676         superclass.setRuntimeAttribute.call(this, attr);
3677
3678         if (this.patterns.color.test(attr)) {
3679             var attributes = this.attributes;
3680             var start = this.parseColor(this.runtimeAttributes[attr].start);
3681             var end = this.parseColor(this.runtimeAttributes[attr].end);
3682
3683             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3684                 end = this.parseColor(attributes[attr].by);
3685
3686                 for (var i = 0, len = start.length; i < len; ++i) {
3687                     end[i] = start[i] + end[i];
3688                 }
3689             }
3690
3691             this.runtimeAttributes[attr].start = start;
3692             this.runtimeAttributes[attr].end = end;
3693         }
3694     };
3695 })();
3696
3697 /*
3698  * Portions of this file are based on pieces of Yahoo User Interface Library
3699  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3700  * YUI licensed under the BSD License:
3701  * http://developer.yahoo.net/yui/license.txt
3702  * <script type="text/javascript">
3703  *
3704  */
3705 Roo.lib.Easing = {
3706
3707
3708     easeNone: function (t, b, c, d) {
3709         return c * t / d + b;
3710     },
3711
3712
3713     easeIn: function (t, b, c, d) {
3714         return c * (t /= d) * t + b;
3715     },
3716
3717
3718     easeOut: function (t, b, c, d) {
3719         return -c * (t /= d) * (t - 2) + b;
3720     },
3721
3722
3723     easeBoth: function (t, b, c, d) {
3724         if ((t /= d / 2) < 1) {
3725             return c / 2 * t * t + b;
3726         }
3727
3728         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3729     },
3730
3731
3732     easeInStrong: function (t, b, c, d) {
3733         return c * (t /= d) * t * t * t + b;
3734     },
3735
3736
3737     easeOutStrong: function (t, b, c, d) {
3738         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3739     },
3740
3741
3742     easeBothStrong: function (t, b, c, d) {
3743         if ((t /= d / 2) < 1) {
3744             return c / 2 * t * t * t * t + b;
3745         }
3746
3747         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3748     },
3749
3750
3751
3752     elasticIn: function (t, b, c, d, a, p) {
3753         if (t == 0) {
3754             return b;
3755         }
3756         if ((t /= d) == 1) {
3757             return b + c;
3758         }
3759         if (!p) {
3760             p = d * .3;
3761         }
3762
3763         if (!a || a < Math.abs(c)) {
3764             a = c;
3765             var s = p / 4;
3766         }
3767         else {
3768             var s = p / (2 * Math.PI) * Math.asin(c / a);
3769         }
3770
3771         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3772     },
3773
3774
3775     elasticOut: function (t, b, c, d, a, p) {
3776         if (t == 0) {
3777             return b;
3778         }
3779         if ((t /= d) == 1) {
3780             return b + c;
3781         }
3782         if (!p) {
3783             p = d * .3;
3784         }
3785
3786         if (!a || a < Math.abs(c)) {
3787             a = c;
3788             var s = p / 4;
3789         }
3790         else {
3791             var s = p / (2 * Math.PI) * Math.asin(c / a);
3792         }
3793
3794         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3795     },
3796
3797
3798     elasticBoth: function (t, b, c, d, a, p) {
3799         if (t == 0) {
3800             return b;
3801         }
3802
3803         if ((t /= d / 2) == 2) {
3804             return b + c;
3805         }
3806
3807         if (!p) {
3808             p = d * (.3 * 1.5);
3809         }
3810
3811         if (!a || a < Math.abs(c)) {
3812             a = c;
3813             var s = p / 4;
3814         }
3815         else {
3816             var s = p / (2 * Math.PI) * Math.asin(c / a);
3817         }
3818
3819         if (t < 1) {
3820             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3821                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3822         }
3823         return a * Math.pow(2, -10 * (t -= 1)) *
3824                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3825     },
3826
3827
3828
3829     backIn: function (t, b, c, d, s) {
3830         if (typeof s == 'undefined') {
3831             s = 1.70158;
3832         }
3833         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3834     },
3835
3836
3837     backOut: function (t, b, c, d, s) {
3838         if (typeof s == 'undefined') {
3839             s = 1.70158;
3840         }
3841         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3842     },
3843
3844
3845     backBoth: function (t, b, c, d, s) {
3846         if (typeof s == 'undefined') {
3847             s = 1.70158;
3848         }
3849
3850         if ((t /= d / 2 ) < 1) {
3851             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3852         }
3853         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3854     },
3855
3856
3857     bounceIn: function (t, b, c, d) {
3858         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3859     },
3860
3861
3862     bounceOut: function (t, b, c, d) {
3863         if ((t /= d) < (1 / 2.75)) {
3864             return c * (7.5625 * t * t) + b;
3865         } else if (t < (2 / 2.75)) {
3866             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3867         } else if (t < (2.5 / 2.75)) {
3868             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3869         }
3870         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3871     },
3872
3873
3874     bounceBoth: function (t, b, c, d) {
3875         if (t < d / 2) {
3876             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3877         }
3878         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3879     }
3880 };/*
3881  * Portions of this file are based on pieces of Yahoo User Interface Library
3882  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3883  * YUI licensed under the BSD License:
3884  * http://developer.yahoo.net/yui/license.txt
3885  * <script type="text/javascript">
3886  *
3887  */
3888     (function() {
3889         Roo.lib.Motion = function(el, attributes, duration, method) {
3890             if (el) {
3891                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3892             }
3893         };
3894
3895         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3896
3897
3898         var Y = Roo.lib;
3899         var superclass = Y.Motion.superclass;
3900         var proto = Y.Motion.prototype;
3901
3902         proto.toString = function() {
3903             var el = this.getEl();
3904             var id = el.id || el.tagName;
3905             return ("Motion " + id);
3906         };
3907
3908         proto.patterns.points = /^points$/i;
3909
3910         proto.setAttribute = function(attr, val, unit) {
3911             if (this.patterns.points.test(attr)) {
3912                 unit = unit || 'px';
3913                 superclass.setAttribute.call(this, 'left', val[0], unit);
3914                 superclass.setAttribute.call(this, 'top', val[1], unit);
3915             } else {
3916                 superclass.setAttribute.call(this, attr, val, unit);
3917             }
3918         };
3919
3920         proto.getAttribute = function(attr) {
3921             if (this.patterns.points.test(attr)) {
3922                 var val = [
3923                         superclass.getAttribute.call(this, 'left'),
3924                         superclass.getAttribute.call(this, 'top')
3925                         ];
3926             } else {
3927                 val = superclass.getAttribute.call(this, attr);
3928             }
3929
3930             return val;
3931         };
3932
3933         proto.doMethod = function(attr, start, end) {
3934             var val = null;
3935
3936             if (this.patterns.points.test(attr)) {
3937                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3938                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3939             } else {
3940                 val = superclass.doMethod.call(this, attr, start, end);
3941             }
3942             return val;
3943         };
3944
3945         proto.setRuntimeAttribute = function(attr) {
3946             if (this.patterns.points.test(attr)) {
3947                 var el = this.getEl();
3948                 var attributes = this.attributes;
3949                 var start;
3950                 var control = attributes['points']['control'] || [];
3951                 var end;
3952                 var i, len;
3953
3954                 if (control.length > 0 && !(control[0] instanceof Array)) {
3955                     control = [control];
3956                 } else {
3957                     var tmp = [];
3958                     for (i = 0,len = control.length; i < len; ++i) {
3959                         tmp[i] = control[i];
3960                     }
3961                     control = tmp;
3962                 }
3963
3964                 Roo.fly(el).position();
3965
3966                 if (isset(attributes['points']['from'])) {
3967                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3968                 }
3969                 else {
3970                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3971                 }
3972
3973                 start = this.getAttribute('points');
3974
3975
3976                 if (isset(attributes['points']['to'])) {
3977                     end = translateValues.call(this, attributes['points']['to'], start);
3978
3979                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3980                     for (i = 0,len = control.length; i < len; ++i) {
3981                         control[i] = translateValues.call(this, control[i], start);
3982                     }
3983
3984
3985                 } else if (isset(attributes['points']['by'])) {
3986                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3987
3988                     for (i = 0,len = control.length; i < len; ++i) {
3989                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3990                     }
3991                 }
3992
3993                 this.runtimeAttributes[attr] = [start];
3994
3995                 if (control.length > 0) {
3996                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3997                 }
3998
3999                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4000             }
4001             else {
4002                 superclass.setRuntimeAttribute.call(this, attr);
4003             }
4004         };
4005
4006         var translateValues = function(val, start) {
4007             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4008             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4009
4010             return val;
4011         };
4012
4013         var isset = function(prop) {
4014             return (typeof prop !== 'undefined');
4015         };
4016     })();
4017 /*
4018  * Portions of this file are based on pieces of Yahoo User Interface Library
4019  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4020  * YUI licensed under the BSD License:
4021  * http://developer.yahoo.net/yui/license.txt
4022  * <script type="text/javascript">
4023  *
4024  */
4025     (function() {
4026         Roo.lib.Scroll = function(el, attributes, duration, method) {
4027             if (el) {
4028                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4029             }
4030         };
4031
4032         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4033
4034
4035         var Y = Roo.lib;
4036         var superclass = Y.Scroll.superclass;
4037         var proto = Y.Scroll.prototype;
4038
4039         proto.toString = function() {
4040             var el = this.getEl();
4041             var id = el.id || el.tagName;
4042             return ("Scroll " + id);
4043         };
4044
4045         proto.doMethod = function(attr, start, end) {
4046             var val = null;
4047
4048             if (attr == 'scroll') {
4049                 val = [
4050                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4051                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4052                         ];
4053
4054             } else {
4055                 val = superclass.doMethod.call(this, attr, start, end);
4056             }
4057             return val;
4058         };
4059
4060         proto.getAttribute = function(attr) {
4061             var val = null;
4062             var el = this.getEl();
4063
4064             if (attr == 'scroll') {
4065                 val = [ el.scrollLeft, el.scrollTop ];
4066             } else {
4067                 val = superclass.getAttribute.call(this, attr);
4068             }
4069
4070             return val;
4071         };
4072
4073         proto.setAttribute = function(attr, val, unit) {
4074             var el = this.getEl();
4075
4076             if (attr == 'scroll') {
4077                 el.scrollLeft = val[0];
4078                 el.scrollTop = val[1];
4079             } else {
4080                 superclass.setAttribute.call(this, attr, val, unit);
4081             }
4082         };
4083     })();
4084 /*
4085  * Based on:
4086  * Ext JS Library 1.1.1
4087  * Copyright(c) 2006-2007, Ext JS, LLC.
4088  *
4089  * Originally Released Under LGPL - original licence link has changed is not relivant.
4090  *
4091  * Fork - LGPL
4092  * <script type="text/javascript">
4093  */
4094
4095
4096 // nasty IE9 hack - what a pile of crap that is..
4097
4098  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4099     Range.prototype.createContextualFragment = function (html) {
4100         var doc = window.document;
4101         var container = doc.createElement("div");
4102         container.innerHTML = html;
4103         var frag = doc.createDocumentFragment(), n;
4104         while ((n = container.firstChild)) {
4105             frag.appendChild(n);
4106         }
4107         return frag;
4108     };
4109 }
4110
4111 /**
4112  * @class Roo.DomHelper
4113  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4114  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4115  * @singleton
4116  */
4117 Roo.DomHelper = function(){
4118     var tempTableEl = null;
4119     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4120     var tableRe = /^table|tbody|tr|td$/i;
4121     var xmlns = {};
4122     // build as innerHTML where available
4123     /** @ignore */
4124     var createHtml = function(o){
4125         if(typeof o == 'string'){
4126             return o;
4127         }
4128         var b = "";
4129         if(!o.tag){
4130             o.tag = "div";
4131         }
4132         b += "<" + o.tag;
4133         for(var attr in o){
4134             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4135             if(attr == "style"){
4136                 var s = o["style"];
4137                 if(typeof s == "function"){
4138                     s = s.call();
4139                 }
4140                 if(typeof s == "string"){
4141                     b += ' style="' + s + '"';
4142                 }else if(typeof s == "object"){
4143                     b += ' style="';
4144                     for(var key in s){
4145                         if(typeof s[key] != "function"){
4146                             b += key + ":" + s[key] + ";";
4147                         }
4148                     }
4149                     b += '"';
4150                 }
4151             }else{
4152                 if(attr == "cls"){
4153                     b += ' class="' + o["cls"] + '"';
4154                 }else if(attr == "htmlFor"){
4155                     b += ' for="' + o["htmlFor"] + '"';
4156                 }else{
4157                     b += " " + attr + '="' + o[attr] + '"';
4158                 }
4159             }
4160         }
4161         if(emptyTags.test(o.tag)){
4162             b += "/>";
4163         }else{
4164             b += ">";
4165             var cn = o.children || o.cn;
4166             if(cn){
4167                 //http://bugs.kde.org/show_bug.cgi?id=71506
4168                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4169                     for(var i = 0, len = cn.length; i < len; i++) {
4170                         b += createHtml(cn[i], b);
4171                     }
4172                 }else{
4173                     b += createHtml(cn, b);
4174                 }
4175             }
4176             if(o.html){
4177                 b += o.html;
4178             }
4179             b += "</" + o.tag + ">";
4180         }
4181         return b;
4182     };
4183
4184     // build as dom
4185     /** @ignore */
4186     var createDom = function(o, parentNode){
4187          
4188         // defininition craeted..
4189         var ns = false;
4190         if (o.ns && o.ns != 'html') {
4191                
4192             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4193                 xmlns[o.ns] = o.xmlns;
4194                 ns = o.xmlns;
4195             }
4196             if (typeof(xmlns[o.ns]) == 'undefined') {
4197                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4198             }
4199             ns = xmlns[o.ns];
4200         }
4201         
4202         
4203         if (typeof(o) == 'string') {
4204             return parentNode.appendChild(document.createTextNode(o));
4205         }
4206         o.tag = o.tag || div;
4207         if (o.ns && Roo.isIE) {
4208             ns = false;
4209             o.tag = o.ns + ':' + o.tag;
4210             
4211         }
4212         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4213         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4214         for(var attr in o){
4215             
4216             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4217                     attr == "style" || typeof o[attr] == "function") continue;
4218                     
4219             if(attr=="cls" && Roo.isIE){
4220                 el.className = o["cls"];
4221             }else{
4222                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4223                 else el[attr] = o[attr];
4224             }
4225         }
4226         Roo.DomHelper.applyStyles(el, o.style);
4227         var cn = o.children || o.cn;
4228         if(cn){
4229             //http://bugs.kde.org/show_bug.cgi?id=71506
4230              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4231                 for(var i = 0, len = cn.length; i < len; i++) {
4232                     createDom(cn[i], el);
4233                 }
4234             }else{
4235                 createDom(cn, el);
4236             }
4237         }
4238         if(o.html){
4239             el.innerHTML = o.html;
4240         }
4241         if(parentNode){
4242            parentNode.appendChild(el);
4243         }
4244         return el;
4245     };
4246
4247     var ieTable = function(depth, s, h, e){
4248         tempTableEl.innerHTML = [s, h, e].join('');
4249         var i = -1, el = tempTableEl;
4250         while(++i < depth){
4251             el = el.firstChild;
4252         }
4253         return el;
4254     };
4255
4256     // kill repeat to save bytes
4257     var ts = '<table>',
4258         te = '</table>',
4259         tbs = ts+'<tbody>',
4260         tbe = '</tbody>'+te,
4261         trs = tbs + '<tr>',
4262         tre = '</tr>'+tbe;
4263
4264     /**
4265      * @ignore
4266      * Nasty code for IE's broken table implementation
4267      */
4268     var insertIntoTable = function(tag, where, el, html){
4269         if(!tempTableEl){
4270             tempTableEl = document.createElement('div');
4271         }
4272         var node;
4273         var before = null;
4274         if(tag == 'td'){
4275             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4276                 return;
4277             }
4278             if(where == 'beforebegin'){
4279                 before = el;
4280                 el = el.parentNode;
4281             } else{
4282                 before = el.nextSibling;
4283                 el = el.parentNode;
4284             }
4285             node = ieTable(4, trs, html, tre);
4286         }
4287         else if(tag == 'tr'){
4288             if(where == 'beforebegin'){
4289                 before = el;
4290                 el = el.parentNode;
4291                 node = ieTable(3, tbs, html, tbe);
4292             } else if(where == 'afterend'){
4293                 before = el.nextSibling;
4294                 el = el.parentNode;
4295                 node = ieTable(3, tbs, html, tbe);
4296             } else{ // INTO a TR
4297                 if(where == 'afterbegin'){
4298                     before = el.firstChild;
4299                 }
4300                 node = ieTable(4, trs, html, tre);
4301             }
4302         } else if(tag == 'tbody'){
4303             if(where == 'beforebegin'){
4304                 before = el;
4305                 el = el.parentNode;
4306                 node = ieTable(2, ts, html, te);
4307             } else if(where == 'afterend'){
4308                 before = el.nextSibling;
4309                 el = el.parentNode;
4310                 node = ieTable(2, ts, html, te);
4311             } else{
4312                 if(where == 'afterbegin'){
4313                     before = el.firstChild;
4314                 }
4315                 node = ieTable(3, tbs, html, tbe);
4316             }
4317         } else{ // TABLE
4318             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4319                 return;
4320             }
4321             if(where == 'afterbegin'){
4322                 before = el.firstChild;
4323             }
4324             node = ieTable(2, ts, html, te);
4325         }
4326         el.insertBefore(node, before);
4327         return node;
4328     };
4329
4330     return {
4331     /** True to force the use of DOM instead of html fragments @type Boolean */
4332     useDom : false,
4333
4334     /**
4335      * Returns the markup for the passed Element(s) config
4336      * @param {Object} o The Dom object spec (and children)
4337      * @return {String}
4338      */
4339     markup : function(o){
4340         return createHtml(o);
4341     },
4342
4343     /**
4344      * Applies a style specification to an element
4345      * @param {String/HTMLElement} el The element to apply styles to
4346      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4347      * a function which returns such a specification.
4348      */
4349     applyStyles : function(el, styles){
4350         if(styles){
4351            el = Roo.fly(el);
4352            if(typeof styles == "string"){
4353                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4354                var matches;
4355                while ((matches = re.exec(styles)) != null){
4356                    el.setStyle(matches[1], matches[2]);
4357                }
4358            }else if (typeof styles == "object"){
4359                for (var style in styles){
4360                   el.setStyle(style, styles[style]);
4361                }
4362            }else if (typeof styles == "function"){
4363                 Roo.DomHelper.applyStyles(el, styles.call());
4364            }
4365         }
4366     },
4367
4368     /**
4369      * Inserts an HTML fragment into the Dom
4370      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4371      * @param {HTMLElement} el The context element
4372      * @param {String} html The HTML fragmenet
4373      * @return {HTMLElement} The new node
4374      */
4375     insertHtml : function(where, el, html){
4376         where = where.toLowerCase();
4377         if(el.insertAdjacentHTML){
4378             if(tableRe.test(el.tagName)){
4379                 var rs;
4380                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4381                     return rs;
4382                 }
4383             }
4384             switch(where){
4385                 case "beforebegin":
4386                     el.insertAdjacentHTML('BeforeBegin', html);
4387                     return el.previousSibling;
4388                 case "afterbegin":
4389                     el.insertAdjacentHTML('AfterBegin', html);
4390                     return el.firstChild;
4391                 case "beforeend":
4392                     el.insertAdjacentHTML('BeforeEnd', html);
4393                     return el.lastChild;
4394                 case "afterend":
4395                     el.insertAdjacentHTML('AfterEnd', html);
4396                     return el.nextSibling;
4397             }
4398             throw 'Illegal insertion point -> "' + where + '"';
4399         }
4400         var range = el.ownerDocument.createRange();
4401         var frag;
4402         switch(where){
4403              case "beforebegin":
4404                 range.setStartBefore(el);
4405                 frag = range.createContextualFragment(html);
4406                 el.parentNode.insertBefore(frag, el);
4407                 return el.previousSibling;
4408              case "afterbegin":
4409                 if(el.firstChild){
4410                     range.setStartBefore(el.firstChild);
4411                     frag = range.createContextualFragment(html);
4412                     el.insertBefore(frag, el.firstChild);
4413                     return el.firstChild;
4414                 }else{
4415                     el.innerHTML = html;
4416                     return el.firstChild;
4417                 }
4418             case "beforeend":
4419                 if(el.lastChild){
4420                     range.setStartAfter(el.lastChild);
4421                     frag = range.createContextualFragment(html);
4422                     el.appendChild(frag);
4423                     return el.lastChild;
4424                 }else{
4425                     el.innerHTML = html;
4426                     return el.lastChild;
4427                 }
4428             case "afterend":
4429                 range.setStartAfter(el);
4430                 frag = range.createContextualFragment(html);
4431                 el.parentNode.insertBefore(frag, el.nextSibling);
4432                 return el.nextSibling;
4433             }
4434             throw 'Illegal insertion point -> "' + where + '"';
4435     },
4436
4437     /**
4438      * Creates new Dom element(s) and inserts them before el
4439      * @param {String/HTMLElement/Element} el The context element
4440      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4441      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4442      * @return {HTMLElement/Roo.Element} The new node
4443      */
4444     insertBefore : function(el, o, returnElement){
4445         return this.doInsert(el, o, returnElement, "beforeBegin");
4446     },
4447
4448     /**
4449      * Creates new Dom element(s) and inserts them after el
4450      * @param {String/HTMLElement/Element} el The context element
4451      * @param {Object} o The Dom object spec (and children)
4452      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4453      * @return {HTMLElement/Roo.Element} The new node
4454      */
4455     insertAfter : function(el, o, returnElement){
4456         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4457     },
4458
4459     /**
4460      * Creates new Dom element(s) and inserts them as the first child of el
4461      * @param {String/HTMLElement/Element} el The context element
4462      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464      * @return {HTMLElement/Roo.Element} The new node
4465      */
4466     insertFirst : function(el, o, returnElement){
4467         return this.doInsert(el, o, returnElement, "afterBegin");
4468     },
4469
4470     // private
4471     doInsert : function(el, o, returnElement, pos, sibling){
4472         el = Roo.getDom(el);
4473         var newNode;
4474         if(this.useDom || o.ns){
4475             newNode = createDom(o, null);
4476             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4477         }else{
4478             var html = createHtml(o);
4479             newNode = this.insertHtml(pos, el, html);
4480         }
4481         return returnElement ? Roo.get(newNode, true) : newNode;
4482     },
4483
4484     /**
4485      * Creates new Dom element(s) and appends them to el
4486      * @param {String/HTMLElement/Element} el The context element
4487      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4488      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4489      * @return {HTMLElement/Roo.Element} The new node
4490      */
4491     append : function(el, o, returnElement){
4492         el = Roo.getDom(el);
4493         var newNode;
4494         if(this.useDom || o.ns){
4495             newNode = createDom(o, null);
4496             el.appendChild(newNode);
4497         }else{
4498             var html = createHtml(o);
4499             newNode = this.insertHtml("beforeEnd", el, html);
4500         }
4501         return returnElement ? Roo.get(newNode, true) : newNode;
4502     },
4503
4504     /**
4505      * Creates new Dom element(s) and overwrites the contents of el with them
4506      * @param {String/HTMLElement/Element} el The context element
4507      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4508      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4509      * @return {HTMLElement/Roo.Element} The new node
4510      */
4511     overwrite : function(el, o, returnElement){
4512         el = Roo.getDom(el);
4513         if (o.ns) {
4514           
4515             while (el.childNodes.length) {
4516                 el.removeChild(el.firstChild);
4517             }
4518             createDom(o, el);
4519         } else {
4520             el.innerHTML = createHtml(o);   
4521         }
4522         
4523         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4524     },
4525
4526     /**
4527      * Creates a new Roo.DomHelper.Template from the Dom object spec
4528      * @param {Object} o The Dom object spec (and children)
4529      * @return {Roo.DomHelper.Template} The new template
4530      */
4531     createTemplate : function(o){
4532         var html = createHtml(o);
4533         return new Roo.Template(html);
4534     }
4535     };
4536 }();
4537 /*
4538  * Based on:
4539  * Ext JS Library 1.1.1
4540  * Copyright(c) 2006-2007, Ext JS, LLC.
4541  *
4542  * Originally Released Under LGPL - original licence link has changed is not relivant.
4543  *
4544  * Fork - LGPL
4545  * <script type="text/javascript">
4546  */
4547  
4548 /**
4549 * @class Roo.Template
4550 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4551 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4552 * Usage:
4553 <pre><code>
4554 var t = new Roo.Template({
4555     html :  '&lt;div name="{id}"&gt;' + 
4556         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4557         '&lt;/div&gt;',
4558     myformat: function (value, allValues) {
4559         return 'XX' + value;
4560     }
4561 });
4562 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4563 </code></pre>
4564 * For more information see this blog post with examples:
4565 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4566      - Create Elements using DOM, HTML fragments and Templates</a>. 
4567 * @constructor
4568 * @param {Object} cfg - Configuration object.
4569 */
4570 Roo.Template = function(cfg){
4571     // BC!
4572     if(cfg instanceof Array){
4573         cfg = cfg.join("");
4574     }else if(arguments.length > 1){
4575         cfg = Array.prototype.join.call(arguments, "");
4576     }
4577     
4578     
4579     if (typeof(cfg) == 'object') {
4580         Roo.apply(this,cfg)
4581     } else {
4582         // bc
4583         this.html = cfg;
4584     }
4585     if (this.url) {
4586         this.load();
4587     }
4588     
4589 };
4590 Roo.Template.prototype = {
4591     
4592     /**
4593      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4594      *                    it should be fixed so that template is observable...
4595      */
4596     url : false,
4597     /**
4598      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4599      */
4600     html : '',
4601     /**
4602      * Returns an HTML fragment of this template with the specified values applied.
4603      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4604      * @return {String} The HTML fragment
4605      */
4606     applyTemplate : function(values){
4607         try {
4608            
4609             if(this.compiled){
4610                 return this.compiled(values);
4611             }
4612             var useF = this.disableFormats !== true;
4613             var fm = Roo.util.Format, tpl = this;
4614             var fn = function(m, name, format, args){
4615                 if(format && useF){
4616                     if(format.substr(0, 5) == "this."){
4617                         return tpl.call(format.substr(5), values[name], values);
4618                     }else{
4619                         if(args){
4620                             // quoted values are required for strings in compiled templates, 
4621                             // but for non compiled we need to strip them
4622                             // quoted reversed for jsmin
4623                             var re = /^\s*['"](.*)["']\s*$/;
4624                             args = args.split(',');
4625                             for(var i = 0, len = args.length; i < len; i++){
4626                                 args[i] = args[i].replace(re, "$1");
4627                             }
4628                             args = [values[name]].concat(args);
4629                         }else{
4630                             args = [values[name]];
4631                         }
4632                         return fm[format].apply(fm, args);
4633                     }
4634                 }else{
4635                     return values[name] !== undefined ? values[name] : "";
4636                 }
4637             };
4638             return this.html.replace(this.re, fn);
4639         } catch (e) {
4640             Roo.log(e);
4641             throw e;
4642         }
4643          
4644     },
4645     
4646     loading : false,
4647       
4648     load : function ()
4649     {
4650          
4651         if (this.loading) {
4652             return;
4653         }
4654         var _t = this;
4655         
4656         this.loading = true;
4657         this.compiled = false;
4658         
4659         var cx = new Roo.data.Connection();
4660         cx.request({
4661             url : this.url,
4662             method : 'GET',
4663             success : function (response) {
4664                 _t.loading = false;
4665                 _t.html = response.responseText;
4666                 _t.url = false;
4667                 _t.compile();
4668              },
4669             failure : function(response) {
4670                 Roo.log("Template failed to load from " + _t.url);
4671                 _t.loading = false;
4672             }
4673         });
4674     },
4675
4676     /**
4677      * Sets the HTML used as the template and optionally compiles it.
4678      * @param {String} html
4679      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4680      * @return {Roo.Template} this
4681      */
4682     set : function(html, compile){
4683         this.html = html;
4684         this.compiled = null;
4685         if(compile){
4686             this.compile();
4687         }
4688         return this;
4689     },
4690     
4691     /**
4692      * True to disable format functions (defaults to false)
4693      * @type Boolean
4694      */
4695     disableFormats : false,
4696     
4697     /**
4698     * The regular expression used to match template variables 
4699     * @type RegExp
4700     * @property 
4701     */
4702     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4703     
4704     /**
4705      * Compiles the template into an internal function, eliminating the RegEx overhead.
4706      * @return {Roo.Template} this
4707      */
4708     compile : function(){
4709         var fm = Roo.util.Format;
4710         var useF = this.disableFormats !== true;
4711         var sep = Roo.isGecko ? "+" : ",";
4712         var fn = function(m, name, format, args){
4713             if(format && useF){
4714                 args = args ? ',' + args : "";
4715                 if(format.substr(0, 5) != "this."){
4716                     format = "fm." + format + '(';
4717                 }else{
4718                     format = 'this.call("'+ format.substr(5) + '", ';
4719                     args = ", values";
4720                 }
4721             }else{
4722                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4723             }
4724             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4725         };
4726         var body;
4727         // branched to use + in gecko and [].join() in others
4728         if(Roo.isGecko){
4729             body = "this.compiled = function(values){ return '" +
4730                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4731                     "';};";
4732         }else{
4733             body = ["this.compiled = function(values){ return ['"];
4734             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4735             body.push("'].join('');};");
4736             body = body.join('');
4737         }
4738         /**
4739          * eval:var:values
4740          * eval:var:fm
4741          */
4742         eval(body);
4743         return this;
4744     },
4745     
4746     // private function used to call members
4747     call : function(fnName, value, allValues){
4748         return this[fnName](value, allValues);
4749     },
4750     
4751     /**
4752      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4753      * @param {String/HTMLElement/Roo.Element} el The context element
4754      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4755      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4756      * @return {HTMLElement/Roo.Element} The new node or Element
4757      */
4758     insertFirst: function(el, values, returnElement){
4759         return this.doInsert('afterBegin', el, values, returnElement);
4760     },
4761
4762     /**
4763      * Applies the supplied values to the template and inserts the new node(s) before el.
4764      * @param {String/HTMLElement/Roo.Element} el The context element
4765      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4766      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4767      * @return {HTMLElement/Roo.Element} The new node or Element
4768      */
4769     insertBefore: function(el, values, returnElement){
4770         return this.doInsert('beforeBegin', el, values, returnElement);
4771     },
4772
4773     /**
4774      * Applies the supplied values to the template and inserts the new node(s) after el.
4775      * @param {String/HTMLElement/Roo.Element} el The context element
4776      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4777      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778      * @return {HTMLElement/Roo.Element} The new node or Element
4779      */
4780     insertAfter : function(el, values, returnElement){
4781         return this.doInsert('afterEnd', el, values, returnElement);
4782     },
4783     
4784     /**
4785      * Applies the supplied values to the template and appends the new node(s) to el.
4786      * @param {String/HTMLElement/Roo.Element} el The context element
4787      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4788      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789      * @return {HTMLElement/Roo.Element} The new node or Element
4790      */
4791     append : function(el, values, returnElement){
4792         return this.doInsert('beforeEnd', el, values, returnElement);
4793     },
4794
4795     doInsert : function(where, el, values, returnEl){
4796         el = Roo.getDom(el);
4797         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4798         return returnEl ? Roo.get(newNode, true) : newNode;
4799     },
4800
4801     /**
4802      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4803      * @param {String/HTMLElement/Roo.Element} el The context element
4804      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4805      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4806      * @return {HTMLElement/Roo.Element} The new node or Element
4807      */
4808     overwrite : function(el, values, returnElement){
4809         el = Roo.getDom(el);
4810         el.innerHTML = this.applyTemplate(values);
4811         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4812     }
4813 };
4814 /**
4815  * Alias for {@link #applyTemplate}
4816  * @method
4817  */
4818 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4819
4820 // backwards compat
4821 Roo.DomHelper.Template = Roo.Template;
4822
4823 /**
4824  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4825  * @param {String/HTMLElement} el A DOM element or its id
4826  * @returns {Roo.Template} The created template
4827  * @static
4828  */
4829 Roo.Template.from = function(el){
4830     el = Roo.getDom(el);
4831     return new Roo.Template(el.value || el.innerHTML);
4832 };/*
4833  * Based on:
4834  * Ext JS Library 1.1.1
4835  * Copyright(c) 2006-2007, Ext JS, LLC.
4836  *
4837  * Originally Released Under LGPL - original licence link has changed is not relivant.
4838  *
4839  * Fork - LGPL
4840  * <script type="text/javascript">
4841  */
4842  
4843
4844 /*
4845  * This is code is also distributed under MIT license for use
4846  * with jQuery and prototype JavaScript libraries.
4847  */
4848 /**
4849  * @class Roo.DomQuery
4850 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4851 <p>
4852 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4853
4854 <p>
4855 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4856 </p>
4857 <h4>Element Selectors:</h4>
4858 <ul class="list">
4859     <li> <b>*</b> any element</li>
4860     <li> <b>E</b> an element with the tag E</li>
4861     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4862     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4863     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4864     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4865 </ul>
4866 <h4>Attribute Selectors:</h4>
4867 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4868 <ul class="list">
4869     <li> <b>E[foo]</b> has an attribute "foo"</li>
4870     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4871     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4872     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4873     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4874     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4875     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4876 </ul>
4877 <h4>Pseudo Classes:</h4>
4878 <ul class="list">
4879     <li> <b>E:first-child</b> E is the first child of its parent</li>
4880     <li> <b>E:last-child</b> E is the last child of its parent</li>
4881     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4882     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4883     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4884     <li> <b>E:only-child</b> E is the only child of its parent</li>
4885     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4886     <li> <b>E:first</b> the first E in the resultset</li>
4887     <li> <b>E:last</b> the last E in the resultset</li>
4888     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4889     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4890     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4891     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4892     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4893     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4894     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4895     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4896     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4897 </ul>
4898 <h4>CSS Value Selectors:</h4>
4899 <ul class="list">
4900     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4901     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4902     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4903     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4904     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4905     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4906 </ul>
4907  * @singleton
4908  */
4909 Roo.DomQuery = function(){
4910     var cache = {}, simpleCache = {}, valueCache = {};
4911     var nonSpace = /\S/;
4912     var trimRe = /^\s+|\s+$/g;
4913     var tplRe = /\{(\d+)\}/g;
4914     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4915     var tagTokenRe = /^(#)?([\w-\*]+)/;
4916     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4917
4918     function child(p, index){
4919         var i = 0;
4920         var n = p.firstChild;
4921         while(n){
4922             if(n.nodeType == 1){
4923                if(++i == index){
4924                    return n;
4925                }
4926             }
4927             n = n.nextSibling;
4928         }
4929         return null;
4930     };
4931
4932     function next(n){
4933         while((n = n.nextSibling) && n.nodeType != 1);
4934         return n;
4935     };
4936
4937     function prev(n){
4938         while((n = n.previousSibling) && n.nodeType != 1);
4939         return n;
4940     };
4941
4942     function children(d){
4943         var n = d.firstChild, ni = -1;
4944             while(n){
4945                 var nx = n.nextSibling;
4946                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4947                     d.removeChild(n);
4948                 }else{
4949                     n.nodeIndex = ++ni;
4950                 }
4951                 n = nx;
4952             }
4953             return this;
4954         };
4955
4956     function byClassName(c, a, v){
4957         if(!v){
4958             return c;
4959         }
4960         var r = [], ri = -1, cn;
4961         for(var i = 0, ci; ci = c[i]; i++){
4962             if((' '+ci.className+' ').indexOf(v) != -1){
4963                 r[++ri] = ci;
4964             }
4965         }
4966         return r;
4967     };
4968
4969     function attrValue(n, attr){
4970         if(!n.tagName && typeof n.length != "undefined"){
4971             n = n[0];
4972         }
4973         if(!n){
4974             return null;
4975         }
4976         if(attr == "for"){
4977             return n.htmlFor;
4978         }
4979         if(attr == "class" || attr == "className"){
4980             return n.className;
4981         }
4982         return n.getAttribute(attr) || n[attr];
4983
4984     };
4985
4986     function getNodes(ns, mode, tagName){
4987         var result = [], ri = -1, cs;
4988         if(!ns){
4989             return result;
4990         }
4991         tagName = tagName || "*";
4992         if(typeof ns.getElementsByTagName != "undefined"){
4993             ns = [ns];
4994         }
4995         if(!mode){
4996             for(var i = 0, ni; ni = ns[i]; i++){
4997                 cs = ni.getElementsByTagName(tagName);
4998                 for(var j = 0, ci; ci = cs[j]; j++){
4999                     result[++ri] = ci;
5000                 }
5001             }
5002         }else if(mode == "/" || mode == ">"){
5003             var utag = tagName.toUpperCase();
5004             for(var i = 0, ni, cn; ni = ns[i]; i++){
5005                 cn = ni.children || ni.childNodes;
5006                 for(var j = 0, cj; cj = cn[j]; j++){
5007                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5008                         result[++ri] = cj;
5009                     }
5010                 }
5011             }
5012         }else if(mode == "+"){
5013             var utag = tagName.toUpperCase();
5014             for(var i = 0, n; n = ns[i]; i++){
5015                 while((n = n.nextSibling) && n.nodeType != 1);
5016                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5017                     result[++ri] = n;
5018                 }
5019             }
5020         }else if(mode == "~"){
5021             for(var i = 0, n; n = ns[i]; i++){
5022                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5023                 if(n){
5024                     result[++ri] = n;
5025                 }
5026             }
5027         }
5028         return result;
5029     };
5030
5031     function concat(a, b){
5032         if(b.slice){
5033             return a.concat(b);
5034         }
5035         for(var i = 0, l = b.length; i < l; i++){
5036             a[a.length] = b[i];
5037         }
5038         return a;
5039     }
5040
5041     function byTag(cs, tagName){
5042         if(cs.tagName || cs == document){
5043             cs = [cs];
5044         }
5045         if(!tagName){
5046             return cs;
5047         }
5048         var r = [], ri = -1;
5049         tagName = tagName.toLowerCase();
5050         for(var i = 0, ci; ci = cs[i]; i++){
5051             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5052                 r[++ri] = ci;
5053             }
5054         }
5055         return r;
5056     };
5057
5058     function byId(cs, attr, id){
5059         if(cs.tagName || cs == document){
5060             cs = [cs];
5061         }
5062         if(!id){
5063             return cs;
5064         }
5065         var r = [], ri = -1;
5066         for(var i = 0,ci; ci = cs[i]; i++){
5067             if(ci && ci.id == id){
5068                 r[++ri] = ci;
5069                 return r;
5070             }
5071         }
5072         return r;
5073     };
5074
5075     function byAttribute(cs, attr, value, op, custom){
5076         var r = [], ri = -1, st = custom=="{";
5077         var f = Roo.DomQuery.operators[op];
5078         for(var i = 0, ci; ci = cs[i]; i++){
5079             var a;
5080             if(st){
5081                 a = Roo.DomQuery.getStyle(ci, attr);
5082             }
5083             else if(attr == "class" || attr == "className"){
5084                 a = ci.className;
5085             }else if(attr == "for"){
5086                 a = ci.htmlFor;
5087             }else if(attr == "href"){
5088                 a = ci.getAttribute("href", 2);
5089             }else{
5090                 a = ci.getAttribute(attr);
5091             }
5092             if((f && f(a, value)) || (!f && a)){
5093                 r[++ri] = ci;
5094             }
5095         }
5096         return r;
5097     };
5098
5099     function byPseudo(cs, name, value){
5100         return Roo.DomQuery.pseudos[name](cs, value);
5101     };
5102
5103     // This is for IE MSXML which does not support expandos.
5104     // IE runs the same speed using setAttribute, however FF slows way down
5105     // and Safari completely fails so they need to continue to use expandos.
5106     var isIE = window.ActiveXObject ? true : false;
5107
5108     // this eval is stop the compressor from
5109     // renaming the variable to something shorter
5110     
5111     /** eval:var:batch */
5112     var batch = 30803; 
5113
5114     var key = 30803;
5115
5116     function nodupIEXml(cs){
5117         var d = ++key;
5118         cs[0].setAttribute("_nodup", d);
5119         var r = [cs[0]];
5120         for(var i = 1, len = cs.length; i < len; i++){
5121             var c = cs[i];
5122             if(!c.getAttribute("_nodup") != d){
5123                 c.setAttribute("_nodup", d);
5124                 r[r.length] = c;
5125             }
5126         }
5127         for(var i = 0, len = cs.length; i < len; i++){
5128             cs[i].removeAttribute("_nodup");
5129         }
5130         return r;
5131     }
5132
5133     function nodup(cs){
5134         if(!cs){
5135             return [];
5136         }
5137         var len = cs.length, c, i, r = cs, cj, ri = -1;
5138         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5139             return cs;
5140         }
5141         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5142             return nodupIEXml(cs);
5143         }
5144         var d = ++key;
5145         cs[0]._nodup = d;
5146         for(i = 1; c = cs[i]; i++){
5147             if(c._nodup != d){
5148                 c._nodup = d;
5149             }else{
5150                 r = [];
5151                 for(var j = 0; j < i; j++){
5152                     r[++ri] = cs[j];
5153                 }
5154                 for(j = i+1; cj = cs[j]; j++){
5155                     if(cj._nodup != d){
5156                         cj._nodup = d;
5157                         r[++ri] = cj;
5158                     }
5159                 }
5160                 return r;
5161             }
5162         }
5163         return r;
5164     }
5165
5166     function quickDiffIEXml(c1, c2){
5167         var d = ++key;
5168         for(var i = 0, len = c1.length; i < len; i++){
5169             c1[i].setAttribute("_qdiff", d);
5170         }
5171         var r = [];
5172         for(var i = 0, len = c2.length; i < len; i++){
5173             if(c2[i].getAttribute("_qdiff") != d){
5174                 r[r.length] = c2[i];
5175             }
5176         }
5177         for(var i = 0, len = c1.length; i < len; i++){
5178            c1[i].removeAttribute("_qdiff");
5179         }
5180         return r;
5181     }
5182
5183     function quickDiff(c1, c2){
5184         var len1 = c1.length;
5185         if(!len1){
5186             return c2;
5187         }
5188         if(isIE && c1[0].selectSingleNode){
5189             return quickDiffIEXml(c1, c2);
5190         }
5191         var d = ++key;
5192         for(var i = 0; i < len1; i++){
5193             c1[i]._qdiff = d;
5194         }
5195         var r = [];
5196         for(var i = 0, len = c2.length; i < len; i++){
5197             if(c2[i]._qdiff != d){
5198                 r[r.length] = c2[i];
5199             }
5200         }
5201         return r;
5202     }
5203
5204     function quickId(ns, mode, root, id){
5205         if(ns == root){
5206            var d = root.ownerDocument || root;
5207            return d.getElementById(id);
5208         }
5209         ns = getNodes(ns, mode, "*");
5210         return byId(ns, null, id);
5211     }
5212
5213     return {
5214         getStyle : function(el, name){
5215             return Roo.fly(el).getStyle(name);
5216         },
5217         /**
5218          * Compiles a selector/xpath query into a reusable function. The returned function
5219          * takes one parameter "root" (optional), which is the context node from where the query should start.
5220          * @param {String} selector The selector/xpath query
5221          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5222          * @return {Function}
5223          */
5224         compile : function(path, type){
5225             type = type || "select";
5226             
5227             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5228             var q = path, mode, lq;
5229             var tk = Roo.DomQuery.matchers;
5230             var tklen = tk.length;
5231             var mm;
5232
5233             // accept leading mode switch
5234             var lmode = q.match(modeRe);
5235             if(lmode && lmode[1]){
5236                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5237                 q = q.replace(lmode[1], "");
5238             }
5239             // strip leading slashes
5240             while(path.substr(0, 1)=="/"){
5241                 path = path.substr(1);
5242             }
5243
5244             while(q && lq != q){
5245                 lq = q;
5246                 var tm = q.match(tagTokenRe);
5247                 if(type == "select"){
5248                     if(tm){
5249                         if(tm[1] == "#"){
5250                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5251                         }else{
5252                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5253                         }
5254                         q = q.replace(tm[0], "");
5255                     }else if(q.substr(0, 1) != '@'){
5256                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5257                     }
5258                 }else{
5259                     if(tm){
5260                         if(tm[1] == "#"){
5261                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5262                         }else{
5263                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5264                         }
5265                         q = q.replace(tm[0], "");
5266                     }
5267                 }
5268                 while(!(mm = q.match(modeRe))){
5269                     var matched = false;
5270                     for(var j = 0; j < tklen; j++){
5271                         var t = tk[j];
5272                         var m = q.match(t.re);
5273                         if(m){
5274                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5275                                                     return m[i];
5276                                                 });
5277                             q = q.replace(m[0], "");
5278                             matched = true;
5279                             break;
5280                         }
5281                     }
5282                     // prevent infinite loop on bad selector
5283                     if(!matched){
5284                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5285                     }
5286                 }
5287                 if(mm[1]){
5288                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5289                     q = q.replace(mm[1], "");
5290                 }
5291             }
5292             fn[fn.length] = "return nodup(n);\n}";
5293             
5294              /** 
5295               * list of variables that need from compression as they are used by eval.
5296              *  eval:var:batch 
5297              *  eval:var:nodup
5298              *  eval:var:byTag
5299              *  eval:var:ById
5300              *  eval:var:getNodes
5301              *  eval:var:quickId
5302              *  eval:var:mode
5303              *  eval:var:root
5304              *  eval:var:n
5305              *  eval:var:byClassName
5306              *  eval:var:byPseudo
5307              *  eval:var:byAttribute
5308              *  eval:var:attrValue
5309              * 
5310              **/ 
5311             eval(fn.join(""));
5312             return f;
5313         },
5314
5315         /**
5316          * Selects a group of elements.
5317          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5318          * @param {Node} root (optional) The start of the query (defaults to document).
5319          * @return {Array}
5320          */
5321         select : function(path, root, type){
5322             if(!root || root == document){
5323                 root = document;
5324             }
5325             if(typeof root == "string"){
5326                 root = document.getElementById(root);
5327             }
5328             var paths = path.split(",");
5329             var results = [];
5330             for(var i = 0, len = paths.length; i < len; i++){
5331                 var p = paths[i].replace(trimRe, "");
5332                 if(!cache[p]){
5333                     cache[p] = Roo.DomQuery.compile(p);
5334                     if(!cache[p]){
5335                         throw p + " is not a valid selector";
5336                     }
5337                 }
5338                 var result = cache[p](root);
5339                 if(result && result != document){
5340                     results = results.concat(result);
5341                 }
5342             }
5343             if(paths.length > 1){
5344                 return nodup(results);
5345             }
5346             return results;
5347         },
5348
5349         /**
5350          * Selects a single element.
5351          * @param {String} selector The selector/xpath query
5352          * @param {Node} root (optional) The start of the query (defaults to document).
5353          * @return {Element}
5354          */
5355         selectNode : function(path, root){
5356             return Roo.DomQuery.select(path, root)[0];
5357         },
5358
5359         /**
5360          * Selects the value of a node, optionally replacing null with the defaultValue.
5361          * @param {String} selector The selector/xpath query
5362          * @param {Node} root (optional) The start of the query (defaults to document).
5363          * @param {String} defaultValue
5364          */
5365         selectValue : function(path, root, defaultValue){
5366             path = path.replace(trimRe, "");
5367             if(!valueCache[path]){
5368                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5369             }
5370             var n = valueCache[path](root);
5371             n = n[0] ? n[0] : n;
5372             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5373             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5374         },
5375
5376         /**
5377          * Selects the value of a node, parsing integers and floats.
5378          * @param {String} selector The selector/xpath query
5379          * @param {Node} root (optional) The start of the query (defaults to document).
5380          * @param {Number} defaultValue
5381          * @return {Number}
5382          */
5383         selectNumber : function(path, root, defaultValue){
5384             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5385             return parseFloat(v);
5386         },
5387
5388         /**
5389          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5390          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5391          * @param {String} selector The simple selector to test
5392          * @return {Boolean}
5393          */
5394         is : function(el, ss){
5395             if(typeof el == "string"){
5396                 el = document.getElementById(el);
5397             }
5398             var isArray = (el instanceof Array);
5399             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5400             return isArray ? (result.length == el.length) : (result.length > 0);
5401         },
5402
5403         /**
5404          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5405          * @param {Array} el An array of elements to filter
5406          * @param {String} selector The simple selector to test
5407          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5408          * the selector instead of the ones that match
5409          * @return {Array}
5410          */
5411         filter : function(els, ss, nonMatches){
5412             ss = ss.replace(trimRe, "");
5413             if(!simpleCache[ss]){
5414                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5415             }
5416             var result = simpleCache[ss](els);
5417             return nonMatches ? quickDiff(result, els) : result;
5418         },
5419
5420         /**
5421          * Collection of matching regular expressions and code snippets.
5422          */
5423         matchers : [{
5424                 re: /^\.([\w-]+)/,
5425                 select: 'n = byClassName(n, null, " {1} ");'
5426             }, {
5427                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5428                 select: 'n = byPseudo(n, "{1}", "{2}");'
5429             },{
5430                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5431                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5432             }, {
5433                 re: /^#([\w-]+)/,
5434                 select: 'n = byId(n, null, "{1}");'
5435             },{
5436                 re: /^@([\w-]+)/,
5437                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5438             }
5439         ],
5440
5441         /**
5442          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5443          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
5444          */
5445         operators : {
5446             "=" : function(a, v){
5447                 return a == v;
5448             },
5449             "!=" : function(a, v){
5450                 return a != v;
5451             },
5452             "^=" : function(a, v){
5453                 return a && a.substr(0, v.length) == v;
5454             },
5455             "$=" : function(a, v){
5456                 return a && a.substr(a.length-v.length) == v;
5457             },
5458             "*=" : function(a, v){
5459                 return a && a.indexOf(v) !== -1;
5460             },
5461             "%=" : function(a, v){
5462                 return (a % v) == 0;
5463             },
5464             "|=" : function(a, v){
5465                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5466             },
5467             "~=" : function(a, v){
5468                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5469             }
5470         },
5471
5472         /**
5473          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5474          * and the argument (if any) supplied in the selector.
5475          */
5476         pseudos : {
5477             "first-child" : function(c){
5478                 var r = [], ri = -1, n;
5479                 for(var i = 0, ci; ci = n = c[i]; i++){
5480                     while((n = n.previousSibling) && n.nodeType != 1);
5481                     if(!n){
5482                         r[++ri] = ci;
5483                     }
5484                 }
5485                 return r;
5486             },
5487
5488             "last-child" : function(c){
5489                 var r = [], ri = -1, n;
5490                 for(var i = 0, ci; ci = n = c[i]; i++){
5491                     while((n = n.nextSibling) && n.nodeType != 1);
5492                     if(!n){
5493                         r[++ri] = ci;
5494                     }
5495                 }
5496                 return r;
5497             },
5498
5499             "nth-child" : function(c, a) {
5500                 var r = [], ri = -1;
5501                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5502                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5503                 for(var i = 0, n; n = c[i]; i++){
5504                     var pn = n.parentNode;
5505                     if (batch != pn._batch) {
5506                         var j = 0;
5507                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5508                             if(cn.nodeType == 1){
5509                                cn.nodeIndex = ++j;
5510                             }
5511                         }
5512                         pn._batch = batch;
5513                     }
5514                     if (f == 1) {
5515                         if (l == 0 || n.nodeIndex == l){
5516                             r[++ri] = n;
5517                         }
5518                     } else if ((n.nodeIndex + l) % f == 0){
5519                         r[++ri] = n;
5520                     }
5521                 }
5522
5523                 return r;
5524             },
5525
5526             "only-child" : function(c){
5527                 var r = [], ri = -1;;
5528                 for(var i = 0, ci; ci = c[i]; i++){
5529                     if(!prev(ci) && !next(ci)){
5530                         r[++ri] = ci;
5531                     }
5532                 }
5533                 return r;
5534             },
5535
5536             "empty" : function(c){
5537                 var r = [], ri = -1;
5538                 for(var i = 0, ci; ci = c[i]; i++){
5539                     var cns = ci.childNodes, j = 0, cn, empty = true;
5540                     while(cn = cns[j]){
5541                         ++j;
5542                         if(cn.nodeType == 1 || cn.nodeType == 3){
5543                             empty = false;
5544                             break;
5545                         }
5546                     }
5547                     if(empty){
5548                         r[++ri] = ci;
5549                     }
5550                 }
5551                 return r;
5552             },
5553
5554             "contains" : function(c, v){
5555                 var r = [], ri = -1;
5556                 for(var i = 0, ci; ci = c[i]; i++){
5557                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5558                         r[++ri] = ci;
5559                     }
5560                 }
5561                 return r;
5562             },
5563
5564             "nodeValue" : function(c, v){
5565                 var r = [], ri = -1;
5566                 for(var i = 0, ci; ci = c[i]; i++){
5567                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5568                         r[++ri] = ci;
5569                     }
5570                 }
5571                 return r;
5572             },
5573
5574             "checked" : function(c){
5575                 var r = [], ri = -1;
5576                 for(var i = 0, ci; ci = c[i]; i++){
5577                     if(ci.checked == true){
5578                         r[++ri] = ci;
5579                     }
5580                 }
5581                 return r;
5582             },
5583
5584             "not" : function(c, ss){
5585                 return Roo.DomQuery.filter(c, ss, true);
5586             },
5587
5588             "odd" : function(c){
5589                 return this["nth-child"](c, "odd");
5590             },
5591
5592             "even" : function(c){
5593                 return this["nth-child"](c, "even");
5594             },
5595
5596             "nth" : function(c, a){
5597                 return c[a-1] || [];
5598             },
5599
5600             "first" : function(c){
5601                 return c[0] || [];
5602             },
5603
5604             "last" : function(c){
5605                 return c[c.length-1] || [];
5606             },
5607
5608             "has" : function(c, ss){
5609                 var s = Roo.DomQuery.select;
5610                 var r = [], ri = -1;
5611                 for(var i = 0, ci; ci = c[i]; i++){
5612                     if(s(ss, ci).length > 0){
5613                         r[++ri] = ci;
5614                     }
5615                 }
5616                 return r;
5617             },
5618
5619             "next" : function(c, ss){
5620                 var is = Roo.DomQuery.is;
5621                 var r = [], ri = -1;
5622                 for(var i = 0, ci; ci = c[i]; i++){
5623                     var n = next(ci);
5624                     if(n && is(n, ss)){
5625                         r[++ri] = ci;
5626                     }
5627                 }
5628                 return r;
5629             },
5630
5631             "prev" : function(c, ss){
5632                 var is = Roo.DomQuery.is;
5633                 var r = [], ri = -1;
5634                 for(var i = 0, ci; ci = c[i]; i++){
5635                     var n = prev(ci);
5636                     if(n && is(n, ss)){
5637                         r[++ri] = ci;
5638                     }
5639                 }
5640                 return r;
5641             }
5642         }
5643     };
5644 }();
5645
5646 /**
5647  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5648  * @param {String} path The selector/xpath query
5649  * @param {Node} root (optional) The start of the query (defaults to document).
5650  * @return {Array}
5651  * @member Roo
5652  * @method query
5653  */
5654 Roo.query = Roo.DomQuery.select;
5655 /*
5656  * Based on:
5657  * Ext JS Library 1.1.1
5658  * Copyright(c) 2006-2007, Ext JS, LLC.
5659  *
5660  * Originally Released Under LGPL - original licence link has changed is not relivant.
5661  *
5662  * Fork - LGPL
5663  * <script type="text/javascript">
5664  */
5665
5666 /**
5667  * @class Roo.util.Observable
5668  * Base class that provides a common interface for publishing events. Subclasses are expected to
5669  * to have a property "events" with all the events defined.<br>
5670  * For example:
5671  * <pre><code>
5672  Employee = function(name){
5673     this.name = name;
5674     this.addEvents({
5675         "fired" : true,
5676         "quit" : true
5677     });
5678  }
5679  Roo.extend(Employee, Roo.util.Observable);
5680 </code></pre>
5681  * @param {Object} config properties to use (incuding events / listeners)
5682  */
5683
5684 Roo.util.Observable = function(cfg){
5685     
5686     cfg = cfg|| {};
5687     this.addEvents(cfg.events || {});
5688     if (cfg.events) {
5689         delete cfg.events; // make sure
5690     }
5691      
5692     Roo.apply(this, cfg);
5693     
5694     if(this.listeners){
5695         this.on(this.listeners);
5696         delete this.listeners;
5697     }
5698 };
5699 Roo.util.Observable.prototype = {
5700     /** 
5701  * @cfg {Object} listeners  list of events and functions to call for this object, 
5702  * For example :
5703  * <pre><code>
5704     listeners :  { 
5705        'click' : function(e) {
5706            ..... 
5707         } ,
5708         .... 
5709     } 
5710   </code></pre>
5711  */
5712     
5713     
5714     /**
5715      * Fires the specified event with the passed parameters (minus the event name).
5716      * @param {String} eventName
5717      * @param {Object...} args Variable number of parameters are passed to handlers
5718      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5719      */
5720     fireEvent : function(){
5721         var ce = this.events[arguments[0].toLowerCase()];
5722         if(typeof ce == "object"){
5723             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5724         }else{
5725             return true;
5726         }
5727     },
5728
5729     // private
5730     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5731
5732     /**
5733      * Appends an event handler to this component
5734      * @param {String}   eventName The type of event to listen for
5735      * @param {Function} handler The method the event invokes
5736      * @param {Object}   scope (optional) The scope in which to execute the handler
5737      * function. The handler function's "this" context.
5738      * @param {Object}   options (optional) An object containing handler configuration
5739      * properties. This may contain any of the following properties:<ul>
5740      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5741      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5742      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5743      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5744      * by the specified number of milliseconds. If the event fires again within that time, the original
5745      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5746      * </ul><br>
5747      * <p>
5748      * <b>Combining Options</b><br>
5749      * Using the options argument, it is possible to combine different types of listeners:<br>
5750      * <br>
5751      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5752                 <pre><code>
5753                 el.on('click', this.onClick, this, {
5754                         single: true,
5755                 delay: 100,
5756                 forumId: 4
5757                 });
5758                 </code></pre>
5759      * <p>
5760      * <b>Attaching multiple handlers in 1 call</b><br>
5761      * The method also allows for a single argument to be passed which is a config object containing properties
5762      * which specify multiple handlers.
5763      * <pre><code>
5764                 el.on({
5765                         'click': {
5766                         fn: this.onClick,
5767                         scope: this,
5768                         delay: 100
5769                 }, 
5770                 'mouseover': {
5771                         fn: this.onMouseOver,
5772                         scope: this
5773                 },
5774                 'mouseout': {
5775                         fn: this.onMouseOut,
5776                         scope: this
5777                 }
5778                 });
5779                 </code></pre>
5780      * <p>
5781      * Or a shorthand syntax which passes the same scope object to all handlers:
5782         <pre><code>
5783                 el.on({
5784                         'click': this.onClick,
5785                 'mouseover': this.onMouseOver,
5786                 'mouseout': this.onMouseOut,
5787                 scope: this
5788                 });
5789                 </code></pre>
5790      */
5791     addListener : function(eventName, fn, scope, o){
5792         if(typeof eventName == "object"){
5793             o = eventName;
5794             for(var e in o){
5795                 if(this.filterOptRe.test(e)){
5796                     continue;
5797                 }
5798                 if(typeof o[e] == "function"){
5799                     // shared options
5800                     this.addListener(e, o[e], o.scope,  o);
5801                 }else{
5802                     // individual options
5803                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5804                 }
5805             }
5806             return;
5807         }
5808         o = (!o || typeof o == "boolean") ? {} : o;
5809         eventName = eventName.toLowerCase();
5810         var ce = this.events[eventName] || true;
5811         if(typeof ce == "boolean"){
5812             ce = new Roo.util.Event(this, eventName);
5813             this.events[eventName] = ce;
5814         }
5815         ce.addListener(fn, scope, o);
5816     },
5817
5818     /**
5819      * Removes a listener
5820      * @param {String}   eventName     The type of event to listen for
5821      * @param {Function} handler        The handler to remove
5822      * @param {Object}   scope  (optional) The scope (this object) for the handler
5823      */
5824     removeListener : function(eventName, fn, scope){
5825         var ce = this.events[eventName.toLowerCase()];
5826         if(typeof ce == "object"){
5827             ce.removeListener(fn, scope);
5828         }
5829     },
5830
5831     /**
5832      * Removes all listeners for this object
5833      */
5834     purgeListeners : function(){
5835         for(var evt in this.events){
5836             if(typeof this.events[evt] == "object"){
5837                  this.events[evt].clearListeners();
5838             }
5839         }
5840     },
5841
5842     relayEvents : function(o, events){
5843         var createHandler = function(ename){
5844             return function(){
5845                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5846             };
5847         };
5848         for(var i = 0, len = events.length; i < len; i++){
5849             var ename = events[i];
5850             if(!this.events[ename]){ this.events[ename] = true; };
5851             o.on(ename, createHandler(ename), this);
5852         }
5853     },
5854
5855     /**
5856      * Used to define events on this Observable
5857      * @param {Object} object The object with the events defined
5858      */
5859     addEvents : function(o){
5860         if(!this.events){
5861             this.events = {};
5862         }
5863         Roo.applyIf(this.events, o);
5864     },
5865
5866     /**
5867      * Checks to see if this object has any listeners for a specified event
5868      * @param {String} eventName The name of the event to check for
5869      * @return {Boolean} True if the event is being listened for, else false
5870      */
5871     hasListener : function(eventName){
5872         var e = this.events[eventName];
5873         return typeof e == "object" && e.listeners.length > 0;
5874     }
5875 };
5876 /**
5877  * Appends an event handler to this element (shorthand for addListener)
5878  * @param {String}   eventName     The type of event to listen for
5879  * @param {Function} handler        The method the event invokes
5880  * @param {Object}   scope (optional) The scope in which to execute the handler
5881  * function. The handler function's "this" context.
5882  * @param {Object}   options  (optional)
5883  * @method
5884  */
5885 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5886 /**
5887  * Removes a listener (shorthand for removeListener)
5888  * @param {String}   eventName     The type of event to listen for
5889  * @param {Function} handler        The handler to remove
5890  * @param {Object}   scope  (optional) The scope (this object) for the handler
5891  * @method
5892  */
5893 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5894
5895 /**
5896  * Starts capture on the specified Observable. All events will be passed
5897  * to the supplied function with the event name + standard signature of the event
5898  * <b>before</b> the event is fired. If the supplied function returns false,
5899  * the event will not fire.
5900  * @param {Observable} o The Observable to capture
5901  * @param {Function} fn The function to call
5902  * @param {Object} scope (optional) The scope (this object) for the fn
5903  * @static
5904  */
5905 Roo.util.Observable.capture = function(o, fn, scope){
5906     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5907 };
5908
5909 /**
5910  * Removes <b>all</b> added captures from the Observable.
5911  * @param {Observable} o The Observable to release
5912  * @static
5913  */
5914 Roo.util.Observable.releaseCapture = function(o){
5915     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5916 };
5917
5918 (function(){
5919
5920     var createBuffered = function(h, o, scope){
5921         var task = new Roo.util.DelayedTask();
5922         return function(){
5923             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5924         };
5925     };
5926
5927     var createSingle = function(h, e, fn, scope){
5928         return function(){
5929             e.removeListener(fn, scope);
5930             return h.apply(scope, arguments);
5931         };
5932     };
5933
5934     var createDelayed = function(h, o, scope){
5935         return function(){
5936             var args = Array.prototype.slice.call(arguments, 0);
5937             setTimeout(function(){
5938                 h.apply(scope, args);
5939             }, o.delay || 10);
5940         };
5941     };
5942
5943     Roo.util.Event = function(obj, name){
5944         this.name = name;
5945         this.obj = obj;
5946         this.listeners = [];
5947     };
5948
5949     Roo.util.Event.prototype = {
5950         addListener : function(fn, scope, options){
5951             var o = options || {};
5952             scope = scope || this.obj;
5953             if(!this.isListening(fn, scope)){
5954                 var l = {fn: fn, scope: scope, options: o};
5955                 var h = fn;
5956                 if(o.delay){
5957                     h = createDelayed(h, o, scope);
5958                 }
5959                 if(o.single){
5960                     h = createSingle(h, this, fn, scope);
5961                 }
5962                 if(o.buffer){
5963                     h = createBuffered(h, o, scope);
5964                 }
5965                 l.fireFn = h;
5966                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5967                     this.listeners.push(l);
5968                 }else{
5969                     this.listeners = this.listeners.slice(0);
5970                     this.listeners.push(l);
5971                 }
5972             }
5973         },
5974
5975         findListener : function(fn, scope){
5976             scope = scope || this.obj;
5977             var ls = this.listeners;
5978             for(var i = 0, len = ls.length; i < len; i++){
5979                 var l = ls[i];
5980                 if(l.fn == fn && l.scope == scope){
5981                     return i;
5982                 }
5983             }
5984             return -1;
5985         },
5986
5987         isListening : function(fn, scope){
5988             return this.findListener(fn, scope) != -1;
5989         },
5990
5991         removeListener : function(fn, scope){
5992             var index;
5993             if((index = this.findListener(fn, scope)) != -1){
5994                 if(!this.firing){
5995                     this.listeners.splice(index, 1);
5996                 }else{
5997                     this.listeners = this.listeners.slice(0);
5998                     this.listeners.splice(index, 1);
5999                 }
6000                 return true;
6001             }
6002             return false;
6003         },
6004
6005         clearListeners : function(){
6006             this.listeners = [];
6007         },
6008
6009         fire : function(){
6010             var ls = this.listeners, scope, len = ls.length;
6011             if(len > 0){
6012                 this.firing = true;
6013                 var args = Array.prototype.slice.call(arguments, 0);
6014                 for(var i = 0; i < len; i++){
6015                     var l = ls[i];
6016                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6017                         this.firing = false;
6018                         return false;
6019                     }
6020                 }
6021                 this.firing = false;
6022             }
6023             return true;
6024         }
6025     };
6026 })();/*
6027  * Based on:
6028  * Ext JS Library 1.1.1
6029  * Copyright(c) 2006-2007, Ext JS, LLC.
6030  *
6031  * Originally Released Under LGPL - original licence link has changed is not relivant.
6032  *
6033  * Fork - LGPL
6034  * <script type="text/javascript">
6035  */
6036
6037 /**
6038  * @class Roo.EventManager
6039  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6040  * several useful events directly.
6041  * See {@link Roo.EventObject} for more details on normalized event objects.
6042  * @singleton
6043  */
6044 Roo.EventManager = function(){
6045     var docReadyEvent, docReadyProcId, docReadyState = false;
6046     var resizeEvent, resizeTask, textEvent, textSize;
6047     var E = Roo.lib.Event;
6048     var D = Roo.lib.Dom;
6049
6050     
6051     
6052
6053     var fireDocReady = function(){
6054         if(!docReadyState){
6055             docReadyState = true;
6056             Roo.isReady = true;
6057             if(docReadyProcId){
6058                 clearInterval(docReadyProcId);
6059             }
6060             if(Roo.isGecko || Roo.isOpera) {
6061                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6062             }
6063             if(Roo.isIE){
6064                 var defer = document.getElementById("ie-deferred-loader");
6065                 if(defer){
6066                     defer.onreadystatechange = null;
6067                     defer.parentNode.removeChild(defer);
6068                 }
6069             }
6070             if(docReadyEvent){
6071                 docReadyEvent.fire();
6072                 docReadyEvent.clearListeners();
6073             }
6074         }
6075     };
6076     
6077     var initDocReady = function(){
6078         docReadyEvent = new Roo.util.Event();
6079         if(Roo.isGecko || Roo.isOpera) {
6080             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6081         }else if(Roo.isIE){
6082             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6083             var defer = document.getElementById("ie-deferred-loader");
6084             defer.onreadystatechange = function(){
6085                 if(this.readyState == "complete"){
6086                     fireDocReady();
6087                 }
6088             };
6089         }else if(Roo.isSafari){ 
6090             docReadyProcId = setInterval(function(){
6091                 var rs = document.readyState;
6092                 if(rs == "complete") {
6093                     fireDocReady();     
6094                  }
6095             }, 10);
6096         }
6097         // no matter what, make sure it fires on load
6098         E.on(window, "load", fireDocReady);
6099     };
6100
6101     var createBuffered = function(h, o){
6102         var task = new Roo.util.DelayedTask(h);
6103         return function(e){
6104             // create new event object impl so new events don't wipe out properties
6105             e = new Roo.EventObjectImpl(e);
6106             task.delay(o.buffer, h, null, [e]);
6107         };
6108     };
6109
6110     var createSingle = function(h, el, ename, fn){
6111         return function(e){
6112             Roo.EventManager.removeListener(el, ename, fn);
6113             h(e);
6114         };
6115     };
6116
6117     var createDelayed = function(h, o){
6118         return function(e){
6119             // create new event object impl so new events don't wipe out properties
6120             e = new Roo.EventObjectImpl(e);
6121             setTimeout(function(){
6122                 h(e);
6123             }, o.delay || 10);
6124         };
6125     };
6126     var transitionEndVal = false;
6127     
6128     var transitionEnd = funciton()
6129     {
6130         if (transitionEndVal) {
6131             return transitionEndVal;
6132         }
6133         var el = document.createElement('div')
6134
6135         var transEndEventNames = {
6136             WebkitTransition : 'webkitTransitionEnd',
6137             MozTransition    : 'transitionend',
6138             OTransition      : 'oTransitionEnd otransitionend',
6139             transition       : 'transitionend'
6140         }
6141     
6142         for (var name in transEndEventNames) {
6143             if (el.style[name] !== undefined) {
6144                 transitionEndVal = transEndEventNames[name];
6145                 return  transitionEndVal ;
6146             }
6147         }
6148     }
6149     
6150
6151     var listen = function(element, ename, opt, fn, scope){
6152         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6153         fn = fn || o.fn; scope = scope || o.scope;
6154         var el = Roo.getDom(element);
6155         if(!el){
6156             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6157         }
6158         var h = function(e){
6159             e = Roo.EventObject.setEvent(e);
6160             var t;
6161             if(o.delegate){
6162                 t = e.getTarget(o.delegate, el);
6163                 if(!t){
6164                     return;
6165                 }
6166             }else{
6167                 t = e.target;
6168             }
6169             if(o.stopEvent === true){
6170                 e.stopEvent();
6171             }
6172             if(o.preventDefault === true){
6173                e.preventDefault();
6174             }
6175             if(o.stopPropagation === true){
6176                 e.stopPropagation();
6177             }
6178
6179             if(o.normalized === false){
6180                 e = e.browserEvent;
6181             }
6182
6183             fn.call(scope || el, e, t, o);
6184         };
6185         if(o.delay){
6186             h = createDelayed(h, o);
6187         }
6188         if(o.single){
6189             h = createSingle(h, el, ename, fn);
6190         }
6191         if(o.buffer){
6192             h = createBuffered(h, o);
6193         }
6194         fn._handlers = fn._handlers || [];
6195         fn._handlers.push([Roo.id(el), ename, h]);
6196         
6197         if (ename == 'transitionend') {
6198             ename = transitionEnd();
6199         }
6200          
6201         E.on(el, ename, h);
6202         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6203             el.addEventListener("DOMMouseScroll", h, false);
6204             E.on(window, 'unload', function(){
6205                 el.removeEventListener("DOMMouseScroll", h, false);
6206             });
6207         }
6208         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6209             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6210         }
6211         return h;
6212     };
6213
6214     var stopListening = function(el, ename, fn){
6215         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6216         if(hds){
6217             for(var i = 0, len = hds.length; i < len; i++){
6218                 var h = hds[i];
6219                 if(h[0] == id && h[1] == ename){
6220                     hd = h[2];
6221                     hds.splice(i, 1);
6222                     break;
6223                 }
6224             }
6225         }
6226         E.un(el, ename, hd);
6227         el = Roo.getDom(el);
6228         if(ename == "mousewheel" && el.addEventListener){
6229             el.removeEventListener("DOMMouseScroll", hd, false);
6230         }
6231         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6232             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6233         }
6234     };
6235
6236     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6237     
6238     var pub = {
6239         
6240         
6241         /** 
6242          * Fix for doc tools
6243          * @scope Roo.EventManager
6244          */
6245         
6246         
6247         /** 
6248          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6249          * object with a Roo.EventObject
6250          * @param {Function} fn        The method the event invokes
6251          * @param {Object}   scope    An object that becomes the scope of the handler
6252          * @param {boolean}  override If true, the obj passed in becomes
6253          *                             the execution scope of the listener
6254          * @return {Function} The wrapped function
6255          * @deprecated
6256          */
6257         wrap : function(fn, scope, override){
6258             return function(e){
6259                 Roo.EventObject.setEvent(e);
6260                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6261             };
6262         },
6263         
6264         /**
6265      * Appends an event handler to an element (shorthand for addListener)
6266      * @param {String/HTMLElement}   element        The html element or id to assign the
6267      * @param {String}   eventName The type of event to listen for
6268      * @param {Function} handler The method the event invokes
6269      * @param {Object}   scope (optional) The scope in which to execute the handler
6270      * function. The handler function's "this" context.
6271      * @param {Object}   options (optional) An object containing handler configuration
6272      * properties. This may contain any of the following properties:<ul>
6273      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6274      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6275      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6276      * <li>preventDefault {Boolean} True to prevent the default action</li>
6277      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6278      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6279      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6280      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6281      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6282      * by the specified number of milliseconds. If the event fires again within that time, the original
6283      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6284      * </ul><br>
6285      * <p>
6286      * <b>Combining Options</b><br>
6287      * Using the options argument, it is possible to combine different types of listeners:<br>
6288      * <br>
6289      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6290      * Code:<pre><code>
6291 el.on('click', this.onClick, this, {
6292     single: true,
6293     delay: 100,
6294     stopEvent : true,
6295     forumId: 4
6296 });</code></pre>
6297      * <p>
6298      * <b>Attaching multiple handlers in 1 call</b><br>
6299       * The method also allows for a single argument to be passed which is a config object containing properties
6300      * which specify multiple handlers.
6301      * <p>
6302      * Code:<pre><code>
6303 el.on({
6304     'click' : {
6305         fn: this.onClick
6306         scope: this,
6307         delay: 100
6308     },
6309     'mouseover' : {
6310         fn: this.onMouseOver
6311         scope: this
6312     },
6313     'mouseout' : {
6314         fn: this.onMouseOut
6315         scope: this
6316     }
6317 });</code></pre>
6318      * <p>
6319      * Or a shorthand syntax:<br>
6320      * Code:<pre><code>
6321 el.on({
6322     'click' : this.onClick,
6323     'mouseover' : this.onMouseOver,
6324     'mouseout' : this.onMouseOut
6325     scope: this
6326 });</code></pre>
6327      */
6328         addListener : function(element, eventName, fn, scope, options){
6329             if(typeof eventName == "object"){
6330                 var o = eventName;
6331                 for(var e in o){
6332                     if(propRe.test(e)){
6333                         continue;
6334                     }
6335                     if(typeof o[e] == "function"){
6336                         // shared options
6337                         listen(element, e, o, o[e], o.scope);
6338                     }else{
6339                         // individual options
6340                         listen(element, e, o[e]);
6341                     }
6342                 }
6343                 return;
6344             }
6345             return listen(element, eventName, options, fn, scope);
6346         },
6347         
6348         /**
6349          * Removes an event handler
6350          *
6351          * @param {String/HTMLElement}   element        The id or html element to remove the 
6352          *                             event from
6353          * @param {String}   eventName     The type of event
6354          * @param {Function} fn
6355          * @return {Boolean} True if a listener was actually removed
6356          */
6357         removeListener : function(element, eventName, fn){
6358             return stopListening(element, eventName, fn);
6359         },
6360         
6361         /**
6362          * Fires when the document is ready (before onload and before images are loaded). Can be 
6363          * accessed shorthanded Roo.onReady().
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         onDocumentReady : function(fn, scope, options){
6369             if(docReadyState){ // if it already fired
6370                 docReadyEvent.addListener(fn, scope, options);
6371                 docReadyEvent.fire();
6372                 docReadyEvent.clearListeners();
6373                 return;
6374             }
6375             if(!docReadyEvent){
6376                 initDocReady();
6377             }
6378             docReadyEvent.addListener(fn, scope, options);
6379         },
6380         
6381         /**
6382          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6383          * @param {Function} fn        The method the event invokes
6384          * @param {Object}   scope    An object that becomes the scope of the handler
6385          * @param {boolean}  options
6386          */
6387         onWindowResize : function(fn, scope, options){
6388             if(!resizeEvent){
6389                 resizeEvent = new Roo.util.Event();
6390                 resizeTask = new Roo.util.DelayedTask(function(){
6391                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6392                 });
6393                 E.on(window, "resize", function(){
6394                     if(Roo.isIE){
6395                         resizeTask.delay(50);
6396                     }else{
6397                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6398                     }
6399                 });
6400             }
6401             resizeEvent.addListener(fn, scope, options);
6402         },
6403
6404         /**
6405          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6406          * @param {Function} fn        The method the event invokes
6407          * @param {Object}   scope    An object that becomes the scope of the handler
6408          * @param {boolean}  options
6409          */
6410         onTextResize : function(fn, scope, options){
6411             if(!textEvent){
6412                 textEvent = new Roo.util.Event();
6413                 var textEl = new Roo.Element(document.createElement('div'));
6414                 textEl.dom.className = 'x-text-resize';
6415                 textEl.dom.innerHTML = 'X';
6416                 textEl.appendTo(document.body);
6417                 textSize = textEl.dom.offsetHeight;
6418                 setInterval(function(){
6419                     if(textEl.dom.offsetHeight != textSize){
6420                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6421                     }
6422                 }, this.textResizeInterval);
6423             }
6424             textEvent.addListener(fn, scope, options);
6425         },
6426
6427         /**
6428          * Removes the passed window resize listener.
6429          * @param {Function} fn        The method the event invokes
6430          * @param {Object}   scope    The scope of handler
6431          */
6432         removeResizeListener : function(fn, scope){
6433             if(resizeEvent){
6434                 resizeEvent.removeListener(fn, scope);
6435             }
6436         },
6437
6438         // private
6439         fireResize : function(){
6440             if(resizeEvent){
6441                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6442             }   
6443         },
6444         /**
6445          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6446          */
6447         ieDeferSrc : false,
6448         /**
6449          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6450          */
6451         textResizeInterval : 50
6452     };
6453     
6454     /**
6455      * Fix for doc tools
6456      * @scopeAlias pub=Roo.EventManager
6457      */
6458     
6459      /**
6460      * Appends an event handler to an element (shorthand for addListener)
6461      * @param {String/HTMLElement}   element        The html element or id to assign the
6462      * @param {String}   eventName The type of event to listen for
6463      * @param {Function} handler The method the event invokes
6464      * @param {Object}   scope (optional) The scope in which to execute the handler
6465      * function. The handler function's "this" context.
6466      * @param {Object}   options (optional) An object containing handler configuration
6467      * properties. This may contain any of the following properties:<ul>
6468      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6469      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6470      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6471      * <li>preventDefault {Boolean} True to prevent the default action</li>
6472      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6473      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6474      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6475      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6476      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6477      * by the specified number of milliseconds. If the event fires again within that time, the original
6478      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6479      * </ul><br>
6480      * <p>
6481      * <b>Combining Options</b><br>
6482      * Using the options argument, it is possible to combine different types of listeners:<br>
6483      * <br>
6484      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6485      * Code:<pre><code>
6486 el.on('click', this.onClick, this, {
6487     single: true,
6488     delay: 100,
6489     stopEvent : true,
6490     forumId: 4
6491 });</code></pre>
6492      * <p>
6493      * <b>Attaching multiple handlers in 1 call</b><br>
6494       * The method also allows for a single argument to be passed which is a config object containing properties
6495      * which specify multiple handlers.
6496      * <p>
6497      * Code:<pre><code>
6498 el.on({
6499     'click' : {
6500         fn: this.onClick
6501         scope: this,
6502         delay: 100
6503     },
6504     'mouseover' : {
6505         fn: this.onMouseOver
6506         scope: this
6507     },
6508     'mouseout' : {
6509         fn: this.onMouseOut
6510         scope: this
6511     }
6512 });</code></pre>
6513      * <p>
6514      * Or a shorthand syntax:<br>
6515      * Code:<pre><code>
6516 el.on({
6517     'click' : this.onClick,
6518     'mouseover' : this.onMouseOver,
6519     'mouseout' : this.onMouseOut
6520     scope: this
6521 });</code></pre>
6522      */
6523     pub.on = pub.addListener;
6524     pub.un = pub.removeListener;
6525
6526     pub.stoppedMouseDownEvent = new Roo.util.Event();
6527     return pub;
6528 }();
6529 /**
6530   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6531   * @param {Function} fn        The method the event invokes
6532   * @param {Object}   scope    An  object that becomes the scope of the handler
6533   * @param {boolean}  override If true, the obj passed in becomes
6534   *                             the execution scope of the listener
6535   * @member Roo
6536   * @method onReady
6537  */
6538 Roo.onReady = Roo.EventManager.onDocumentReady;
6539
6540 Roo.onReady(function(){
6541     var bd = Roo.get(document.body);
6542     if(!bd){ return; }
6543
6544     var cls = [
6545             Roo.isIE ? "roo-ie"
6546             : Roo.isGecko ? "roo-gecko"
6547             : Roo.isOpera ? "roo-opera"
6548             : Roo.isSafari ? "roo-safari" : ""];
6549
6550     if(Roo.isMac){
6551         cls.push("roo-mac");
6552     }
6553     if(Roo.isLinux){
6554         cls.push("roo-linux");
6555     }
6556     if(Roo.isBorderBox){
6557         cls.push('roo-border-box');
6558     }
6559     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6560         var p = bd.dom.parentNode;
6561         if(p){
6562             p.className += ' roo-strict';
6563         }
6564     }
6565     bd.addClass(cls.join(' '));
6566 });
6567
6568 /**
6569  * @class Roo.EventObject
6570  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6571  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6572  * Example:
6573  * <pre><code>
6574  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6575     e.preventDefault();
6576     var target = e.getTarget();
6577     ...
6578  }
6579  var myDiv = Roo.get("myDiv");
6580  myDiv.on("click", handleClick);
6581  //or
6582  Roo.EventManager.on("myDiv", 'click', handleClick);
6583  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6584  </code></pre>
6585  * @singleton
6586  */
6587 Roo.EventObject = function(){
6588     
6589     var E = Roo.lib.Event;
6590     
6591     // safari keypress events for special keys return bad keycodes
6592     var safariKeys = {
6593         63234 : 37, // left
6594         63235 : 39, // right
6595         63232 : 38, // up
6596         63233 : 40, // down
6597         63276 : 33, // page up
6598         63277 : 34, // page down
6599         63272 : 46, // delete
6600         63273 : 36, // home
6601         63275 : 35  // end
6602     };
6603
6604     // normalize button clicks
6605     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6606                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6607
6608     Roo.EventObjectImpl = function(e){
6609         if(e){
6610             this.setEvent(e.browserEvent || e);
6611         }
6612     };
6613     Roo.EventObjectImpl.prototype = {
6614         /**
6615          * Used to fix doc tools.
6616          * @scope Roo.EventObject.prototype
6617          */
6618             
6619
6620         
6621         
6622         /** The normal browser event */
6623         browserEvent : null,
6624         /** The button pressed in a mouse event */
6625         button : -1,
6626         /** True if the shift key was down during the event */
6627         shiftKey : false,
6628         /** True if the control key was down during the event */
6629         ctrlKey : false,
6630         /** True if the alt key was down during the event */
6631         altKey : false,
6632
6633         /** Key constant 
6634         * @type Number */
6635         BACKSPACE : 8,
6636         /** Key constant 
6637         * @type Number */
6638         TAB : 9,
6639         /** Key constant 
6640         * @type Number */
6641         RETURN : 13,
6642         /** Key constant 
6643         * @type Number */
6644         ENTER : 13,
6645         /** Key constant 
6646         * @type Number */
6647         SHIFT : 16,
6648         /** Key constant 
6649         * @type Number */
6650         CONTROL : 17,
6651         /** Key constant 
6652         * @type Number */
6653         ESC : 27,
6654         /** Key constant 
6655         * @type Number */
6656         SPACE : 32,
6657         /** Key constant 
6658         * @type Number */
6659         PAGEUP : 33,
6660         /** Key constant 
6661         * @type Number */
6662         PAGEDOWN : 34,
6663         /** Key constant 
6664         * @type Number */
6665         END : 35,
6666         /** Key constant 
6667         * @type Number */
6668         HOME : 36,
6669         /** Key constant 
6670         * @type Number */
6671         LEFT : 37,
6672         /** Key constant 
6673         * @type Number */
6674         UP : 38,
6675         /** Key constant 
6676         * @type Number */
6677         RIGHT : 39,
6678         /** Key constant 
6679         * @type Number */
6680         DOWN : 40,
6681         /** Key constant 
6682         * @type Number */
6683         DELETE : 46,
6684         /** Key constant 
6685         * @type Number */
6686         F5 : 116,
6687
6688            /** @private */
6689         setEvent : function(e){
6690             if(e == this || (e && e.browserEvent)){ // already wrapped
6691                 return e;
6692             }
6693             this.browserEvent = e;
6694             if(e){
6695                 // normalize buttons
6696                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6697                 if(e.type == 'click' && this.button == -1){
6698                     this.button = 0;
6699                 }
6700                 this.type = e.type;
6701                 this.shiftKey = e.shiftKey;
6702                 // mac metaKey behaves like ctrlKey
6703                 this.ctrlKey = e.ctrlKey || e.metaKey;
6704                 this.altKey = e.altKey;
6705                 // in getKey these will be normalized for the mac
6706                 this.keyCode = e.keyCode;
6707                 // keyup warnings on firefox.
6708                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6709                 // cache the target for the delayed and or buffered events
6710                 this.target = E.getTarget(e);
6711                 // same for XY
6712                 this.xy = E.getXY(e);
6713             }else{
6714                 this.button = -1;
6715                 this.shiftKey = false;
6716                 this.ctrlKey = false;
6717                 this.altKey = false;
6718                 this.keyCode = 0;
6719                 this.charCode =0;
6720                 this.target = null;
6721                 this.xy = [0, 0];
6722             }
6723             return this;
6724         },
6725
6726         /**
6727          * Stop the event (preventDefault and stopPropagation)
6728          */
6729         stopEvent : function(){
6730             if(this.browserEvent){
6731                 if(this.browserEvent.type == 'mousedown'){
6732                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6733                 }
6734                 E.stopEvent(this.browserEvent);
6735             }
6736         },
6737
6738         /**
6739          * Prevents the browsers default handling of the event.
6740          */
6741         preventDefault : function(){
6742             if(this.browserEvent){
6743                 E.preventDefault(this.browserEvent);
6744             }
6745         },
6746
6747         /** @private */
6748         isNavKeyPress : function(){
6749             var k = this.keyCode;
6750             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6751             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6752         },
6753
6754         isSpecialKey : function(){
6755             var k = this.keyCode;
6756             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6757             (k == 16) || (k == 17) ||
6758             (k >= 18 && k <= 20) ||
6759             (k >= 33 && k <= 35) ||
6760             (k >= 36 && k <= 39) ||
6761             (k >= 44 && k <= 45);
6762         },
6763         /**
6764          * Cancels bubbling of the event.
6765          */
6766         stopPropagation : function(){
6767             if(this.browserEvent){
6768                 if(this.type == 'mousedown'){
6769                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6770                 }
6771                 E.stopPropagation(this.browserEvent);
6772             }
6773         },
6774
6775         /**
6776          * Gets the key code for the event.
6777          * @return {Number}
6778          */
6779         getCharCode : function(){
6780             return this.charCode || this.keyCode;
6781         },
6782
6783         /**
6784          * Returns a normalized keyCode for the event.
6785          * @return {Number} The key code
6786          */
6787         getKey : function(){
6788             var k = this.keyCode || this.charCode;
6789             return Roo.isSafari ? (safariKeys[k] || k) : k;
6790         },
6791
6792         /**
6793          * Gets the x coordinate of the event.
6794          * @return {Number}
6795          */
6796         getPageX : function(){
6797             return this.xy[0];
6798         },
6799
6800         /**
6801          * Gets the y coordinate of the event.
6802          * @return {Number}
6803          */
6804         getPageY : function(){
6805             return this.xy[1];
6806         },
6807
6808         /**
6809          * Gets the time of the event.
6810          * @return {Number}
6811          */
6812         getTime : function(){
6813             if(this.browserEvent){
6814                 return E.getTime(this.browserEvent);
6815             }
6816             return null;
6817         },
6818
6819         /**
6820          * Gets the page coordinates of the event.
6821          * @return {Array} The xy values like [x, y]
6822          */
6823         getXY : function(){
6824             return this.xy;
6825         },
6826
6827         /**
6828          * Gets the target for the event.
6829          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6830          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6831                 search as a number or element (defaults to 10 || document.body)
6832          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6833          * @return {HTMLelement}
6834          */
6835         getTarget : function(selector, maxDepth, returnEl){
6836             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6837         },
6838         /**
6839          * Gets the related target.
6840          * @return {HTMLElement}
6841          */
6842         getRelatedTarget : function(){
6843             if(this.browserEvent){
6844                 return E.getRelatedTarget(this.browserEvent);
6845             }
6846             return null;
6847         },
6848
6849         /**
6850          * Normalizes mouse wheel delta across browsers
6851          * @return {Number} The delta
6852          */
6853         getWheelDelta : function(){
6854             var e = this.browserEvent;
6855             var delta = 0;
6856             if(e.wheelDelta){ /* IE/Opera. */
6857                 delta = e.wheelDelta/120;
6858             }else if(e.detail){ /* Mozilla case. */
6859                 delta = -e.detail/3;
6860             }
6861             return delta;
6862         },
6863
6864         /**
6865          * Returns true if the control, meta, shift or alt key was pressed during this event.
6866          * @return {Boolean}
6867          */
6868         hasModifier : function(){
6869             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6870         },
6871
6872         /**
6873          * Returns true if the target of this event equals el or is a child of el
6874          * @param {String/HTMLElement/Element} el
6875          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6876          * @return {Boolean}
6877          */
6878         within : function(el, related){
6879             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6880             return t && Roo.fly(el).contains(t);
6881         },
6882
6883         getPoint : function(){
6884             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6885         }
6886     };
6887
6888     return new Roo.EventObjectImpl();
6889 }();
6890             
6891     /*
6892  * Based on:
6893  * Ext JS Library 1.1.1
6894  * Copyright(c) 2006-2007, Ext JS, LLC.
6895  *
6896  * Originally Released Under LGPL - original licence link has changed is not relivant.
6897  *
6898  * Fork - LGPL
6899  * <script type="text/javascript">
6900  */
6901
6902  
6903 // was in Composite Element!??!?!
6904  
6905 (function(){
6906     var D = Roo.lib.Dom;
6907     var E = Roo.lib.Event;
6908     var A = Roo.lib.Anim;
6909
6910     // local style camelizing for speed
6911     var propCache = {};
6912     var camelRe = /(-[a-z])/gi;
6913     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6914     var view = document.defaultView;
6915
6916 /**
6917  * @class Roo.Element
6918  * Represents an Element in the DOM.<br><br>
6919  * Usage:<br>
6920 <pre><code>
6921 var el = Roo.get("my-div");
6922
6923 // or with getEl
6924 var el = getEl("my-div");
6925
6926 // or with a DOM element
6927 var el = Roo.get(myDivElement);
6928 </code></pre>
6929  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6930  * each call instead of constructing a new one.<br><br>
6931  * <b>Animations</b><br />
6932  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6933  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6934 <pre>
6935 Option    Default   Description
6936 --------- --------  ---------------------------------------------
6937 duration  .35       The duration of the animation in seconds
6938 easing    easeOut   The YUI easing method
6939 callback  none      A function to execute when the anim completes
6940 scope     this      The scope (this) of the callback function
6941 </pre>
6942 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6943 * manipulate the animation. Here's an example:
6944 <pre><code>
6945 var el = Roo.get("my-div");
6946
6947 // no animation
6948 el.setWidth(100);
6949
6950 // default animation
6951 el.setWidth(100, true);
6952
6953 // animation with some options set
6954 el.setWidth(100, {
6955     duration: 1,
6956     callback: this.foo,
6957     scope: this
6958 });
6959
6960 // using the "anim" property to get the Anim object
6961 var opt = {
6962     duration: 1,
6963     callback: this.foo,
6964     scope: this
6965 };
6966 el.setWidth(100, opt);
6967 ...
6968 if(opt.anim.isAnimated()){
6969     opt.anim.stop();
6970 }
6971 </code></pre>
6972 * <b> Composite (Collections of) Elements</b><br />
6973  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6974  * @constructor Create a new Element directly.
6975  * @param {String/HTMLElement} element
6976  * @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).
6977  */
6978     Roo.Element = function(element, forceNew){
6979         var dom = typeof element == "string" ?
6980                 document.getElementById(element) : element;
6981         if(!dom){ // invalid id/element
6982             return null;
6983         }
6984         var id = dom.id;
6985         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6986             return Roo.Element.cache[id];
6987         }
6988
6989         /**
6990          * The DOM element
6991          * @type HTMLElement
6992          */
6993         this.dom = dom;
6994
6995         /**
6996          * The DOM element ID
6997          * @type String
6998          */
6999         this.id = id || Roo.id(dom);
7000     };
7001
7002     var El = Roo.Element;
7003
7004     El.prototype = {
7005         /**
7006          * The element's default display mode  (defaults to "")
7007          * @type String
7008          */
7009         originalDisplay : "",
7010
7011         visibilityMode : 1,
7012         /**
7013          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7014          * @type String
7015          */
7016         defaultUnit : "px",
7017         /**
7018          * Sets the element's visibility mode. When setVisible() is called it
7019          * will use this to determine whether to set the visibility or the display property.
7020          * @param visMode Element.VISIBILITY or Element.DISPLAY
7021          * @return {Roo.Element} this
7022          */
7023         setVisibilityMode : function(visMode){
7024             this.visibilityMode = visMode;
7025             return this;
7026         },
7027         /**
7028          * Convenience method for setVisibilityMode(Element.DISPLAY)
7029          * @param {String} display (optional) What to set display to when visible
7030          * @return {Roo.Element} this
7031          */
7032         enableDisplayMode : function(display){
7033             this.setVisibilityMode(El.DISPLAY);
7034             if(typeof display != "undefined") this.originalDisplay = display;
7035             return this;
7036         },
7037
7038         /**
7039          * 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)
7040          * @param {String} selector The simple selector to test
7041          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7042                 search as a number or element (defaults to 10 || document.body)
7043          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7044          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7045          */
7046         findParent : function(simpleSelector, maxDepth, returnEl){
7047             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7048             maxDepth = maxDepth || 50;
7049             if(typeof maxDepth != "number"){
7050                 stopEl = Roo.getDom(maxDepth);
7051                 maxDepth = 10;
7052             }
7053             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7054                 if(dq.is(p, simpleSelector)){
7055                     return returnEl ? Roo.get(p) : p;
7056                 }
7057                 depth++;
7058                 p = p.parentNode;
7059             }
7060             return null;
7061         },
7062
7063
7064         /**
7065          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7066          * @param {String} selector The simple selector to test
7067          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7068                 search as a number or element (defaults to 10 || document.body)
7069          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7070          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7071          */
7072         findParentNode : function(simpleSelector, maxDepth, returnEl){
7073             var p = Roo.fly(this.dom.parentNode, '_internal');
7074             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7075         },
7076
7077         /**
7078          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7079          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7080          * @param {String} selector The simple selector to test
7081          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7082                 search as a number or element (defaults to 10 || document.body)
7083          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7084          */
7085         up : function(simpleSelector, maxDepth){
7086             return this.findParentNode(simpleSelector, maxDepth, true);
7087         },
7088
7089
7090
7091         /**
7092          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7093          * @param {String} selector The simple selector to test
7094          * @return {Boolean} True if this element matches the selector, else false
7095          */
7096         is : function(simpleSelector){
7097             return Roo.DomQuery.is(this.dom, simpleSelector);
7098         },
7099
7100         /**
7101          * Perform animation on this element.
7102          * @param {Object} args The YUI animation control args
7103          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7104          * @param {Function} onComplete (optional) Function to call when animation completes
7105          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7106          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7107          * @return {Roo.Element} this
7108          */
7109         animate : function(args, duration, onComplete, easing, animType){
7110             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7111             return this;
7112         },
7113
7114         /*
7115          * @private Internal animation call
7116          */
7117         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7118             animType = animType || 'run';
7119             opt = opt || {};
7120             var anim = Roo.lib.Anim[animType](
7121                 this.dom, args,
7122                 (opt.duration || defaultDur) || .35,
7123                 (opt.easing || defaultEase) || 'easeOut',
7124                 function(){
7125                     Roo.callback(cb, this);
7126                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7127                 },
7128                 this
7129             );
7130             opt.anim = anim;
7131             return anim;
7132         },
7133
7134         // private legacy anim prep
7135         preanim : function(a, i){
7136             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7137         },
7138
7139         /**
7140          * Removes worthless text nodes
7141          * @param {Boolean} forceReclean (optional) By default the element
7142          * keeps track if it has been cleaned already so
7143          * you can call this over and over. However, if you update the element and
7144          * need to force a reclean, you can pass true.
7145          */
7146         clean : function(forceReclean){
7147             if(this.isCleaned && forceReclean !== true){
7148                 return this;
7149             }
7150             var ns = /\S/;
7151             var d = this.dom, n = d.firstChild, ni = -1;
7152             while(n){
7153                 var nx = n.nextSibling;
7154                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7155                     d.removeChild(n);
7156                 }else{
7157                     n.nodeIndex = ++ni;
7158                 }
7159                 n = nx;
7160             }
7161             this.isCleaned = true;
7162             return this;
7163         },
7164
7165         // private
7166         calcOffsetsTo : function(el){
7167             el = Roo.get(el);
7168             var d = el.dom;
7169             var restorePos = false;
7170             if(el.getStyle('position') == 'static'){
7171                 el.position('relative');
7172                 restorePos = true;
7173             }
7174             var x = 0, y =0;
7175             var op = this.dom;
7176             while(op && op != d && op.tagName != 'HTML'){
7177                 x+= op.offsetLeft;
7178                 y+= op.offsetTop;
7179                 op = op.offsetParent;
7180             }
7181             if(restorePos){
7182                 el.position('static');
7183             }
7184             return [x, y];
7185         },
7186
7187         /**
7188          * Scrolls this element into view within the passed container.
7189          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7190          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7191          * @return {Roo.Element} this
7192          */
7193         scrollIntoView : function(container, hscroll){
7194             var c = Roo.getDom(container) || document.body;
7195             var el = this.dom;
7196
7197             var o = this.calcOffsetsTo(c),
7198                 l = o[0],
7199                 t = o[1],
7200                 b = t+el.offsetHeight,
7201                 r = l+el.offsetWidth;
7202
7203             var ch = c.clientHeight;
7204             var ct = parseInt(c.scrollTop, 10);
7205             var cl = parseInt(c.scrollLeft, 10);
7206             var cb = ct + ch;
7207             var cr = cl + c.clientWidth;
7208
7209             if(t < ct){
7210                 c.scrollTop = t;
7211             }else if(b > cb){
7212                 c.scrollTop = b-ch;
7213             }
7214
7215             if(hscroll !== false){
7216                 if(l < cl){
7217                     c.scrollLeft = l;
7218                 }else if(r > cr){
7219                     c.scrollLeft = r-c.clientWidth;
7220                 }
7221             }
7222             return this;
7223         },
7224
7225         // private
7226         scrollChildIntoView : function(child, hscroll){
7227             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7228         },
7229
7230         /**
7231          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7232          * the new height may not be available immediately.
7233          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7234          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7235          * @param {Function} onComplete (optional) Function to call when animation completes
7236          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7237          * @return {Roo.Element} this
7238          */
7239         autoHeight : function(animate, duration, onComplete, easing){
7240             var oldHeight = this.getHeight();
7241             this.clip();
7242             this.setHeight(1); // force clipping
7243             setTimeout(function(){
7244                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7245                 if(!animate){
7246                     this.setHeight(height);
7247                     this.unclip();
7248                     if(typeof onComplete == "function"){
7249                         onComplete();
7250                     }
7251                 }else{
7252                     this.setHeight(oldHeight); // restore original height
7253                     this.setHeight(height, animate, duration, function(){
7254                         this.unclip();
7255                         if(typeof onComplete == "function") onComplete();
7256                     }.createDelegate(this), easing);
7257                 }
7258             }.createDelegate(this), 0);
7259             return this;
7260         },
7261
7262         /**
7263          * Returns true if this element is an ancestor of the passed element
7264          * @param {HTMLElement/String} el The element to check
7265          * @return {Boolean} True if this element is an ancestor of el, else false
7266          */
7267         contains : function(el){
7268             if(!el){return false;}
7269             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7270         },
7271
7272         /**
7273          * Checks whether the element is currently visible using both visibility and display properties.
7274          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7275          * @return {Boolean} True if the element is currently visible, else false
7276          */
7277         isVisible : function(deep) {
7278             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7279             if(deep !== true || !vis){
7280                 return vis;
7281             }
7282             var p = this.dom.parentNode;
7283             while(p && p.tagName.toLowerCase() != "body"){
7284                 if(!Roo.fly(p, '_isVisible').isVisible()){
7285                     return false;
7286                 }
7287                 p = p.parentNode;
7288             }
7289             return true;
7290         },
7291
7292         /**
7293          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7294          * @param {String} selector The CSS selector
7295          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7296          * @return {CompositeElement/CompositeElementLite} The composite element
7297          */
7298         select : function(selector, unique){
7299             return El.select(selector, unique, this.dom);
7300         },
7301
7302         /**
7303          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7304          * @param {String} selector The CSS selector
7305          * @return {Array} An array of the matched nodes
7306          */
7307         query : function(selector, unique){
7308             return Roo.DomQuery.select(selector, this.dom);
7309         },
7310
7311         /**
7312          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7313          * @param {String} selector The CSS selector
7314          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7315          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7316          */
7317         child : function(selector, returnDom){
7318             var n = Roo.DomQuery.selectNode(selector, this.dom);
7319             return returnDom ? n : Roo.get(n);
7320         },
7321
7322         /**
7323          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7324          * @param {String} selector The CSS selector
7325          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7326          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7327          */
7328         down : function(selector, returnDom){
7329             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7330             return returnDom ? n : Roo.get(n);
7331         },
7332
7333         /**
7334          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7335          * @param {String} group The group the DD object is member of
7336          * @param {Object} config The DD config object
7337          * @param {Object} overrides An object containing methods to override/implement on the DD object
7338          * @return {Roo.dd.DD} The DD object
7339          */
7340         initDD : function(group, config, overrides){
7341             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7342             return Roo.apply(dd, overrides);
7343         },
7344
7345         /**
7346          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7347          * @param {String} group The group the DDProxy object is member of
7348          * @param {Object} config The DDProxy config object
7349          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7350          * @return {Roo.dd.DDProxy} The DDProxy object
7351          */
7352         initDDProxy : function(group, config, overrides){
7353             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7354             return Roo.apply(dd, overrides);
7355         },
7356
7357         /**
7358          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7359          * @param {String} group The group the DDTarget object is member of
7360          * @param {Object} config The DDTarget config object
7361          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7362          * @return {Roo.dd.DDTarget} The DDTarget object
7363          */
7364         initDDTarget : function(group, config, overrides){
7365             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7366             return Roo.apply(dd, overrides);
7367         },
7368
7369         /**
7370          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7371          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7372          * @param {Boolean} visible Whether the element is visible
7373          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7374          * @return {Roo.Element} this
7375          */
7376          setVisible : function(visible, animate){
7377             if(!animate || !A){
7378                 if(this.visibilityMode == El.DISPLAY){
7379                     this.setDisplayed(visible);
7380                 }else{
7381                     this.fixDisplay();
7382                     this.dom.style.visibility = visible ? "visible" : "hidden";
7383                 }
7384             }else{
7385                 // closure for composites
7386                 var dom = this.dom;
7387                 var visMode = this.visibilityMode;
7388                 if(visible){
7389                     this.setOpacity(.01);
7390                     this.setVisible(true);
7391                 }
7392                 this.anim({opacity: { to: (visible?1:0) }},
7393                       this.preanim(arguments, 1),
7394                       null, .35, 'easeIn', function(){
7395                          if(!visible){
7396                              if(visMode == El.DISPLAY){
7397                                  dom.style.display = "none";
7398                              }else{
7399                                  dom.style.visibility = "hidden";
7400                              }
7401                              Roo.get(dom).setOpacity(1);
7402                          }
7403                      });
7404             }
7405             return this;
7406         },
7407
7408         /**
7409          * Returns true if display is not "none"
7410          * @return {Boolean}
7411          */
7412         isDisplayed : function() {
7413             return this.getStyle("display") != "none";
7414         },
7415
7416         /**
7417          * Toggles the element's visibility or display, depending on visibility mode.
7418          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7419          * @return {Roo.Element} this
7420          */
7421         toggle : function(animate){
7422             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7423             return this;
7424         },
7425
7426         /**
7427          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7428          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7429          * @return {Roo.Element} this
7430          */
7431         setDisplayed : function(value) {
7432             if(typeof value == "boolean"){
7433                value = value ? this.originalDisplay : "none";
7434             }
7435             this.setStyle("display", value);
7436             return this;
7437         },
7438
7439         /**
7440          * Tries to focus the element. Any exceptions are caught and ignored.
7441          * @return {Roo.Element} this
7442          */
7443         focus : function() {
7444             try{
7445                 this.dom.focus();
7446             }catch(e){}
7447             return this;
7448         },
7449
7450         /**
7451          * Tries to blur the element. Any exceptions are caught and ignored.
7452          * @return {Roo.Element} this
7453          */
7454         blur : function() {
7455             try{
7456                 this.dom.blur();
7457             }catch(e){}
7458             return this;
7459         },
7460
7461         /**
7462          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7463          * @param {String/Array} className The CSS class to add, or an array of classes
7464          * @return {Roo.Element} this
7465          */
7466         addClass : function(className){
7467             if(className instanceof Array){
7468                 for(var i = 0, len = className.length; i < len; i++) {
7469                     this.addClass(className[i]);
7470                 }
7471             }else{
7472                 if(className && !this.hasClass(className)){
7473                     this.dom.className = this.dom.className + " " + className;
7474                 }
7475             }
7476             return this;
7477         },
7478
7479         /**
7480          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7481          * @param {String/Array} className The CSS class to add, or an array of classes
7482          * @return {Roo.Element} this
7483          */
7484         radioClass : function(className){
7485             var siblings = this.dom.parentNode.childNodes;
7486             for(var i = 0; i < siblings.length; i++) {
7487                 var s = siblings[i];
7488                 if(s.nodeType == 1){
7489                     Roo.get(s).removeClass(className);
7490                 }
7491             }
7492             this.addClass(className);
7493             return this;
7494         },
7495
7496         /**
7497          * Removes one or more CSS classes from the element.
7498          * @param {String/Array} className The CSS class to remove, or an array of classes
7499          * @return {Roo.Element} this
7500          */
7501         removeClass : function(className){
7502             if(!className || !this.dom.className){
7503                 return this;
7504             }
7505             if(className instanceof Array){
7506                 for(var i = 0, len = className.length; i < len; i++) {
7507                     this.removeClass(className[i]);
7508                 }
7509             }else{
7510                 if(this.hasClass(className)){
7511                     var re = this.classReCache[className];
7512                     if (!re) {
7513                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7514                        this.classReCache[className] = re;
7515                     }
7516                     this.dom.className =
7517                         this.dom.className.replace(re, " ");
7518                 }
7519             }
7520             return this;
7521         },
7522
7523         // private
7524         classReCache: {},
7525
7526         /**
7527          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7528          * @param {String} className The CSS class to toggle
7529          * @return {Roo.Element} this
7530          */
7531         toggleClass : function(className){
7532             if(this.hasClass(className)){
7533                 this.removeClass(className);
7534             }else{
7535                 this.addClass(className);
7536             }
7537             return this;
7538         },
7539
7540         /**
7541          * Checks if the specified CSS class exists on this element's DOM node.
7542          * @param {String} className The CSS class to check for
7543          * @return {Boolean} True if the class exists, else false
7544          */
7545         hasClass : function(className){
7546             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7547         },
7548
7549         /**
7550          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7551          * @param {String} oldClassName The CSS class to replace
7552          * @param {String} newClassName The replacement CSS class
7553          * @return {Roo.Element} this
7554          */
7555         replaceClass : function(oldClassName, newClassName){
7556             this.removeClass(oldClassName);
7557             this.addClass(newClassName);
7558             return this;
7559         },
7560
7561         /**
7562          * Returns an object with properties matching the styles requested.
7563          * For example, el.getStyles('color', 'font-size', 'width') might return
7564          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7565          * @param {String} style1 A style name
7566          * @param {String} style2 A style name
7567          * @param {String} etc.
7568          * @return {Object} The style object
7569          */
7570         getStyles : function(){
7571             var a = arguments, len = a.length, r = {};
7572             for(var i = 0; i < len; i++){
7573                 r[a[i]] = this.getStyle(a[i]);
7574             }
7575             return r;
7576         },
7577
7578         /**
7579          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7580          * @param {String} property The style property whose value is returned.
7581          * @return {String} The current value of the style property for this element.
7582          */
7583         getStyle : function(){
7584             return view && view.getComputedStyle ?
7585                 function(prop){
7586                     var el = this.dom, v, cs, camel;
7587                     if(prop == 'float'){
7588                         prop = "cssFloat";
7589                     }
7590                     if(el.style && (v = el.style[prop])){
7591                         return v;
7592                     }
7593                     if(cs = view.getComputedStyle(el, "")){
7594                         if(!(camel = propCache[prop])){
7595                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7596                         }
7597                         return cs[camel];
7598                     }
7599                     return null;
7600                 } :
7601                 function(prop){
7602                     var el = this.dom, v, cs, camel;
7603                     if(prop == 'opacity'){
7604                         if(typeof el.style.filter == 'string'){
7605                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7606                             if(m){
7607                                 var fv = parseFloat(m[1]);
7608                                 if(!isNaN(fv)){
7609                                     return fv ? fv / 100 : 0;
7610                                 }
7611                             }
7612                         }
7613                         return 1;
7614                     }else if(prop == 'float'){
7615                         prop = "styleFloat";
7616                     }
7617                     if(!(camel = propCache[prop])){
7618                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7619                     }
7620                     if(v = el.style[camel]){
7621                         return v;
7622                     }
7623                     if(cs = el.currentStyle){
7624                         return cs[camel];
7625                     }
7626                     return null;
7627                 };
7628         }(),
7629
7630         /**
7631          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7632          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7633          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7634          * @return {Roo.Element} this
7635          */
7636         setStyle : function(prop, value){
7637             if(typeof prop == "string"){
7638                 
7639                 if (prop == 'float') {
7640                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7641                     return this;
7642                 }
7643                 
7644                 var camel;
7645                 if(!(camel = propCache[prop])){
7646                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7647                 }
7648                 
7649                 if(camel == 'opacity') {
7650                     this.setOpacity(value);
7651                 }else{
7652                     this.dom.style[camel] = value;
7653                 }
7654             }else{
7655                 for(var style in prop){
7656                     if(typeof prop[style] != "function"){
7657                        this.setStyle(style, prop[style]);
7658                     }
7659                 }
7660             }
7661             return this;
7662         },
7663
7664         /**
7665          * More flexible version of {@link #setStyle} for setting style properties.
7666          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7667          * a function which returns such a specification.
7668          * @return {Roo.Element} this
7669          */
7670         applyStyles : function(style){
7671             Roo.DomHelper.applyStyles(this.dom, style);
7672             return this;
7673         },
7674
7675         /**
7676           * 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).
7677           * @return {Number} The X position of the element
7678           */
7679         getX : function(){
7680             return D.getX(this.dom);
7681         },
7682
7683         /**
7684           * 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).
7685           * @return {Number} The Y position of the element
7686           */
7687         getY : function(){
7688             return D.getY(this.dom);
7689         },
7690
7691         /**
7692           * 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).
7693           * @return {Array} The XY position of the element
7694           */
7695         getXY : function(){
7696             return D.getXY(this.dom);
7697         },
7698
7699         /**
7700          * 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).
7701          * @param {Number} The X position of the element
7702          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7703          * @return {Roo.Element} this
7704          */
7705         setX : function(x, animate){
7706             if(!animate || !A){
7707                 D.setX(this.dom, x);
7708             }else{
7709                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7710             }
7711             return this;
7712         },
7713
7714         /**
7715          * 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).
7716          * @param {Number} The Y position of the element
7717          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7718          * @return {Roo.Element} this
7719          */
7720         setY : function(y, animate){
7721             if(!animate || !A){
7722                 D.setY(this.dom, y);
7723             }else{
7724                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7725             }
7726             return this;
7727         },
7728
7729         /**
7730          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7731          * @param {String} left The left CSS property value
7732          * @return {Roo.Element} this
7733          */
7734         setLeft : function(left){
7735             this.setStyle("left", this.addUnits(left));
7736             return this;
7737         },
7738
7739         /**
7740          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7741          * @param {String} top The top CSS property value
7742          * @return {Roo.Element} this
7743          */
7744         setTop : function(top){
7745             this.setStyle("top", this.addUnits(top));
7746             return this;
7747         },
7748
7749         /**
7750          * Sets the element's CSS right style.
7751          * @param {String} right The right CSS property value
7752          * @return {Roo.Element} this
7753          */
7754         setRight : function(right){
7755             this.setStyle("right", this.addUnits(right));
7756             return this;
7757         },
7758
7759         /**
7760          * Sets the element's CSS bottom style.
7761          * @param {String} bottom The bottom CSS property value
7762          * @return {Roo.Element} this
7763          */
7764         setBottom : function(bottom){
7765             this.setStyle("bottom", this.addUnits(bottom));
7766             return this;
7767         },
7768
7769         /**
7770          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7771          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7772          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7773          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7774          * @return {Roo.Element} this
7775          */
7776         setXY : function(pos, animate){
7777             if(!animate || !A){
7778                 D.setXY(this.dom, pos);
7779             }else{
7780                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7781             }
7782             return this;
7783         },
7784
7785         /**
7786          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7787          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7788          * @param {Number} x X value for new position (coordinates are page-based)
7789          * @param {Number} y Y value for new position (coordinates are page-based)
7790          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7791          * @return {Roo.Element} this
7792          */
7793         setLocation : function(x, y, animate){
7794             this.setXY([x, y], this.preanim(arguments, 2));
7795             return this;
7796         },
7797
7798         /**
7799          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7800          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7801          * @param {Number} x X value for new position (coordinates are page-based)
7802          * @param {Number} y Y value for new position (coordinates are page-based)
7803          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7804          * @return {Roo.Element} this
7805          */
7806         moveTo : function(x, y, animate){
7807             this.setXY([x, y], this.preanim(arguments, 2));
7808             return this;
7809         },
7810
7811         /**
7812          * Returns the region of the given element.
7813          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7814          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7815          */
7816         getRegion : function(){
7817             return D.getRegion(this.dom);
7818         },
7819
7820         /**
7821          * Returns the offset height of the element
7822          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7823          * @return {Number} The element's height
7824          */
7825         getHeight : function(contentHeight){
7826             var h = this.dom.offsetHeight || 0;
7827             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7828         },
7829
7830         /**
7831          * Returns the offset width of the element
7832          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7833          * @return {Number} The element's width
7834          */
7835         getWidth : function(contentWidth){
7836             var w = this.dom.offsetWidth || 0;
7837             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7838         },
7839
7840         /**
7841          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7842          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7843          * if a height has not been set using CSS.
7844          * @return {Number}
7845          */
7846         getComputedHeight : function(){
7847             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7848             if(!h){
7849                 h = parseInt(this.getStyle('height'), 10) || 0;
7850                 if(!this.isBorderBox()){
7851                     h += this.getFrameWidth('tb');
7852                 }
7853             }
7854             return h;
7855         },
7856
7857         /**
7858          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7859          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7860          * if a width has not been set using CSS.
7861          * @return {Number}
7862          */
7863         getComputedWidth : function(){
7864             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7865             if(!w){
7866                 w = parseInt(this.getStyle('width'), 10) || 0;
7867                 if(!this.isBorderBox()){
7868                     w += this.getFrameWidth('lr');
7869                 }
7870             }
7871             return w;
7872         },
7873
7874         /**
7875          * Returns the size of the element.
7876          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7877          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7878          */
7879         getSize : function(contentSize){
7880             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7881         },
7882
7883         /**
7884          * Returns the width and height of the viewport.
7885          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7886          */
7887         getViewSize : function(){
7888             var d = this.dom, doc = document, aw = 0, ah = 0;
7889             if(d == doc || d == doc.body){
7890                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7891             }else{
7892                 return {
7893                     width : d.clientWidth,
7894                     height: d.clientHeight
7895                 };
7896             }
7897         },
7898
7899         /**
7900          * Returns the value of the "value" attribute
7901          * @param {Boolean} asNumber true to parse the value as a number
7902          * @return {String/Number}
7903          */
7904         getValue : function(asNumber){
7905             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7906         },
7907
7908         // private
7909         adjustWidth : function(width){
7910             if(typeof width == "number"){
7911                 if(this.autoBoxAdjust && !this.isBorderBox()){
7912                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7913                 }
7914                 if(width < 0){
7915                     width = 0;
7916                 }
7917             }
7918             return width;
7919         },
7920
7921         // private
7922         adjustHeight : function(height){
7923             if(typeof height == "number"){
7924                if(this.autoBoxAdjust && !this.isBorderBox()){
7925                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7926                }
7927                if(height < 0){
7928                    height = 0;
7929                }
7930             }
7931             return height;
7932         },
7933
7934         /**
7935          * Set the width of the element
7936          * @param {Number} width The new width
7937          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7938          * @return {Roo.Element} this
7939          */
7940         setWidth : function(width, animate){
7941             width = this.adjustWidth(width);
7942             if(!animate || !A){
7943                 this.dom.style.width = this.addUnits(width);
7944             }else{
7945                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7946             }
7947             return this;
7948         },
7949
7950         /**
7951          * Set the height of the element
7952          * @param {Number} height The new height
7953          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7954          * @return {Roo.Element} this
7955          */
7956          setHeight : function(height, animate){
7957             height = this.adjustHeight(height);
7958             if(!animate || !A){
7959                 this.dom.style.height = this.addUnits(height);
7960             }else{
7961                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7962             }
7963             return this;
7964         },
7965
7966         /**
7967          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7968          * @param {Number} width The new width
7969          * @param {Number} height The new height
7970          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7971          * @return {Roo.Element} this
7972          */
7973          setSize : function(width, height, animate){
7974             if(typeof width == "object"){ // in case of object from getSize()
7975                 height = width.height; width = width.width;
7976             }
7977             width = this.adjustWidth(width); height = this.adjustHeight(height);
7978             if(!animate || !A){
7979                 this.dom.style.width = this.addUnits(width);
7980                 this.dom.style.height = this.addUnits(height);
7981             }else{
7982                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7983             }
7984             return this;
7985         },
7986
7987         /**
7988          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7989          * @param {Number} x X value for new position (coordinates are page-based)
7990          * @param {Number} y Y value for new position (coordinates are page-based)
7991          * @param {Number} width The new width
7992          * @param {Number} height The new height
7993          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7994          * @return {Roo.Element} this
7995          */
7996         setBounds : function(x, y, width, height, animate){
7997             if(!animate || !A){
7998                 this.setSize(width, height);
7999                 this.setLocation(x, y);
8000             }else{
8001                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8002                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8003                               this.preanim(arguments, 4), 'motion');
8004             }
8005             return this;
8006         },
8007
8008         /**
8009          * 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.
8010          * @param {Roo.lib.Region} region The region to fill
8011          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8012          * @return {Roo.Element} this
8013          */
8014         setRegion : function(region, animate){
8015             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8016             return this;
8017         },
8018
8019         /**
8020          * Appends an event handler
8021          *
8022          * @param {String}   eventName     The type of event to append
8023          * @param {Function} fn        The method the event invokes
8024          * @param {Object} scope       (optional) The scope (this object) of the fn
8025          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8026          */
8027         addListener : function(eventName, fn, scope, options){
8028             if (this.dom) {
8029                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8030             }
8031         },
8032
8033         /**
8034          * Removes an event handler from this element
8035          * @param {String} eventName the type of event to remove
8036          * @param {Function} fn the method the event invokes
8037          * @return {Roo.Element} this
8038          */
8039         removeListener : function(eventName, fn){
8040             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8041             return this;
8042         },
8043
8044         /**
8045          * Removes all previous added listeners from this element
8046          * @return {Roo.Element} this
8047          */
8048         removeAllListeners : function(){
8049             E.purgeElement(this.dom);
8050             return this;
8051         },
8052
8053         relayEvent : function(eventName, observable){
8054             this.on(eventName, function(e){
8055                 observable.fireEvent(eventName, e);
8056             });
8057         },
8058
8059         /**
8060          * Set the opacity of the element
8061          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8062          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8063          * @return {Roo.Element} this
8064          */
8065          setOpacity : function(opacity, animate){
8066             if(!animate || !A){
8067                 var s = this.dom.style;
8068                 if(Roo.isIE){
8069                     s.zoom = 1;
8070                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8071                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8072                 }else{
8073                     s.opacity = opacity;
8074                 }
8075             }else{
8076                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8077             }
8078             return this;
8079         },
8080
8081         /**
8082          * Gets the left X coordinate
8083          * @param {Boolean} local True to get the local css position instead of page coordinate
8084          * @return {Number}
8085          */
8086         getLeft : function(local){
8087             if(!local){
8088                 return this.getX();
8089             }else{
8090                 return parseInt(this.getStyle("left"), 10) || 0;
8091             }
8092         },
8093
8094         /**
8095          * Gets the right X coordinate of the element (element X position + element width)
8096          * @param {Boolean} local True to get the local css position instead of page coordinate
8097          * @return {Number}
8098          */
8099         getRight : function(local){
8100             if(!local){
8101                 return this.getX() + this.getWidth();
8102             }else{
8103                 return (this.getLeft(true) + this.getWidth()) || 0;
8104             }
8105         },
8106
8107         /**
8108          * Gets the top Y coordinate
8109          * @param {Boolean} local True to get the local css position instead of page coordinate
8110          * @return {Number}
8111          */
8112         getTop : function(local) {
8113             if(!local){
8114                 return this.getY();
8115             }else{
8116                 return parseInt(this.getStyle("top"), 10) || 0;
8117             }
8118         },
8119
8120         /**
8121          * Gets the bottom Y coordinate of the element (element Y position + element height)
8122          * @param {Boolean} local True to get the local css position instead of page coordinate
8123          * @return {Number}
8124          */
8125         getBottom : function(local){
8126             if(!local){
8127                 return this.getY() + this.getHeight();
8128             }else{
8129                 return (this.getTop(true) + this.getHeight()) || 0;
8130             }
8131         },
8132
8133         /**
8134         * Initializes positioning on this element. If a desired position is not passed, it will make the
8135         * the element positioned relative IF it is not already positioned.
8136         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8137         * @param {Number} zIndex (optional) The zIndex to apply
8138         * @param {Number} x (optional) Set the page X position
8139         * @param {Number} y (optional) Set the page Y position
8140         */
8141         position : function(pos, zIndex, x, y){
8142             if(!pos){
8143                if(this.getStyle('position') == 'static'){
8144                    this.setStyle('position', 'relative');
8145                }
8146             }else{
8147                 this.setStyle("position", pos);
8148             }
8149             if(zIndex){
8150                 this.setStyle("z-index", zIndex);
8151             }
8152             if(x !== undefined && y !== undefined){
8153                 this.setXY([x, y]);
8154             }else if(x !== undefined){
8155                 this.setX(x);
8156             }else if(y !== undefined){
8157                 this.setY(y);
8158             }
8159         },
8160
8161         /**
8162         * Clear positioning back to the default when the document was loaded
8163         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8164         * @return {Roo.Element} this
8165          */
8166         clearPositioning : function(value){
8167             value = value ||'';
8168             this.setStyle({
8169                 "left": value,
8170                 "right": value,
8171                 "top": value,
8172                 "bottom": value,
8173                 "z-index": "",
8174                 "position" : "static"
8175             });
8176             return this;
8177         },
8178
8179         /**
8180         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8181         * snapshot before performing an update and then restoring the element.
8182         * @return {Object}
8183         */
8184         getPositioning : function(){
8185             var l = this.getStyle("left");
8186             var t = this.getStyle("top");
8187             return {
8188                 "position" : this.getStyle("position"),
8189                 "left" : l,
8190                 "right" : l ? "" : this.getStyle("right"),
8191                 "top" : t,
8192                 "bottom" : t ? "" : this.getStyle("bottom"),
8193                 "z-index" : this.getStyle("z-index")
8194             };
8195         },
8196
8197         /**
8198          * Gets the width of the border(s) for the specified side(s)
8199          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8200          * passing lr would get the border (l)eft width + the border (r)ight width.
8201          * @return {Number} The width of the sides passed added together
8202          */
8203         getBorderWidth : function(side){
8204             return this.addStyles(side, El.borders);
8205         },
8206
8207         /**
8208          * Gets the width of the padding(s) for the specified side(s)
8209          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8210          * passing lr would get the padding (l)eft + the padding (r)ight.
8211          * @return {Number} The padding of the sides passed added together
8212          */
8213         getPadding : function(side){
8214             return this.addStyles(side, El.paddings);
8215         },
8216
8217         /**
8218         * Set positioning with an object returned by getPositioning().
8219         * @param {Object} posCfg
8220         * @return {Roo.Element} this
8221          */
8222         setPositioning : function(pc){
8223             this.applyStyles(pc);
8224             if(pc.right == "auto"){
8225                 this.dom.style.right = "";
8226             }
8227             if(pc.bottom == "auto"){
8228                 this.dom.style.bottom = "";
8229             }
8230             return this;
8231         },
8232
8233         // private
8234         fixDisplay : function(){
8235             if(this.getStyle("display") == "none"){
8236                 this.setStyle("visibility", "hidden");
8237                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8238                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8239                     this.setStyle("display", "block");
8240                 }
8241             }
8242         },
8243
8244         /**
8245          * Quick set left and top adding default units
8246          * @param {String} left The left CSS property value
8247          * @param {String} top The top CSS property value
8248          * @return {Roo.Element} this
8249          */
8250          setLeftTop : function(left, top){
8251             this.dom.style.left = this.addUnits(left);
8252             this.dom.style.top = this.addUnits(top);
8253             return this;
8254         },
8255
8256         /**
8257          * Move this element relative to its current position.
8258          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8259          * @param {Number} distance How far to move the element in pixels
8260          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8261          * @return {Roo.Element} this
8262          */
8263          move : function(direction, distance, animate){
8264             var xy = this.getXY();
8265             direction = direction.toLowerCase();
8266             switch(direction){
8267                 case "l":
8268                 case "left":
8269                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8270                     break;
8271                case "r":
8272                case "right":
8273                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8274                     break;
8275                case "t":
8276                case "top":
8277                case "up":
8278                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8279                     break;
8280                case "b":
8281                case "bottom":
8282                case "down":
8283                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8284                     break;
8285             }
8286             return this;
8287         },
8288
8289         /**
8290          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8291          * @return {Roo.Element} this
8292          */
8293         clip : function(){
8294             if(!this.isClipped){
8295                this.isClipped = true;
8296                this.originalClip = {
8297                    "o": this.getStyle("overflow"),
8298                    "x": this.getStyle("overflow-x"),
8299                    "y": this.getStyle("overflow-y")
8300                };
8301                this.setStyle("overflow", "hidden");
8302                this.setStyle("overflow-x", "hidden");
8303                this.setStyle("overflow-y", "hidden");
8304             }
8305             return this;
8306         },
8307
8308         /**
8309          *  Return clipping (overflow) to original clipping before clip() was called
8310          * @return {Roo.Element} this
8311          */
8312         unclip : function(){
8313             if(this.isClipped){
8314                 this.isClipped = false;
8315                 var o = this.originalClip;
8316                 if(o.o){this.setStyle("overflow", o.o);}
8317                 if(o.x){this.setStyle("overflow-x", o.x);}
8318                 if(o.y){this.setStyle("overflow-y", o.y);}
8319             }
8320             return this;
8321         },
8322
8323
8324         /**
8325          * Gets the x,y coordinates specified by the anchor position on the element.
8326          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8327          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8328          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8329          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8330          * @return {Array} [x, y] An array containing the element's x and y coordinates
8331          */
8332         getAnchorXY : function(anchor, local, s){
8333             //Passing a different size is useful for pre-calculating anchors,
8334             //especially for anchored animations that change the el size.
8335
8336             var w, h, vp = false;
8337             if(!s){
8338                 var d = this.dom;
8339                 if(d == document.body || d == document){
8340                     vp = true;
8341                     w = D.getViewWidth(); h = D.getViewHeight();
8342                 }else{
8343                     w = this.getWidth(); h = this.getHeight();
8344                 }
8345             }else{
8346                 w = s.width;  h = s.height;
8347             }
8348             var x = 0, y = 0, r = Math.round;
8349             switch((anchor || "tl").toLowerCase()){
8350                 case "c":
8351                     x = r(w*.5);
8352                     y = r(h*.5);
8353                 break;
8354                 case "t":
8355                     x = r(w*.5);
8356                     y = 0;
8357                 break;
8358                 case "l":
8359                     x = 0;
8360                     y = r(h*.5);
8361                 break;
8362                 case "r":
8363                     x = w;
8364                     y = r(h*.5);
8365                 break;
8366                 case "b":
8367                     x = r(w*.5);
8368                     y = h;
8369                 break;
8370                 case "tl":
8371                     x = 0;
8372                     y = 0;
8373                 break;
8374                 case "bl":
8375                     x = 0;
8376                     y = h;
8377                 break;
8378                 case "br":
8379                     x = w;
8380                     y = h;
8381                 break;
8382                 case "tr":
8383                     x = w;
8384                     y = 0;
8385                 break;
8386             }
8387             if(local === true){
8388                 return [x, y];
8389             }
8390             if(vp){
8391                 var sc = this.getScroll();
8392                 return [x + sc.left, y + sc.top];
8393             }
8394             //Add the element's offset xy
8395             var o = this.getXY();
8396             return [x+o[0], y+o[1]];
8397         },
8398
8399         /**
8400          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8401          * supported position values.
8402          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8403          * @param {String} position The position to align to.
8404          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8405          * @return {Array} [x, y]
8406          */
8407         getAlignToXY : function(el, p, o){
8408             el = Roo.get(el);
8409             var d = this.dom;
8410             if(!el.dom){
8411                 throw "Element.alignTo with an element that doesn't exist";
8412             }
8413             var c = false; //constrain to viewport
8414             var p1 = "", p2 = "";
8415             o = o || [0,0];
8416
8417             if(!p){
8418                 p = "tl-bl";
8419             }else if(p == "?"){
8420                 p = "tl-bl?";
8421             }else if(p.indexOf("-") == -1){
8422                 p = "tl-" + p;
8423             }
8424             p = p.toLowerCase();
8425             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8426             if(!m){
8427                throw "Element.alignTo with an invalid alignment " + p;
8428             }
8429             p1 = m[1]; p2 = m[2]; c = !!m[3];
8430
8431             //Subtract the aligned el's internal xy from the target's offset xy
8432             //plus custom offset to get the aligned el's new offset xy
8433             var a1 = this.getAnchorXY(p1, true);
8434             var a2 = el.getAnchorXY(p2, false);
8435             var x = a2[0] - a1[0] + o[0];
8436             var y = a2[1] - a1[1] + o[1];
8437             if(c){
8438                 //constrain the aligned el to viewport if necessary
8439                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8440                 // 5px of margin for ie
8441                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8442
8443                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8444                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8445                 //otherwise swap the aligned el to the opposite border of the target.
8446                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8447                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8448                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8449                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8450
8451                var doc = document;
8452                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8453                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8454
8455                if((x+w) > dw + scrollX){
8456                     x = swapX ? r.left-w : dw+scrollX-w;
8457                 }
8458                if(x < scrollX){
8459                    x = swapX ? r.right : scrollX;
8460                }
8461                if((y+h) > dh + scrollY){
8462                     y = swapY ? r.top-h : dh+scrollY-h;
8463                 }
8464                if (y < scrollY){
8465                    y = swapY ? r.bottom : scrollY;
8466                }
8467             }
8468             return [x,y];
8469         },
8470
8471         // private
8472         getConstrainToXY : function(){
8473             var os = {top:0, left:0, bottom:0, right: 0};
8474
8475             return function(el, local, offsets, proposedXY){
8476                 el = Roo.get(el);
8477                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8478
8479                 var vw, vh, vx = 0, vy = 0;
8480                 if(el.dom == document.body || el.dom == document){
8481                     vw = Roo.lib.Dom.getViewWidth();
8482                     vh = Roo.lib.Dom.getViewHeight();
8483                 }else{
8484                     vw = el.dom.clientWidth;
8485                     vh = el.dom.clientHeight;
8486                     if(!local){
8487                         var vxy = el.getXY();
8488                         vx = vxy[0];
8489                         vy = vxy[1];
8490                     }
8491                 }
8492
8493                 var s = el.getScroll();
8494
8495                 vx += offsets.left + s.left;
8496                 vy += offsets.top + s.top;
8497
8498                 vw -= offsets.right;
8499                 vh -= offsets.bottom;
8500
8501                 var vr = vx+vw;
8502                 var vb = vy+vh;
8503
8504                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8505                 var x = xy[0], y = xy[1];
8506                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8507
8508                 // only move it if it needs it
8509                 var moved = false;
8510
8511                 // first validate right/bottom
8512                 if((x + w) > vr){
8513                     x = vr - w;
8514                     moved = true;
8515                 }
8516                 if((y + h) > vb){
8517                     y = vb - h;
8518                     moved = true;
8519                 }
8520                 // then make sure top/left isn't negative
8521                 if(x < vx){
8522                     x = vx;
8523                     moved = true;
8524                 }
8525                 if(y < vy){
8526                     y = vy;
8527                     moved = true;
8528                 }
8529                 return moved ? [x, y] : false;
8530             };
8531         }(),
8532
8533         // private
8534         adjustForConstraints : function(xy, parent, offsets){
8535             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8536         },
8537
8538         /**
8539          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8540          * document it aligns it to the viewport.
8541          * The position parameter is optional, and can be specified in any one of the following formats:
8542          * <ul>
8543          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8544          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8545          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8546          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8547          *   <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
8548          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8549          * </ul>
8550          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8551          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8552          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8553          * that specified in order to enforce the viewport constraints.
8554          * Following are all of the supported anchor positions:
8555     <pre>
8556     Value  Description
8557     -----  -----------------------------
8558     tl     The top left corner (default)
8559     t      The center of the top edge
8560     tr     The top right corner
8561     l      The center of the left edge
8562     c      In the center of the element
8563     r      The center of the right edge
8564     bl     The bottom left corner
8565     b      The center of the bottom edge
8566     br     The bottom right corner
8567     </pre>
8568     Example Usage:
8569     <pre><code>
8570     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8571     el.alignTo("other-el");
8572
8573     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8574     el.alignTo("other-el", "tr?");
8575
8576     // align the bottom right corner of el with the center left edge of other-el
8577     el.alignTo("other-el", "br-l?");
8578
8579     // align the center of el with the bottom left corner of other-el and
8580     // adjust the x position by -6 pixels (and the y position by 0)
8581     el.alignTo("other-el", "c-bl", [-6, 0]);
8582     </code></pre>
8583          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8584          * @param {String} position The position to align to.
8585          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8586          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8587          * @return {Roo.Element} this
8588          */
8589         alignTo : function(element, position, offsets, animate){
8590             var xy = this.getAlignToXY(element, position, offsets);
8591             this.setXY(xy, this.preanim(arguments, 3));
8592             return this;
8593         },
8594
8595         /**
8596          * Anchors an element to another element and realigns it when the window is resized.
8597          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8598          * @param {String} position The position to align to.
8599          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8600          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8601          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8602          * is a number, it is used as the buffer delay (defaults to 50ms).
8603          * @param {Function} callback The function to call after the animation finishes
8604          * @return {Roo.Element} this
8605          */
8606         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8607             var action = function(){
8608                 this.alignTo(el, alignment, offsets, animate);
8609                 Roo.callback(callback, this);
8610             };
8611             Roo.EventManager.onWindowResize(action, this);
8612             var tm = typeof monitorScroll;
8613             if(tm != 'undefined'){
8614                 Roo.EventManager.on(window, 'scroll', action, this,
8615                     {buffer: tm == 'number' ? monitorScroll : 50});
8616             }
8617             action.call(this); // align immediately
8618             return this;
8619         },
8620         /**
8621          * Clears any opacity settings from this element. Required in some cases for IE.
8622          * @return {Roo.Element} this
8623          */
8624         clearOpacity : function(){
8625             if (window.ActiveXObject) {
8626                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8627                     this.dom.style.filter = "";
8628                 }
8629             } else {
8630                 this.dom.style.opacity = "";
8631                 this.dom.style["-moz-opacity"] = "";
8632                 this.dom.style["-khtml-opacity"] = "";
8633             }
8634             return this;
8635         },
8636
8637         /**
8638          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8639          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8640          * @return {Roo.Element} this
8641          */
8642         hide : function(animate){
8643             this.setVisible(false, this.preanim(arguments, 0));
8644             return this;
8645         },
8646
8647         /**
8648         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8649         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8650          * @return {Roo.Element} this
8651          */
8652         show : function(animate){
8653             this.setVisible(true, this.preanim(arguments, 0));
8654             return this;
8655         },
8656
8657         /**
8658          * @private Test if size has a unit, otherwise appends the default
8659          */
8660         addUnits : function(size){
8661             return Roo.Element.addUnits(size, this.defaultUnit);
8662         },
8663
8664         /**
8665          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8666          * @return {Roo.Element} this
8667          */
8668         beginMeasure : function(){
8669             var el = this.dom;
8670             if(el.offsetWidth || el.offsetHeight){
8671                 return this; // offsets work already
8672             }
8673             var changed = [];
8674             var p = this.dom, b = document.body; // start with this element
8675             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8676                 var pe = Roo.get(p);
8677                 if(pe.getStyle('display') == 'none'){
8678                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8679                     p.style.visibility = "hidden";
8680                     p.style.display = "block";
8681                 }
8682                 p = p.parentNode;
8683             }
8684             this._measureChanged = changed;
8685             return this;
8686
8687         },
8688
8689         /**
8690          * Restores displays to before beginMeasure was called
8691          * @return {Roo.Element} this
8692          */
8693         endMeasure : function(){
8694             var changed = this._measureChanged;
8695             if(changed){
8696                 for(var i = 0, len = changed.length; i < len; i++) {
8697                     var r = changed[i];
8698                     r.el.style.visibility = r.visibility;
8699                     r.el.style.display = "none";
8700                 }
8701                 this._measureChanged = null;
8702             }
8703             return this;
8704         },
8705
8706         /**
8707         * Update the innerHTML of this element, optionally searching for and processing scripts
8708         * @param {String} html The new HTML
8709         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8710         * @param {Function} callback For async script loading you can be noticed when the update completes
8711         * @return {Roo.Element} this
8712          */
8713         update : function(html, loadScripts, callback){
8714             if(typeof html == "undefined"){
8715                 html = "";
8716             }
8717             if(loadScripts !== true){
8718                 this.dom.innerHTML = html;
8719                 if(typeof callback == "function"){
8720                     callback();
8721                 }
8722                 return this;
8723             }
8724             var id = Roo.id();
8725             var dom = this.dom;
8726
8727             html += '<span id="' + id + '"></span>';
8728
8729             E.onAvailable(id, function(){
8730                 var hd = document.getElementsByTagName("head")[0];
8731                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8732                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8733                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8734
8735                 var match;
8736                 while(match = re.exec(html)){
8737                     var attrs = match[1];
8738                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8739                     if(srcMatch && srcMatch[2]){
8740                        var s = document.createElement("script");
8741                        s.src = srcMatch[2];
8742                        var typeMatch = attrs.match(typeRe);
8743                        if(typeMatch && typeMatch[2]){
8744                            s.type = typeMatch[2];
8745                        }
8746                        hd.appendChild(s);
8747                     }else if(match[2] && match[2].length > 0){
8748                         if(window.execScript) {
8749                            window.execScript(match[2]);
8750                         } else {
8751                             /**
8752                              * eval:var:id
8753                              * eval:var:dom
8754                              * eval:var:html
8755                              * 
8756                              */
8757                            window.eval(match[2]);
8758                         }
8759                     }
8760                 }
8761                 var el = document.getElementById(id);
8762                 if(el){el.parentNode.removeChild(el);}
8763                 if(typeof callback == "function"){
8764                     callback();
8765                 }
8766             });
8767             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8768             return this;
8769         },
8770
8771         /**
8772          * Direct access to the UpdateManager update() method (takes the same parameters).
8773          * @param {String/Function} url The url for this request or a function to call to get the url
8774          * @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}
8775          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8776          * @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.
8777          * @return {Roo.Element} this
8778          */
8779         load : function(){
8780             var um = this.getUpdateManager();
8781             um.update.apply(um, arguments);
8782             return this;
8783         },
8784
8785         /**
8786         * Gets this element's UpdateManager
8787         * @return {Roo.UpdateManager} The UpdateManager
8788         */
8789         getUpdateManager : function(){
8790             if(!this.updateManager){
8791                 this.updateManager = new Roo.UpdateManager(this);
8792             }
8793             return this.updateManager;
8794         },
8795
8796         /**
8797          * Disables text selection for this element (normalized across browsers)
8798          * @return {Roo.Element} this
8799          */
8800         unselectable : function(){
8801             this.dom.unselectable = "on";
8802             this.swallowEvent("selectstart", true);
8803             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8804             this.addClass("x-unselectable");
8805             return this;
8806         },
8807
8808         /**
8809         * Calculates the x, y to center this element on the screen
8810         * @return {Array} The x, y values [x, y]
8811         */
8812         getCenterXY : function(){
8813             return this.getAlignToXY(document, 'c-c');
8814         },
8815
8816         /**
8817         * Centers the Element in either the viewport, or another Element.
8818         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8819         */
8820         center : function(centerIn){
8821             this.alignTo(centerIn || document, 'c-c');
8822             return this;
8823         },
8824
8825         /**
8826          * Tests various css rules/browsers to determine if this element uses a border box
8827          * @return {Boolean}
8828          */
8829         isBorderBox : function(){
8830             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8831         },
8832
8833         /**
8834          * Return a box {x, y, width, height} that can be used to set another elements
8835          * size/location to match this element.
8836          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8837          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8838          * @return {Object} box An object in the format {x, y, width, height}
8839          */
8840         getBox : function(contentBox, local){
8841             var xy;
8842             if(!local){
8843                 xy = this.getXY();
8844             }else{
8845                 var left = parseInt(this.getStyle("left"), 10) || 0;
8846                 var top = parseInt(this.getStyle("top"), 10) || 0;
8847                 xy = [left, top];
8848             }
8849             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8850             if(!contentBox){
8851                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8852             }else{
8853                 var l = this.getBorderWidth("l")+this.getPadding("l");
8854                 var r = this.getBorderWidth("r")+this.getPadding("r");
8855                 var t = this.getBorderWidth("t")+this.getPadding("t");
8856                 var b = this.getBorderWidth("b")+this.getPadding("b");
8857                 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)};
8858             }
8859             bx.right = bx.x + bx.width;
8860             bx.bottom = bx.y + bx.height;
8861             return bx;
8862         },
8863
8864         /**
8865          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8866          for more information about the sides.
8867          * @param {String} sides
8868          * @return {Number}
8869          */
8870         getFrameWidth : function(sides, onlyContentBox){
8871             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8872         },
8873
8874         /**
8875          * 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.
8876          * @param {Object} box The box to fill {x, y, width, height}
8877          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8878          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8879          * @return {Roo.Element} this
8880          */
8881         setBox : function(box, adjust, animate){
8882             var w = box.width, h = box.height;
8883             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8884                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8885                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8886             }
8887             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8888             return this;
8889         },
8890
8891         /**
8892          * Forces the browser to repaint this element
8893          * @return {Roo.Element} this
8894          */
8895          repaint : function(){
8896             var dom = this.dom;
8897             this.addClass("x-repaint");
8898             setTimeout(function(){
8899                 Roo.get(dom).removeClass("x-repaint");
8900             }, 1);
8901             return this;
8902         },
8903
8904         /**
8905          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8906          * then it returns the calculated width of the sides (see getPadding)
8907          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8908          * @return {Object/Number}
8909          */
8910         getMargins : function(side){
8911             if(!side){
8912                 return {
8913                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8914                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8915                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8916                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8917                 };
8918             }else{
8919                 return this.addStyles(side, El.margins);
8920              }
8921         },
8922
8923         // private
8924         addStyles : function(sides, styles){
8925             var val = 0, v, w;
8926             for(var i = 0, len = sides.length; i < len; i++){
8927                 v = this.getStyle(styles[sides.charAt(i)]);
8928                 if(v){
8929                      w = parseInt(v, 10);
8930                      if(w){ val += w; }
8931                 }
8932             }
8933             return val;
8934         },
8935
8936         /**
8937          * Creates a proxy element of this element
8938          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8939          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8940          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8941          * @return {Roo.Element} The new proxy element
8942          */
8943         createProxy : function(config, renderTo, matchBox){
8944             if(renderTo){
8945                 renderTo = Roo.getDom(renderTo);
8946             }else{
8947                 renderTo = document.body;
8948             }
8949             config = typeof config == "object" ?
8950                 config : {tag : "div", cls: config};
8951             var proxy = Roo.DomHelper.append(renderTo, config, true);
8952             if(matchBox){
8953                proxy.setBox(this.getBox());
8954             }
8955             return proxy;
8956         },
8957
8958         /**
8959          * Puts a mask over this element to disable user interaction. Requires core.css.
8960          * This method can only be applied to elements which accept child nodes.
8961          * @param {String} msg (optional) A message to display in the mask
8962          * @param {String} msgCls (optional) A css class to apply to the msg element
8963          * @return {Element} The mask  element
8964          */
8965         mask : function(msg, msgCls)
8966         {
8967             if(this.getStyle("position") == "static"){
8968                 this.setStyle("position", "relative");
8969             }
8970             if(!this._mask){
8971                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8972             }
8973             this.addClass("x-masked");
8974             this._mask.setDisplayed(true);
8975             
8976             // we wander
8977             var z = 0;
8978             var dom = this.dom
8979             while (dom && dom.style) {
8980                 if (!isNaN(parseInt(dom.style.zIndex))) {
8981                     z = Math.max(z, parseInt(dom.style.zIndex));
8982                 }
8983                 dom = dom.parentNode;
8984             }
8985             // if we are masking the body - then it hides everything..
8986             if (this.dom == document.body) {
8987                 z = 1000000;
8988                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8989                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8990             }
8991            
8992             if(typeof msg == 'string'){
8993                 if(!this._maskMsg){
8994                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8995                 }
8996                 var mm = this._maskMsg;
8997                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8998                 mm.dom.firstChild.innerHTML = msg;
8999                 mm.setDisplayed(true);
9000                 mm.center(this);
9001                 mm.setStyle('z-index', z + 102);
9002             }
9003             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9004                 this._mask.setHeight(this.getHeight());
9005             }
9006             this._mask.setStyle('z-index', z + 100);
9007             
9008             return this._mask;
9009         },
9010
9011         /**
9012          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9013          * it is cached for reuse.
9014          */
9015         unmask : function(removeEl){
9016             if(this._mask){
9017                 if(removeEl === true){
9018                     this._mask.remove();
9019                     delete this._mask;
9020                     if(this._maskMsg){
9021                         this._maskMsg.remove();
9022                         delete this._maskMsg;
9023                     }
9024                 }else{
9025                     this._mask.setDisplayed(false);
9026                     if(this._maskMsg){
9027                         this._maskMsg.setDisplayed(false);
9028                     }
9029                 }
9030             }
9031             this.removeClass("x-masked");
9032         },
9033
9034         /**
9035          * Returns true if this element is masked
9036          * @return {Boolean}
9037          */
9038         isMasked : function(){
9039             return this._mask && this._mask.isVisible();
9040         },
9041
9042         /**
9043          * Creates an iframe shim for this element to keep selects and other windowed objects from
9044          * showing through.
9045          * @return {Roo.Element} The new shim element
9046          */
9047         createShim : function(){
9048             var el = document.createElement('iframe');
9049             el.frameBorder = 'no';
9050             el.className = 'roo-shim';
9051             if(Roo.isIE && Roo.isSecure){
9052                 el.src = Roo.SSL_SECURE_URL;
9053             }
9054             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9055             shim.autoBoxAdjust = false;
9056             return shim;
9057         },
9058
9059         /**
9060          * Removes this element from the DOM and deletes it from the cache
9061          */
9062         remove : function(){
9063             if(this.dom.parentNode){
9064                 this.dom.parentNode.removeChild(this.dom);
9065             }
9066             delete El.cache[this.dom.id];
9067         },
9068
9069         /**
9070          * Sets up event handlers to add and remove a css class when the mouse is over this element
9071          * @param {String} className
9072          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9073          * mouseout events for children elements
9074          * @return {Roo.Element} this
9075          */
9076         addClassOnOver : function(className, preventFlicker){
9077             this.on("mouseover", function(){
9078                 Roo.fly(this, '_internal').addClass(className);
9079             }, this.dom);
9080             var removeFn = function(e){
9081                 if(preventFlicker !== true || !e.within(this, true)){
9082                     Roo.fly(this, '_internal').removeClass(className);
9083                 }
9084             };
9085             this.on("mouseout", removeFn, this.dom);
9086             return this;
9087         },
9088
9089         /**
9090          * Sets up event handlers to add and remove a css class when this element has the focus
9091          * @param {String} className
9092          * @return {Roo.Element} this
9093          */
9094         addClassOnFocus : function(className){
9095             this.on("focus", function(){
9096                 Roo.fly(this, '_internal').addClass(className);
9097             }, this.dom);
9098             this.on("blur", function(){
9099                 Roo.fly(this, '_internal').removeClass(className);
9100             }, this.dom);
9101             return this;
9102         },
9103         /**
9104          * 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)
9105          * @param {String} className
9106          * @return {Roo.Element} this
9107          */
9108         addClassOnClick : function(className){
9109             var dom = this.dom;
9110             this.on("mousedown", function(){
9111                 Roo.fly(dom, '_internal').addClass(className);
9112                 var d = Roo.get(document);
9113                 var fn = function(){
9114                     Roo.fly(dom, '_internal').removeClass(className);
9115                     d.removeListener("mouseup", fn);
9116                 };
9117                 d.on("mouseup", fn);
9118             });
9119             return this;
9120         },
9121
9122         /**
9123          * Stops the specified event from bubbling and optionally prevents the default action
9124          * @param {String} eventName
9125          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9126          * @return {Roo.Element} this
9127          */
9128         swallowEvent : function(eventName, preventDefault){
9129             var fn = function(e){
9130                 e.stopPropagation();
9131                 if(preventDefault){
9132                     e.preventDefault();
9133                 }
9134             };
9135             if(eventName instanceof Array){
9136                 for(var i = 0, len = eventName.length; i < len; i++){
9137                      this.on(eventName[i], fn);
9138                 }
9139                 return this;
9140             }
9141             this.on(eventName, fn);
9142             return this;
9143         },
9144
9145         /**
9146          * @private
9147          */
9148       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9149
9150         /**
9151          * Sizes this element to its parent element's dimensions performing
9152          * neccessary box adjustments.
9153          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9154          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9155          * @return {Roo.Element} this
9156          */
9157         fitToParent : function(monitorResize, targetParent) {
9158           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9159           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9160           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9161             return;
9162           }
9163           var p = Roo.get(targetParent || this.dom.parentNode);
9164           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9165           if (monitorResize === true) {
9166             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9167             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9168           }
9169           return this;
9170         },
9171
9172         /**
9173          * Gets the next sibling, skipping text nodes
9174          * @return {HTMLElement} The next sibling or null
9175          */
9176         getNextSibling : function(){
9177             var n = this.dom.nextSibling;
9178             while(n && n.nodeType != 1){
9179                 n = n.nextSibling;
9180             }
9181             return n;
9182         },
9183
9184         /**
9185          * Gets the previous sibling, skipping text nodes
9186          * @return {HTMLElement} The previous sibling or null
9187          */
9188         getPrevSibling : function(){
9189             var n = this.dom.previousSibling;
9190             while(n && n.nodeType != 1){
9191                 n = n.previousSibling;
9192             }
9193             return n;
9194         },
9195
9196
9197         /**
9198          * Appends the passed element(s) to this element
9199          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9200          * @return {Roo.Element} this
9201          */
9202         appendChild: function(el){
9203             el = Roo.get(el);
9204             el.appendTo(this);
9205             return this;
9206         },
9207
9208         /**
9209          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9210          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9211          * automatically generated with the specified attributes.
9212          * @param {HTMLElement} insertBefore (optional) a child element of this element
9213          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9214          * @return {Roo.Element} The new child element
9215          */
9216         createChild: function(config, insertBefore, returnDom){
9217             config = config || {tag:'div'};
9218             if(insertBefore){
9219                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9220             }
9221             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9222         },
9223
9224         /**
9225          * Appends this element to the passed element
9226          * @param {String/HTMLElement/Element} el The new parent element
9227          * @return {Roo.Element} this
9228          */
9229         appendTo: function(el){
9230             el = Roo.getDom(el);
9231             el.appendChild(this.dom);
9232             return this;
9233         },
9234
9235         /**
9236          * Inserts this element before the passed element in the DOM
9237          * @param {String/HTMLElement/Element} el The element to insert before
9238          * @return {Roo.Element} this
9239          */
9240         insertBefore: function(el){
9241             el = Roo.getDom(el);
9242             el.parentNode.insertBefore(this.dom, el);
9243             return this;
9244         },
9245
9246         /**
9247          * Inserts this element after the passed element in the DOM
9248          * @param {String/HTMLElement/Element} el The element to insert after
9249          * @return {Roo.Element} this
9250          */
9251         insertAfter: function(el){
9252             el = Roo.getDom(el);
9253             el.parentNode.insertBefore(this.dom, el.nextSibling);
9254             return this;
9255         },
9256
9257         /**
9258          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9259          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9260          * @return {Roo.Element} The new child
9261          */
9262         insertFirst: function(el, returnDom){
9263             el = el || {};
9264             if(typeof el == 'object' && !el.nodeType){ // dh config
9265                 return this.createChild(el, this.dom.firstChild, returnDom);
9266             }else{
9267                 el = Roo.getDom(el);
9268                 this.dom.insertBefore(el, this.dom.firstChild);
9269                 return !returnDom ? Roo.get(el) : el;
9270             }
9271         },
9272
9273         /**
9274          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9275          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9276          * @param {String} where (optional) 'before' or 'after' defaults to before
9277          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9278          * @return {Roo.Element} the inserted Element
9279          */
9280         insertSibling: function(el, where, returnDom){
9281             where = where ? where.toLowerCase() : 'before';
9282             el = el || {};
9283             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9284
9285             if(typeof el == 'object' && !el.nodeType){ // dh config
9286                 if(where == 'after' && !this.dom.nextSibling){
9287                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9288                 }else{
9289                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9290                 }
9291
9292             }else{
9293                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9294                             where == 'before' ? this.dom : this.dom.nextSibling);
9295                 if(!returnDom){
9296                     rt = Roo.get(rt);
9297                 }
9298             }
9299             return rt;
9300         },
9301
9302         /**
9303          * Creates and wraps this element with another element
9304          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9305          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9306          * @return {HTMLElement/Element} The newly created wrapper element
9307          */
9308         wrap: function(config, returnDom){
9309             if(!config){
9310                 config = {tag: "div"};
9311             }
9312             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9313             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9314             return newEl;
9315         },
9316
9317         /**
9318          * Replaces the passed element with this element
9319          * @param {String/HTMLElement/Element} el The element to replace
9320          * @return {Roo.Element} this
9321          */
9322         replace: function(el){
9323             el = Roo.get(el);
9324             this.insertBefore(el);
9325             el.remove();
9326             return this;
9327         },
9328
9329         /**
9330          * Inserts an html fragment into this element
9331          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9332          * @param {String} html The HTML fragment
9333          * @param {Boolean} returnEl True to return an Roo.Element
9334          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9335          */
9336         insertHtml : function(where, html, returnEl){
9337             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9338             return returnEl ? Roo.get(el) : el;
9339         },
9340
9341         /**
9342          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9343          * @param {Object} o The object with the attributes
9344          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9345          * @return {Roo.Element} this
9346          */
9347         set : function(o, useSet){
9348             var el = this.dom;
9349             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9350             for(var attr in o){
9351                 if(attr == "style" || typeof o[attr] == "function") continue;
9352                 if(attr=="cls"){
9353                     el.className = o["cls"];
9354                 }else{
9355                     if(useSet) el.setAttribute(attr, o[attr]);
9356                     else el[attr] = o[attr];
9357                 }
9358             }
9359             if(o.style){
9360                 Roo.DomHelper.applyStyles(el, o.style);
9361             }
9362             return this;
9363         },
9364
9365         /**
9366          * Convenience method for constructing a KeyMap
9367          * @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:
9368          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9369          * @param {Function} fn The function to call
9370          * @param {Object} scope (optional) The scope of the function
9371          * @return {Roo.KeyMap} The KeyMap created
9372          */
9373         addKeyListener : function(key, fn, scope){
9374             var config;
9375             if(typeof key != "object" || key instanceof Array){
9376                 config = {
9377                     key: key,
9378                     fn: fn,
9379                     scope: scope
9380                 };
9381             }else{
9382                 config = {
9383                     key : key.key,
9384                     shift : key.shift,
9385                     ctrl : key.ctrl,
9386                     alt : key.alt,
9387                     fn: fn,
9388                     scope: scope
9389                 };
9390             }
9391             return new Roo.KeyMap(this, config);
9392         },
9393
9394         /**
9395          * Creates a KeyMap for this element
9396          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9397          * @return {Roo.KeyMap} The KeyMap created
9398          */
9399         addKeyMap : function(config){
9400             return new Roo.KeyMap(this, config);
9401         },
9402
9403         /**
9404          * Returns true if this element is scrollable.
9405          * @return {Boolean}
9406          */
9407          isScrollable : function(){
9408             var dom = this.dom;
9409             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9410         },
9411
9412         /**
9413          * 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().
9414          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9415          * @param {Number} value The new scroll value
9416          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9417          * @return {Element} this
9418          */
9419
9420         scrollTo : function(side, value, animate){
9421             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9422             if(!animate || !A){
9423                 this.dom[prop] = value;
9424             }else{
9425                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9426                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9427             }
9428             return this;
9429         },
9430
9431         /**
9432          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9433          * within this element's scrollable range.
9434          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9435          * @param {Number} distance How far to scroll the element in pixels
9436          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9437          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9438          * was scrolled as far as it could go.
9439          */
9440          scroll : function(direction, distance, animate){
9441              if(!this.isScrollable()){
9442                  return;
9443              }
9444              var el = this.dom;
9445              var l = el.scrollLeft, t = el.scrollTop;
9446              var w = el.scrollWidth, h = el.scrollHeight;
9447              var cw = el.clientWidth, ch = el.clientHeight;
9448              direction = direction.toLowerCase();
9449              var scrolled = false;
9450              var a = this.preanim(arguments, 2);
9451              switch(direction){
9452                  case "l":
9453                  case "left":
9454                      if(w - l > cw){
9455                          var v = Math.min(l + distance, w-cw);
9456                          this.scrollTo("left", v, a);
9457                          scrolled = true;
9458                      }
9459                      break;
9460                 case "r":
9461                 case "right":
9462                      if(l > 0){
9463                          var v = Math.max(l - distance, 0);
9464                          this.scrollTo("left", v, a);
9465                          scrolled = true;
9466                      }
9467                      break;
9468                 case "t":
9469                 case "top":
9470                 case "up":
9471                      if(t > 0){
9472                          var v = Math.max(t - distance, 0);
9473                          this.scrollTo("top", v, a);
9474                          scrolled = true;
9475                      }
9476                      break;
9477                 case "b":
9478                 case "bottom":
9479                 case "down":
9480                      if(h - t > ch){
9481                          var v = Math.min(t + distance, h-ch);
9482                          this.scrollTo("top", v, a);
9483                          scrolled = true;
9484                      }
9485                      break;
9486              }
9487              return scrolled;
9488         },
9489
9490         /**
9491          * Translates the passed page coordinates into left/top css values for this element
9492          * @param {Number/Array} x The page x or an array containing [x, y]
9493          * @param {Number} y The page y
9494          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9495          */
9496         translatePoints : function(x, y){
9497             if(typeof x == 'object' || x instanceof Array){
9498                 y = x[1]; x = x[0];
9499             }
9500             var p = this.getStyle('position');
9501             var o = this.getXY();
9502
9503             var l = parseInt(this.getStyle('left'), 10);
9504             var t = parseInt(this.getStyle('top'), 10);
9505
9506             if(isNaN(l)){
9507                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9508             }
9509             if(isNaN(t)){
9510                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9511             }
9512
9513             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9514         },
9515
9516         /**
9517          * Returns the current scroll position of the element.
9518          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9519          */
9520         getScroll : function(){
9521             var d = this.dom, doc = document;
9522             if(d == doc || d == doc.body){
9523                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9524                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9525                 return {left: l, top: t};
9526             }else{
9527                 return {left: d.scrollLeft, top: d.scrollTop};
9528             }
9529         },
9530
9531         /**
9532          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9533          * are convert to standard 6 digit hex color.
9534          * @param {String} attr The css attribute
9535          * @param {String} defaultValue The default value to use when a valid color isn't found
9536          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9537          * YUI color anims.
9538          */
9539         getColor : function(attr, defaultValue, prefix){
9540             var v = this.getStyle(attr);
9541             if(!v || v == "transparent" || v == "inherit") {
9542                 return defaultValue;
9543             }
9544             var color = typeof prefix == "undefined" ? "#" : prefix;
9545             if(v.substr(0, 4) == "rgb("){
9546                 var rvs = v.slice(4, v.length -1).split(",");
9547                 for(var i = 0; i < 3; i++){
9548                     var h = parseInt(rvs[i]).toString(16);
9549                     if(h < 16){
9550                         h = "0" + h;
9551                     }
9552                     color += h;
9553                 }
9554             } else {
9555                 if(v.substr(0, 1) == "#"){
9556                     if(v.length == 4) {
9557                         for(var i = 1; i < 4; i++){
9558                             var c = v.charAt(i);
9559                             color +=  c + c;
9560                         }
9561                     }else if(v.length == 7){
9562                         color += v.substr(1);
9563                     }
9564                 }
9565             }
9566             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9567         },
9568
9569         /**
9570          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9571          * gradient background, rounded corners and a 4-way shadow.
9572          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9573          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9574          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9575          * @return {Roo.Element} this
9576          */
9577         boxWrap : function(cls){
9578             cls = cls || 'x-box';
9579             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9580             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9581             return el;
9582         },
9583
9584         /**
9585          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9586          * @param {String} namespace The namespace in which to look for the attribute
9587          * @param {String} name The attribute name
9588          * @return {String} The attribute value
9589          */
9590         getAttributeNS : Roo.isIE ? function(ns, name){
9591             var d = this.dom;
9592             var type = typeof d[ns+":"+name];
9593             if(type != 'undefined' && type != 'unknown'){
9594                 return d[ns+":"+name];
9595             }
9596             return d[name];
9597         } : function(ns, name){
9598             var d = this.dom;
9599             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9600         },
9601         
9602         
9603         /**
9604          * Sets or Returns the value the dom attribute value
9605          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9606          * @param {String} value (optional) The value to set the attribute to
9607          * @return {String} The attribute value
9608          */
9609         attr : function(name){
9610             if (arguments.length > 1) {
9611                 this.dom.setAttribute(name, arguments[1]);
9612                 return arguments[1];
9613             }
9614             if (typeof(name) == 'object') {
9615                 for(var i in name) {
9616                     this.attr(i, name[i]);
9617                 }
9618                 return name;
9619             }
9620             
9621             
9622             if (!this.dom.hasAttribute(name)) {
9623                 return undefined;
9624             }
9625             return this.dom.getAttribute(name);
9626         }
9627         
9628         
9629         
9630     };
9631
9632     var ep = El.prototype;
9633
9634     /**
9635      * Appends an event handler (Shorthand for addListener)
9636      * @param {String}   eventName     The type of event to append
9637      * @param {Function} fn        The method the event invokes
9638      * @param {Object} scope       (optional) The scope (this object) of the fn
9639      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9640      * @method
9641      */
9642     ep.on = ep.addListener;
9643         // backwards compat
9644     ep.mon = ep.addListener;
9645
9646     /**
9647      * Removes an event handler from this element (shorthand for removeListener)
9648      * @param {String} eventName the type of event to remove
9649      * @param {Function} fn the method the event invokes
9650      * @return {Roo.Element} this
9651      * @method
9652      */
9653     ep.un = ep.removeListener;
9654
9655     /**
9656      * true to automatically adjust width and height settings for box-model issues (default to true)
9657      */
9658     ep.autoBoxAdjust = true;
9659
9660     // private
9661     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9662
9663     // private
9664     El.addUnits = function(v, defaultUnit){
9665         if(v === "" || v == "auto"){
9666             return v;
9667         }
9668         if(v === undefined){
9669             return '';
9670         }
9671         if(typeof v == "number" || !El.unitPattern.test(v)){
9672             return v + (defaultUnit || 'px');
9673         }
9674         return v;
9675     };
9676
9677     // special markup used throughout Roo when box wrapping elements
9678     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>';
9679     /**
9680      * Visibility mode constant - Use visibility to hide element
9681      * @static
9682      * @type Number
9683      */
9684     El.VISIBILITY = 1;
9685     /**
9686      * Visibility mode constant - Use display to hide element
9687      * @static
9688      * @type Number
9689      */
9690     El.DISPLAY = 2;
9691
9692     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9693     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9694     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9695
9696
9697
9698     /**
9699      * @private
9700      */
9701     El.cache = {};
9702
9703     var docEl;
9704
9705     /**
9706      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9707      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9708      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9709      * @return {Element} The Element object
9710      * @static
9711      */
9712     El.get = function(el){
9713         var ex, elm, id;
9714         if(!el){ return null; }
9715         if(typeof el == "string"){ // element id
9716             if(!(elm = document.getElementById(el))){
9717                 return null;
9718             }
9719             if(ex = El.cache[el]){
9720                 ex.dom = elm;
9721             }else{
9722                 ex = El.cache[el] = new El(elm);
9723             }
9724             return ex;
9725         }else if(el.tagName){ // dom element
9726             if(!(id = el.id)){
9727                 id = Roo.id(el);
9728             }
9729             if(ex = El.cache[id]){
9730                 ex.dom = el;
9731             }else{
9732                 ex = El.cache[id] = new El(el);
9733             }
9734             return ex;
9735         }else if(el instanceof El){
9736             if(el != docEl){
9737                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9738                                                               // catch case where it hasn't been appended
9739                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9740             }
9741             return el;
9742         }else if(el.isComposite){
9743             return el;
9744         }else if(el instanceof Array){
9745             return El.select(el);
9746         }else if(el == document){
9747             // create a bogus element object representing the document object
9748             if(!docEl){
9749                 var f = function(){};
9750                 f.prototype = El.prototype;
9751                 docEl = new f();
9752                 docEl.dom = document;
9753             }
9754             return docEl;
9755         }
9756         return null;
9757     };
9758
9759     // private
9760     El.uncache = function(el){
9761         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9762             if(a[i]){
9763                 delete El.cache[a[i].id || a[i]];
9764             }
9765         }
9766     };
9767
9768     // private
9769     // Garbage collection - uncache elements/purge listeners on orphaned elements
9770     // so we don't hold a reference and cause the browser to retain them
9771     El.garbageCollect = function(){
9772         if(!Roo.enableGarbageCollector){
9773             clearInterval(El.collectorThread);
9774             return;
9775         }
9776         for(var eid in El.cache){
9777             var el = El.cache[eid], d = el.dom;
9778             // -------------------------------------------------------
9779             // Determining what is garbage:
9780             // -------------------------------------------------------
9781             // !d
9782             // dom node is null, definitely garbage
9783             // -------------------------------------------------------
9784             // !d.parentNode
9785             // no parentNode == direct orphan, definitely garbage
9786             // -------------------------------------------------------
9787             // !d.offsetParent && !document.getElementById(eid)
9788             // display none elements have no offsetParent so we will
9789             // also try to look it up by it's id. However, check
9790             // offsetParent first so we don't do unneeded lookups.
9791             // This enables collection of elements that are not orphans
9792             // directly, but somewhere up the line they have an orphan
9793             // parent.
9794             // -------------------------------------------------------
9795             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9796                 delete El.cache[eid];
9797                 if(d && Roo.enableListenerCollection){
9798                     E.purgeElement(d);
9799                 }
9800             }
9801         }
9802     }
9803     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9804
9805
9806     // dom is optional
9807     El.Flyweight = function(dom){
9808         this.dom = dom;
9809     };
9810     El.Flyweight.prototype = El.prototype;
9811
9812     El._flyweights = {};
9813     /**
9814      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9815      * the dom node can be overwritten by other code.
9816      * @param {String/HTMLElement} el The dom node or id
9817      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9818      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9819      * @static
9820      * @return {Element} The shared Element object
9821      */
9822     El.fly = function(el, named){
9823         named = named || '_global';
9824         el = Roo.getDom(el);
9825         if(!el){
9826             return null;
9827         }
9828         if(!El._flyweights[named]){
9829             El._flyweights[named] = new El.Flyweight();
9830         }
9831         El._flyweights[named].dom = el;
9832         return El._flyweights[named];
9833     };
9834
9835     /**
9836      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9837      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9838      * Shorthand of {@link Roo.Element#get}
9839      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9840      * @return {Element} The Element object
9841      * @member Roo
9842      * @method get
9843      */
9844     Roo.get = El.get;
9845     /**
9846      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9847      * the dom node can be overwritten by other code.
9848      * Shorthand of {@link Roo.Element#fly}
9849      * @param {String/HTMLElement} el The dom node or id
9850      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9851      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9852      * @static
9853      * @return {Element} The shared Element object
9854      * @member Roo
9855      * @method fly
9856      */
9857     Roo.fly = El.fly;
9858
9859     // speedy lookup for elements never to box adjust
9860     var noBoxAdjust = Roo.isStrict ? {
9861         select:1
9862     } : {
9863         input:1, select:1, textarea:1
9864     };
9865     if(Roo.isIE || Roo.isGecko){
9866         noBoxAdjust['button'] = 1;
9867     }
9868
9869
9870     Roo.EventManager.on(window, 'unload', function(){
9871         delete El.cache;
9872         delete El._flyweights;
9873     });
9874 })();
9875
9876
9877
9878
9879 if(Roo.DomQuery){
9880     Roo.Element.selectorFunction = Roo.DomQuery.select;
9881 }
9882
9883 Roo.Element.select = function(selector, unique, root){
9884     var els;
9885     if(typeof selector == "string"){
9886         els = Roo.Element.selectorFunction(selector, root);
9887     }else if(selector.length !== undefined){
9888         els = selector;
9889     }else{
9890         throw "Invalid selector";
9891     }
9892     if(unique === true){
9893         return new Roo.CompositeElement(els);
9894     }else{
9895         return new Roo.CompositeElementLite(els);
9896     }
9897 };
9898 /**
9899  * Selects elements based on the passed CSS selector to enable working on them as 1.
9900  * @param {String/Array} selector The CSS selector or an array of elements
9901  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9902  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9903  * @return {CompositeElementLite/CompositeElement}
9904  * @member Roo
9905  * @method select
9906  */
9907 Roo.select = Roo.Element.select;
9908
9909
9910
9911
9912
9913
9914
9915
9916
9917
9918
9919
9920
9921
9922 /*
9923  * Based on:
9924  * Ext JS Library 1.1.1
9925  * Copyright(c) 2006-2007, Ext JS, LLC.
9926  *
9927  * Originally Released Under LGPL - original licence link has changed is not relivant.
9928  *
9929  * Fork - LGPL
9930  * <script type="text/javascript">
9931  */
9932
9933
9934
9935 //Notifies Element that fx methods are available
9936 Roo.enableFx = true;
9937
9938 /**
9939  * @class Roo.Fx
9940  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9941  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9942  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9943  * Element effects to work.</p><br/>
9944  *
9945  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9946  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9947  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9948  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9949  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9950  * expected results and should be done with care.</p><br/>
9951  *
9952  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9953  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9954 <pre>
9955 Value  Description
9956 -----  -----------------------------
9957 tl     The top left corner
9958 t      The center of the top edge
9959 tr     The top right corner
9960 l      The center of the left edge
9961 r      The center of the right edge
9962 bl     The bottom left corner
9963 b      The center of the bottom edge
9964 br     The bottom right corner
9965 </pre>
9966  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9967  * below are common options that can be passed to any Fx method.</b>
9968  * @cfg {Function} callback A function called when the effect is finished
9969  * @cfg {Object} scope The scope of the effect function
9970  * @cfg {String} easing A valid Easing value for the effect
9971  * @cfg {String} afterCls A css class to apply after the effect
9972  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9973  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9974  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9975  * effects that end with the element being visually hidden, ignored otherwise)
9976  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9977  * a function which returns such a specification that will be applied to the Element after the effect finishes
9978  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9979  * @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
9980  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9981  */
9982 Roo.Fx = {
9983         /**
9984          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9985          * origin for the slide effect.  This function automatically handles wrapping the element with
9986          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9987          * Usage:
9988          *<pre><code>
9989 // default: slide the element in from the top
9990 el.slideIn();
9991
9992 // custom: slide the element in from the right with a 2-second duration
9993 el.slideIn('r', { duration: 2 });
9994
9995 // common config options shown with default values
9996 el.slideIn('t', {
9997     easing: 'easeOut',
9998     duration: .5
9999 });
10000 </code></pre>
10001          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10002          * @param {Object} options (optional) Object literal with any of the Fx config options
10003          * @return {Roo.Element} The Element
10004          */
10005     slideIn : function(anchor, o){
10006         var el = this.getFxEl();
10007         o = o || {};
10008
10009         el.queueFx(o, function(){
10010
10011             anchor = anchor || "t";
10012
10013             // fix display to visibility
10014             this.fixDisplay();
10015
10016             // restore values after effect
10017             var r = this.getFxRestore();
10018             var b = this.getBox();
10019             // fixed size for slide
10020             this.setSize(b);
10021
10022             // wrap if needed
10023             var wrap = this.fxWrap(r.pos, o, "hidden");
10024
10025             var st = this.dom.style;
10026             st.visibility = "visible";
10027             st.position = "absolute";
10028
10029             // clear out temp styles after slide and unwrap
10030             var after = function(){
10031                 el.fxUnwrap(wrap, r.pos, o);
10032                 st.width = r.width;
10033                 st.height = r.height;
10034                 el.afterFx(o);
10035             };
10036             // time to calc the positions
10037             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10038
10039             switch(anchor.toLowerCase()){
10040                 case "t":
10041                     wrap.setSize(b.width, 0);
10042                     st.left = st.bottom = "0";
10043                     a = {height: bh};
10044                 break;
10045                 case "l":
10046                     wrap.setSize(0, b.height);
10047                     st.right = st.top = "0";
10048                     a = {width: bw};
10049                 break;
10050                 case "r":
10051                     wrap.setSize(0, b.height);
10052                     wrap.setX(b.right);
10053                     st.left = st.top = "0";
10054                     a = {width: bw, points: pt};
10055                 break;
10056                 case "b":
10057                     wrap.setSize(b.width, 0);
10058                     wrap.setY(b.bottom);
10059                     st.left = st.top = "0";
10060                     a = {height: bh, points: pt};
10061                 break;
10062                 case "tl":
10063                     wrap.setSize(0, 0);
10064                     st.right = st.bottom = "0";
10065                     a = {width: bw, height: bh};
10066                 break;
10067                 case "bl":
10068                     wrap.setSize(0, 0);
10069                     wrap.setY(b.y+b.height);
10070                     st.right = st.top = "0";
10071                     a = {width: bw, height: bh, points: pt};
10072                 break;
10073                 case "br":
10074                     wrap.setSize(0, 0);
10075                     wrap.setXY([b.right, b.bottom]);
10076                     st.left = st.top = "0";
10077                     a = {width: bw, height: bh, points: pt};
10078                 break;
10079                 case "tr":
10080                     wrap.setSize(0, 0);
10081                     wrap.setX(b.x+b.width);
10082                     st.left = st.bottom = "0";
10083                     a = {width: bw, height: bh, points: pt};
10084                 break;
10085             }
10086             this.dom.style.visibility = "visible";
10087             wrap.show();
10088
10089             arguments.callee.anim = wrap.fxanim(a,
10090                 o,
10091                 'motion',
10092                 .5,
10093                 'easeOut', after);
10094         });
10095         return this;
10096     },
10097     
10098         /**
10099          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10100          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10101          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10102          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10103          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10104          * Usage:
10105          *<pre><code>
10106 // default: slide the element out to the top
10107 el.slideOut();
10108
10109 // custom: slide the element out to the right with a 2-second duration
10110 el.slideOut('r', { duration: 2 });
10111
10112 // common config options shown with default values
10113 el.slideOut('t', {
10114     easing: 'easeOut',
10115     duration: .5,
10116     remove: false,
10117     useDisplay: false
10118 });
10119 </code></pre>
10120          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10121          * @param {Object} options (optional) Object literal with any of the Fx config options
10122          * @return {Roo.Element} The Element
10123          */
10124     slideOut : function(anchor, o){
10125         var el = this.getFxEl();
10126         o = o || {};
10127
10128         el.queueFx(o, function(){
10129
10130             anchor = anchor || "t";
10131
10132             // restore values after effect
10133             var r = this.getFxRestore();
10134             
10135             var b = this.getBox();
10136             // fixed size for slide
10137             this.setSize(b);
10138
10139             // wrap if needed
10140             var wrap = this.fxWrap(r.pos, o, "visible");
10141
10142             var st = this.dom.style;
10143             st.visibility = "visible";
10144             st.position = "absolute";
10145
10146             wrap.setSize(b);
10147
10148             var after = function(){
10149                 if(o.useDisplay){
10150                     el.setDisplayed(false);
10151                 }else{
10152                     el.hide();
10153                 }
10154
10155                 el.fxUnwrap(wrap, r.pos, o);
10156
10157                 st.width = r.width;
10158                 st.height = r.height;
10159
10160                 el.afterFx(o);
10161             };
10162
10163             var a, zero = {to: 0};
10164             switch(anchor.toLowerCase()){
10165                 case "t":
10166                     st.left = st.bottom = "0";
10167                     a = {height: zero};
10168                 break;
10169                 case "l":
10170                     st.right = st.top = "0";
10171                     a = {width: zero};
10172                 break;
10173                 case "r":
10174                     st.left = st.top = "0";
10175                     a = {width: zero, points: {to:[b.right, b.y]}};
10176                 break;
10177                 case "b":
10178                     st.left = st.top = "0";
10179                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10180                 break;
10181                 case "tl":
10182                     st.right = st.bottom = "0";
10183                     a = {width: zero, height: zero};
10184                 break;
10185                 case "bl":
10186                     st.right = st.top = "0";
10187                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10188                 break;
10189                 case "br":
10190                     st.left = st.top = "0";
10191                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10192                 break;
10193                 case "tr":
10194                     st.left = st.bottom = "0";
10195                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10196                 break;
10197             }
10198
10199             arguments.callee.anim = wrap.fxanim(a,
10200                 o,
10201                 'motion',
10202                 .5,
10203                 "easeOut", after);
10204         });
10205         return this;
10206     },
10207
10208         /**
10209          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10210          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10211          * The element must be removed from the DOM using the 'remove' config option if desired.
10212          * Usage:
10213          *<pre><code>
10214 // default
10215 el.puff();
10216
10217 // common config options shown with default values
10218 el.puff({
10219     easing: 'easeOut',
10220     duration: .5,
10221     remove: false,
10222     useDisplay: false
10223 });
10224 </code></pre>
10225          * @param {Object} options (optional) Object literal with any of the Fx config options
10226          * @return {Roo.Element} The Element
10227          */
10228     puff : function(o){
10229         var el = this.getFxEl();
10230         o = o || {};
10231
10232         el.queueFx(o, function(){
10233             this.clearOpacity();
10234             this.show();
10235
10236             // restore values after effect
10237             var r = this.getFxRestore();
10238             var st = this.dom.style;
10239
10240             var after = function(){
10241                 if(o.useDisplay){
10242                     el.setDisplayed(false);
10243                 }else{
10244                     el.hide();
10245                 }
10246
10247                 el.clearOpacity();
10248
10249                 el.setPositioning(r.pos);
10250                 st.width = r.width;
10251                 st.height = r.height;
10252                 st.fontSize = '';
10253                 el.afterFx(o);
10254             };
10255
10256             var width = this.getWidth();
10257             var height = this.getHeight();
10258
10259             arguments.callee.anim = this.fxanim({
10260                     width : {to: this.adjustWidth(width * 2)},
10261                     height : {to: this.adjustHeight(height * 2)},
10262                     points : {by: [-(width * .5), -(height * .5)]},
10263                     opacity : {to: 0},
10264                     fontSize: {to:200, unit: "%"}
10265                 },
10266                 o,
10267                 'motion',
10268                 .5,
10269                 "easeOut", after);
10270         });
10271         return this;
10272     },
10273
10274         /**
10275          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10276          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10277          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10278          * Usage:
10279          *<pre><code>
10280 // default
10281 el.switchOff();
10282
10283 // all config options shown with default values
10284 el.switchOff({
10285     easing: 'easeIn',
10286     duration: .3,
10287     remove: false,
10288     useDisplay: false
10289 });
10290 </code></pre>
10291          * @param {Object} options (optional) Object literal with any of the Fx config options
10292          * @return {Roo.Element} The Element
10293          */
10294     switchOff : function(o){
10295         var el = this.getFxEl();
10296         o = o || {};
10297
10298         el.queueFx(o, function(){
10299             this.clearOpacity();
10300             this.clip();
10301
10302             // restore values after effect
10303             var r = this.getFxRestore();
10304             var st = this.dom.style;
10305
10306             var after = function(){
10307                 if(o.useDisplay){
10308                     el.setDisplayed(false);
10309                 }else{
10310                     el.hide();
10311                 }
10312
10313                 el.clearOpacity();
10314                 el.setPositioning(r.pos);
10315                 st.width = r.width;
10316                 st.height = r.height;
10317
10318                 el.afterFx(o);
10319             };
10320
10321             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10322                 this.clearOpacity();
10323                 (function(){
10324                     this.fxanim({
10325                         height:{to:1},
10326                         points:{by:[0, this.getHeight() * .5]}
10327                     }, o, 'motion', 0.3, 'easeIn', after);
10328                 }).defer(100, this);
10329             });
10330         });
10331         return this;
10332     },
10333
10334     /**
10335      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10336      * changed using the "attr" config option) and then fading back to the original color. If no original
10337      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10338      * Usage:
10339 <pre><code>
10340 // default: highlight background to yellow
10341 el.highlight();
10342
10343 // custom: highlight foreground text to blue for 2 seconds
10344 el.highlight("0000ff", { attr: 'color', duration: 2 });
10345
10346 // common config options shown with default values
10347 el.highlight("ffff9c", {
10348     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10349     endColor: (current color) or "ffffff",
10350     easing: 'easeIn',
10351     duration: 1
10352 });
10353 </code></pre>
10354      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10355      * @param {Object} options (optional) Object literal with any of the Fx config options
10356      * @return {Roo.Element} The Element
10357      */ 
10358     highlight : function(color, o){
10359         var el = this.getFxEl();
10360         o = o || {};
10361
10362         el.queueFx(o, function(){
10363             color = color || "ffff9c";
10364             attr = o.attr || "backgroundColor";
10365
10366             this.clearOpacity();
10367             this.show();
10368
10369             var origColor = this.getColor(attr);
10370             var restoreColor = this.dom.style[attr];
10371             endColor = (o.endColor || origColor) || "ffffff";
10372
10373             var after = function(){
10374                 el.dom.style[attr] = restoreColor;
10375                 el.afterFx(o);
10376             };
10377
10378             var a = {};
10379             a[attr] = {from: color, to: endColor};
10380             arguments.callee.anim = this.fxanim(a,
10381                 o,
10382                 'color',
10383                 1,
10384                 'easeIn', after);
10385         });
10386         return this;
10387     },
10388
10389    /**
10390     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10391     * Usage:
10392 <pre><code>
10393 // default: a single light blue ripple
10394 el.frame();
10395
10396 // custom: 3 red ripples lasting 3 seconds total
10397 el.frame("ff0000", 3, { duration: 3 });
10398
10399 // common config options shown with default values
10400 el.frame("C3DAF9", 1, {
10401     duration: 1 //duration of entire animation (not each individual ripple)
10402     // Note: Easing is not configurable and will be ignored if included
10403 });
10404 </code></pre>
10405     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10406     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10407     * @param {Object} options (optional) Object literal with any of the Fx config options
10408     * @return {Roo.Element} The Element
10409     */
10410     frame : function(color, count, o){
10411         var el = this.getFxEl();
10412         o = o || {};
10413
10414         el.queueFx(o, function(){
10415             color = color || "#C3DAF9";
10416             if(color.length == 6){
10417                 color = "#" + color;
10418             }
10419             count = count || 1;
10420             duration = o.duration || 1;
10421             this.show();
10422
10423             var b = this.getBox();
10424             var animFn = function(){
10425                 var proxy = this.createProxy({
10426
10427                      style:{
10428                         visbility:"hidden",
10429                         position:"absolute",
10430                         "z-index":"35000", // yee haw
10431                         border:"0px solid " + color
10432                      }
10433                   });
10434                 var scale = Roo.isBorderBox ? 2 : 1;
10435                 proxy.animate({
10436                     top:{from:b.y, to:b.y - 20},
10437                     left:{from:b.x, to:b.x - 20},
10438                     borderWidth:{from:0, to:10},
10439                     opacity:{from:1, to:0},
10440                     height:{from:b.height, to:(b.height + (20*scale))},
10441                     width:{from:b.width, to:(b.width + (20*scale))}
10442                 }, duration, function(){
10443                     proxy.remove();
10444                 });
10445                 if(--count > 0){
10446                      animFn.defer((duration/2)*1000, this);
10447                 }else{
10448                     el.afterFx(o);
10449                 }
10450             };
10451             animFn.call(this);
10452         });
10453         return this;
10454     },
10455
10456    /**
10457     * Creates a pause before any subsequent queued effects begin.  If there are
10458     * no effects queued after the pause it will have no effect.
10459     * Usage:
10460 <pre><code>
10461 el.pause(1);
10462 </code></pre>
10463     * @param {Number} seconds The length of time to pause (in seconds)
10464     * @return {Roo.Element} The Element
10465     */
10466     pause : function(seconds){
10467         var el = this.getFxEl();
10468         var o = {};
10469
10470         el.queueFx(o, function(){
10471             setTimeout(function(){
10472                 el.afterFx(o);
10473             }, seconds * 1000);
10474         });
10475         return this;
10476     },
10477
10478    /**
10479     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10480     * using the "endOpacity" config option.
10481     * Usage:
10482 <pre><code>
10483 // default: fade in from opacity 0 to 100%
10484 el.fadeIn();
10485
10486 // custom: fade in from opacity 0 to 75% over 2 seconds
10487 el.fadeIn({ endOpacity: .75, duration: 2});
10488
10489 // common config options shown with default values
10490 el.fadeIn({
10491     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10492     easing: 'easeOut',
10493     duration: .5
10494 });
10495 </code></pre>
10496     * @param {Object} options (optional) Object literal with any of the Fx config options
10497     * @return {Roo.Element} The Element
10498     */
10499     fadeIn : function(o){
10500         var el = this.getFxEl();
10501         o = o || {};
10502         el.queueFx(o, function(){
10503             this.setOpacity(0);
10504             this.fixDisplay();
10505             this.dom.style.visibility = 'visible';
10506             var to = o.endOpacity || 1;
10507             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10508                 o, null, .5, "easeOut", function(){
10509                 if(to == 1){
10510                     this.clearOpacity();
10511                 }
10512                 el.afterFx(o);
10513             });
10514         });
10515         return this;
10516     },
10517
10518    /**
10519     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10520     * using the "endOpacity" config option.
10521     * Usage:
10522 <pre><code>
10523 // default: fade out from the element's current opacity to 0
10524 el.fadeOut();
10525
10526 // custom: fade out from the element's current opacity to 25% over 2 seconds
10527 el.fadeOut({ endOpacity: .25, duration: 2});
10528
10529 // common config options shown with default values
10530 el.fadeOut({
10531     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10532     easing: 'easeOut',
10533     duration: .5
10534     remove: false,
10535     useDisplay: false
10536 });
10537 </code></pre>
10538     * @param {Object} options (optional) Object literal with any of the Fx config options
10539     * @return {Roo.Element} The Element
10540     */
10541     fadeOut : function(o){
10542         var el = this.getFxEl();
10543         o = o || {};
10544         el.queueFx(o, function(){
10545             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10546                 o, null, .5, "easeOut", function(){
10547                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10548                      this.dom.style.display = "none";
10549                 }else{
10550                      this.dom.style.visibility = "hidden";
10551                 }
10552                 this.clearOpacity();
10553                 el.afterFx(o);
10554             });
10555         });
10556         return this;
10557     },
10558
10559    /**
10560     * Animates the transition of an element's dimensions from a starting height/width
10561     * to an ending height/width.
10562     * Usage:
10563 <pre><code>
10564 // change height and width to 100x100 pixels
10565 el.scale(100, 100);
10566
10567 // common config options shown with default values.  The height and width will default to
10568 // the element's existing values if passed as null.
10569 el.scale(
10570     [element's width],
10571     [element's height], {
10572     easing: 'easeOut',
10573     duration: .35
10574 });
10575 </code></pre>
10576     * @param {Number} width  The new width (pass undefined to keep the original width)
10577     * @param {Number} height  The new height (pass undefined to keep the original height)
10578     * @param {Object} options (optional) Object literal with any of the Fx config options
10579     * @return {Roo.Element} The Element
10580     */
10581     scale : function(w, h, o){
10582         this.shift(Roo.apply({}, o, {
10583             width: w,
10584             height: h
10585         }));
10586         return this;
10587     },
10588
10589    /**
10590     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10591     * Any of these properties not specified in the config object will not be changed.  This effect 
10592     * requires that at least one new dimension, position or opacity setting must be passed in on
10593     * the config object in order for the function to have any effect.
10594     * Usage:
10595 <pre><code>
10596 // slide the element horizontally to x position 200 while changing the height and opacity
10597 el.shift({ x: 200, height: 50, opacity: .8 });
10598
10599 // common config options shown with default values.
10600 el.shift({
10601     width: [element's width],
10602     height: [element's height],
10603     x: [element's x position],
10604     y: [element's y position],
10605     opacity: [element's opacity],
10606     easing: 'easeOut',
10607     duration: .35
10608 });
10609 </code></pre>
10610     * @param {Object} options  Object literal with any of the Fx config options
10611     * @return {Roo.Element} The Element
10612     */
10613     shift : function(o){
10614         var el = this.getFxEl();
10615         o = o || {};
10616         el.queueFx(o, function(){
10617             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10618             if(w !== undefined){
10619                 a.width = {to: this.adjustWidth(w)};
10620             }
10621             if(h !== undefined){
10622                 a.height = {to: this.adjustHeight(h)};
10623             }
10624             if(x !== undefined || y !== undefined){
10625                 a.points = {to: [
10626                     x !== undefined ? x : this.getX(),
10627                     y !== undefined ? y : this.getY()
10628                 ]};
10629             }
10630             if(op !== undefined){
10631                 a.opacity = {to: op};
10632             }
10633             if(o.xy !== undefined){
10634                 a.points = {to: o.xy};
10635             }
10636             arguments.callee.anim = this.fxanim(a,
10637                 o, 'motion', .35, "easeOut", function(){
10638                 el.afterFx(o);
10639             });
10640         });
10641         return this;
10642     },
10643
10644         /**
10645          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10646          * ending point of the effect.
10647          * Usage:
10648          *<pre><code>
10649 // default: slide the element downward while fading out
10650 el.ghost();
10651
10652 // custom: slide the element out to the right with a 2-second duration
10653 el.ghost('r', { duration: 2 });
10654
10655 // common config options shown with default values
10656 el.ghost('b', {
10657     easing: 'easeOut',
10658     duration: .5
10659     remove: false,
10660     useDisplay: false
10661 });
10662 </code></pre>
10663          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10664          * @param {Object} options (optional) Object literal with any of the Fx config options
10665          * @return {Roo.Element} The Element
10666          */
10667     ghost : function(anchor, o){
10668         var el = this.getFxEl();
10669         o = o || {};
10670
10671         el.queueFx(o, function(){
10672             anchor = anchor || "b";
10673
10674             // restore values after effect
10675             var r = this.getFxRestore();
10676             var w = this.getWidth(),
10677                 h = this.getHeight();
10678
10679             var st = this.dom.style;
10680
10681             var after = function(){
10682                 if(o.useDisplay){
10683                     el.setDisplayed(false);
10684                 }else{
10685                     el.hide();
10686                 }
10687
10688                 el.clearOpacity();
10689                 el.setPositioning(r.pos);
10690                 st.width = r.width;
10691                 st.height = r.height;
10692
10693                 el.afterFx(o);
10694             };
10695
10696             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10697             switch(anchor.toLowerCase()){
10698                 case "t":
10699                     pt.by = [0, -h];
10700                 break;
10701                 case "l":
10702                     pt.by = [-w, 0];
10703                 break;
10704                 case "r":
10705                     pt.by = [w, 0];
10706                 break;
10707                 case "b":
10708                     pt.by = [0, h];
10709                 break;
10710                 case "tl":
10711                     pt.by = [-w, -h];
10712                 break;
10713                 case "bl":
10714                     pt.by = [-w, h];
10715                 break;
10716                 case "br":
10717                     pt.by = [w, h];
10718                 break;
10719                 case "tr":
10720                     pt.by = [w, -h];
10721                 break;
10722             }
10723
10724             arguments.callee.anim = this.fxanim(a,
10725                 o,
10726                 'motion',
10727                 .5,
10728                 "easeOut", after);
10729         });
10730         return this;
10731     },
10732
10733         /**
10734          * Ensures that all effects queued after syncFx is called on the element are
10735          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10736          * @return {Roo.Element} The Element
10737          */
10738     syncFx : function(){
10739         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10740             block : false,
10741             concurrent : true,
10742             stopFx : false
10743         });
10744         return this;
10745     },
10746
10747         /**
10748          * Ensures that all effects queued after sequenceFx is called on the element are
10749          * run in sequence.  This is the opposite of {@link #syncFx}.
10750          * @return {Roo.Element} The Element
10751          */
10752     sequenceFx : function(){
10753         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10754             block : false,
10755             concurrent : false,
10756             stopFx : false
10757         });
10758         return this;
10759     },
10760
10761         /* @private */
10762     nextFx : function(){
10763         var ef = this.fxQueue[0];
10764         if(ef){
10765             ef.call(this);
10766         }
10767     },
10768
10769         /**
10770          * Returns true if the element has any effects actively running or queued, else returns false.
10771          * @return {Boolean} True if element has active effects, else false
10772          */
10773     hasActiveFx : function(){
10774         return this.fxQueue && this.fxQueue[0];
10775     },
10776
10777         /**
10778          * Stops any running effects and clears the element's internal effects queue if it contains
10779          * any additional effects that haven't started yet.
10780          * @return {Roo.Element} The Element
10781          */
10782     stopFx : function(){
10783         if(this.hasActiveFx()){
10784             var cur = this.fxQueue[0];
10785             if(cur && cur.anim && cur.anim.isAnimated()){
10786                 this.fxQueue = [cur]; // clear out others
10787                 cur.anim.stop(true);
10788             }
10789         }
10790         return this;
10791     },
10792
10793         /* @private */
10794     beforeFx : function(o){
10795         if(this.hasActiveFx() && !o.concurrent){
10796            if(o.stopFx){
10797                this.stopFx();
10798                return true;
10799            }
10800            return false;
10801         }
10802         return true;
10803     },
10804
10805         /**
10806          * Returns true if the element is currently blocking so that no other effect can be queued
10807          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10808          * used to ensure that an effect initiated by a user action runs to completion prior to the
10809          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10810          * @return {Boolean} True if blocking, else false
10811          */
10812     hasFxBlock : function(){
10813         var q = this.fxQueue;
10814         return q && q[0] && q[0].block;
10815     },
10816
10817         /* @private */
10818     queueFx : function(o, fn){
10819         if(!this.fxQueue){
10820             this.fxQueue = [];
10821         }
10822         if(!this.hasFxBlock()){
10823             Roo.applyIf(o, this.fxDefaults);
10824             if(!o.concurrent){
10825                 var run = this.beforeFx(o);
10826                 fn.block = o.block;
10827                 this.fxQueue.push(fn);
10828                 if(run){
10829                     this.nextFx();
10830                 }
10831             }else{
10832                 fn.call(this);
10833             }
10834         }
10835         return this;
10836     },
10837
10838         /* @private */
10839     fxWrap : function(pos, o, vis){
10840         var wrap;
10841         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10842             var wrapXY;
10843             if(o.fixPosition){
10844                 wrapXY = this.getXY();
10845             }
10846             var div = document.createElement("div");
10847             div.style.visibility = vis;
10848             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10849             wrap.setPositioning(pos);
10850             if(wrap.getStyle("position") == "static"){
10851                 wrap.position("relative");
10852             }
10853             this.clearPositioning('auto');
10854             wrap.clip();
10855             wrap.dom.appendChild(this.dom);
10856             if(wrapXY){
10857                 wrap.setXY(wrapXY);
10858             }
10859         }
10860         return wrap;
10861     },
10862
10863         /* @private */
10864     fxUnwrap : function(wrap, pos, o){
10865         this.clearPositioning();
10866         this.setPositioning(pos);
10867         if(!o.wrap){
10868             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10869             wrap.remove();
10870         }
10871     },
10872
10873         /* @private */
10874     getFxRestore : function(){
10875         var st = this.dom.style;
10876         return {pos: this.getPositioning(), width: st.width, height : st.height};
10877     },
10878
10879         /* @private */
10880     afterFx : function(o){
10881         if(o.afterStyle){
10882             this.applyStyles(o.afterStyle);
10883         }
10884         if(o.afterCls){
10885             this.addClass(o.afterCls);
10886         }
10887         if(o.remove === true){
10888             this.remove();
10889         }
10890         Roo.callback(o.callback, o.scope, [this]);
10891         if(!o.concurrent){
10892             this.fxQueue.shift();
10893             this.nextFx();
10894         }
10895     },
10896
10897         /* @private */
10898     getFxEl : function(){ // support for composite element fx
10899         return Roo.get(this.dom);
10900     },
10901
10902         /* @private */
10903     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10904         animType = animType || 'run';
10905         opt = opt || {};
10906         var anim = Roo.lib.Anim[animType](
10907             this.dom, args,
10908             (opt.duration || defaultDur) || .35,
10909             (opt.easing || defaultEase) || 'easeOut',
10910             function(){
10911                 Roo.callback(cb, this);
10912             },
10913             this
10914         );
10915         opt.anim = anim;
10916         return anim;
10917     }
10918 };
10919
10920 // backwords compat
10921 Roo.Fx.resize = Roo.Fx.scale;
10922
10923 //When included, Roo.Fx is automatically applied to Element so that all basic
10924 //effects are available directly via the Element API
10925 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10926  * Based on:
10927  * Ext JS Library 1.1.1
10928  * Copyright(c) 2006-2007, Ext JS, LLC.
10929  *
10930  * Originally Released Under LGPL - original licence link has changed is not relivant.
10931  *
10932  * Fork - LGPL
10933  * <script type="text/javascript">
10934  */
10935
10936
10937 /**
10938  * @class Roo.CompositeElement
10939  * Standard composite class. Creates a Roo.Element for every element in the collection.
10940  * <br><br>
10941  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10942  * actions will be performed on all the elements in this collection.</b>
10943  * <br><br>
10944  * All methods return <i>this</i> and can be chained.
10945  <pre><code>
10946  var els = Roo.select("#some-el div.some-class", true);
10947  // or select directly from an existing element
10948  var el = Roo.get('some-el');
10949  el.select('div.some-class', true);
10950
10951  els.setWidth(100); // all elements become 100 width
10952  els.hide(true); // all elements fade out and hide
10953  // or
10954  els.setWidth(100).hide(true);
10955  </code></pre>
10956  */
10957 Roo.CompositeElement = function(els){
10958     this.elements = [];
10959     this.addElements(els);
10960 };
10961 Roo.CompositeElement.prototype = {
10962     isComposite: true,
10963     addElements : function(els){
10964         if(!els) return this;
10965         if(typeof els == "string"){
10966             els = Roo.Element.selectorFunction(els);
10967         }
10968         var yels = this.elements;
10969         var index = yels.length-1;
10970         for(var i = 0, len = els.length; i < len; i++) {
10971                 yels[++index] = Roo.get(els[i]);
10972         }
10973         return this;
10974     },
10975
10976     /**
10977     * Clears this composite and adds the elements returned by the passed selector.
10978     * @param {String/Array} els A string CSS selector, an array of elements or an element
10979     * @return {CompositeElement} this
10980     */
10981     fill : function(els){
10982         this.elements = [];
10983         this.add(els);
10984         return this;
10985     },
10986
10987     /**
10988     * Filters this composite to only elements that match the passed selector.
10989     * @param {String} selector A string CSS selector
10990     * @param {Boolean} inverse return inverse filter (not matches)
10991     * @return {CompositeElement} this
10992     */
10993     filter : function(selector, inverse){
10994         var els = [];
10995         inverse = inverse || false;
10996         this.each(function(el){
10997             var match = inverse ? !el.is(selector) : el.is(selector);
10998             if(match){
10999                 els[els.length] = el.dom;
11000             }
11001         });
11002         this.fill(els);
11003         return this;
11004     },
11005
11006     invoke : function(fn, args){
11007         var els = this.elements;
11008         for(var i = 0, len = els.length; i < len; i++) {
11009                 Roo.Element.prototype[fn].apply(els[i], args);
11010         }
11011         return this;
11012     },
11013     /**
11014     * Adds elements to this composite.
11015     * @param {String/Array} els A string CSS selector, an array of elements or an element
11016     * @return {CompositeElement} this
11017     */
11018     add : function(els){
11019         if(typeof els == "string"){
11020             this.addElements(Roo.Element.selectorFunction(els));
11021         }else if(els.length !== undefined){
11022             this.addElements(els);
11023         }else{
11024             this.addElements([els]);
11025         }
11026         return this;
11027     },
11028     /**
11029     * Calls the passed function passing (el, this, index) for each element in this composite.
11030     * @param {Function} fn The function to call
11031     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11032     * @return {CompositeElement} this
11033     */
11034     each : function(fn, scope){
11035         var els = this.elements;
11036         for(var i = 0, len = els.length; i < len; i++){
11037             if(fn.call(scope || els[i], els[i], this, i) === false) {
11038                 break;
11039             }
11040         }
11041         return this;
11042     },
11043
11044     /**
11045      * Returns the Element object at the specified index
11046      * @param {Number} index
11047      * @return {Roo.Element}
11048      */
11049     item : function(index){
11050         return this.elements[index] || null;
11051     },
11052
11053     /**
11054      * Returns the first Element
11055      * @return {Roo.Element}
11056      */
11057     first : function(){
11058         return this.item(0);
11059     },
11060
11061     /**
11062      * Returns the last Element
11063      * @return {Roo.Element}
11064      */
11065     last : function(){
11066         return this.item(this.elements.length-1);
11067     },
11068
11069     /**
11070      * Returns the number of elements in this composite
11071      * @return Number
11072      */
11073     getCount : function(){
11074         return this.elements.length;
11075     },
11076
11077     /**
11078      * Returns true if this composite contains the passed element
11079      * @return Boolean
11080      */
11081     contains : function(el){
11082         return this.indexOf(el) !== -1;
11083     },
11084
11085     /**
11086      * Returns true if this composite contains the passed element
11087      * @return Boolean
11088      */
11089     indexOf : function(el){
11090         return this.elements.indexOf(Roo.get(el));
11091     },
11092
11093
11094     /**
11095     * Removes the specified element(s).
11096     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11097     * or an array of any of those.
11098     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11099     * @return {CompositeElement} this
11100     */
11101     removeElement : function(el, removeDom){
11102         if(el instanceof Array){
11103             for(var i = 0, len = el.length; i < len; i++){
11104                 this.removeElement(el[i]);
11105             }
11106             return this;
11107         }
11108         var index = typeof el == 'number' ? el : this.indexOf(el);
11109         if(index !== -1){
11110             if(removeDom){
11111                 var d = this.elements[index];
11112                 if(d.dom){
11113                     d.remove();
11114                 }else{
11115                     d.parentNode.removeChild(d);
11116                 }
11117             }
11118             this.elements.splice(index, 1);
11119         }
11120         return this;
11121     },
11122
11123     /**
11124     * Replaces the specified element with the passed element.
11125     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11126     * to replace.
11127     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11128     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11129     * @return {CompositeElement} this
11130     */
11131     replaceElement : function(el, replacement, domReplace){
11132         var index = typeof el == 'number' ? el : this.indexOf(el);
11133         if(index !== -1){
11134             if(domReplace){
11135                 this.elements[index].replaceWith(replacement);
11136             }else{
11137                 this.elements.splice(index, 1, Roo.get(replacement))
11138             }
11139         }
11140         return this;
11141     },
11142
11143     /**
11144      * Removes all elements.
11145      */
11146     clear : function(){
11147         this.elements = [];
11148     }
11149 };
11150 (function(){
11151     Roo.CompositeElement.createCall = function(proto, fnName){
11152         if(!proto[fnName]){
11153             proto[fnName] = function(){
11154                 return this.invoke(fnName, arguments);
11155             };
11156         }
11157     };
11158     for(var fnName in Roo.Element.prototype){
11159         if(typeof Roo.Element.prototype[fnName] == "function"){
11160             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11161         }
11162     };
11163 })();
11164 /*
11165  * Based on:
11166  * Ext JS Library 1.1.1
11167  * Copyright(c) 2006-2007, Ext JS, LLC.
11168  *
11169  * Originally Released Under LGPL - original licence link has changed is not relivant.
11170  *
11171  * Fork - LGPL
11172  * <script type="text/javascript">
11173  */
11174
11175 /**
11176  * @class Roo.CompositeElementLite
11177  * @extends Roo.CompositeElement
11178  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11179  <pre><code>
11180  var els = Roo.select("#some-el div.some-class");
11181  // or select directly from an existing element
11182  var el = Roo.get('some-el');
11183  el.select('div.some-class');
11184
11185  els.setWidth(100); // all elements become 100 width
11186  els.hide(true); // all elements fade out and hide
11187  // or
11188  els.setWidth(100).hide(true);
11189  </code></pre><br><br>
11190  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11191  * actions will be performed on all the elements in this collection.</b>
11192  */
11193 Roo.CompositeElementLite = function(els){
11194     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11195     this.el = new Roo.Element.Flyweight();
11196 };
11197 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11198     addElements : function(els){
11199         if(els){
11200             if(els instanceof Array){
11201                 this.elements = this.elements.concat(els);
11202             }else{
11203                 var yels = this.elements;
11204                 var index = yels.length-1;
11205                 for(var i = 0, len = els.length; i < len; i++) {
11206                     yels[++index] = els[i];
11207                 }
11208             }
11209         }
11210         return this;
11211     },
11212     invoke : function(fn, args){
11213         var els = this.elements;
11214         var el = this.el;
11215         for(var i = 0, len = els.length; i < len; i++) {
11216             el.dom = els[i];
11217                 Roo.Element.prototype[fn].apply(el, args);
11218         }
11219         return this;
11220     },
11221     /**
11222      * Returns a flyweight Element of the dom element object at the specified index
11223      * @param {Number} index
11224      * @return {Roo.Element}
11225      */
11226     item : function(index){
11227         if(!this.elements[index]){
11228             return null;
11229         }
11230         this.el.dom = this.elements[index];
11231         return this.el;
11232     },
11233
11234     // fixes scope with flyweight
11235     addListener : function(eventName, handler, scope, opt){
11236         var els = this.elements;
11237         for(var i = 0, len = els.length; i < len; i++) {
11238             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11239         }
11240         return this;
11241     },
11242
11243     /**
11244     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11245     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11246     * a reference to the dom node, use el.dom.</b>
11247     * @param {Function} fn The function to call
11248     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11249     * @return {CompositeElement} this
11250     */
11251     each : function(fn, scope){
11252         var els = this.elements;
11253         var el = this.el;
11254         for(var i = 0, len = els.length; i < len; i++){
11255             el.dom = els[i];
11256                 if(fn.call(scope || el, el, this, i) === false){
11257                 break;
11258             }
11259         }
11260         return this;
11261     },
11262
11263     indexOf : function(el){
11264         return this.elements.indexOf(Roo.getDom(el));
11265     },
11266
11267     replaceElement : function(el, replacement, domReplace){
11268         var index = typeof el == 'number' ? el : this.indexOf(el);
11269         if(index !== -1){
11270             replacement = Roo.getDom(replacement);
11271             if(domReplace){
11272                 var d = this.elements[index];
11273                 d.parentNode.insertBefore(replacement, d);
11274                 d.parentNode.removeChild(d);
11275             }
11276             this.elements.splice(index, 1, replacement);
11277         }
11278         return this;
11279     }
11280 });
11281 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11282
11283 /*
11284  * Based on:
11285  * Ext JS Library 1.1.1
11286  * Copyright(c) 2006-2007, Ext JS, LLC.
11287  *
11288  * Originally Released Under LGPL - original licence link has changed is not relivant.
11289  *
11290  * Fork - LGPL
11291  * <script type="text/javascript">
11292  */
11293
11294  
11295
11296 /**
11297  * @class Roo.data.Connection
11298  * @extends Roo.util.Observable
11299  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11300  * either to a configured URL, or to a URL specified at request time.<br><br>
11301  * <p>
11302  * Requests made by this class are asynchronous, and will return immediately. No data from
11303  * the server will be available to the statement immediately following the {@link #request} call.
11304  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11305  * <p>
11306  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11307  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11308  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11309  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11310  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11311  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11312  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11313  * standard DOM methods.
11314  * @constructor
11315  * @param {Object} config a configuration object.
11316  */
11317 Roo.data.Connection = function(config){
11318     Roo.apply(this, config);
11319     this.addEvents({
11320         /**
11321          * @event beforerequest
11322          * Fires before a network request is made to retrieve a data object.
11323          * @param {Connection} conn This Connection object.
11324          * @param {Object} options The options config object passed to the {@link #request} method.
11325          */
11326         "beforerequest" : true,
11327         /**
11328          * @event requestcomplete
11329          * Fires if the request was successfully completed.
11330          * @param {Connection} conn This Connection object.
11331          * @param {Object} response The XHR object containing the response data.
11332          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11333          * @param {Object} options The options config object passed to the {@link #request} method.
11334          */
11335         "requestcomplete" : true,
11336         /**
11337          * @event requestexception
11338          * Fires if an error HTTP status was returned from the server.
11339          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11340          * @param {Connection} conn This Connection object.
11341          * @param {Object} response The XHR object containing the response data.
11342          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11343          * @param {Object} options The options config object passed to the {@link #request} method.
11344          */
11345         "requestexception" : true
11346     });
11347     Roo.data.Connection.superclass.constructor.call(this);
11348 };
11349
11350 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11351     /**
11352      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11353      */
11354     /**
11355      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11356      * extra parameters to each request made by this object. (defaults to undefined)
11357      */
11358     /**
11359      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11360      *  to each request made by this object. (defaults to undefined)
11361      */
11362     /**
11363      * @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)
11364      */
11365     /**
11366      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11367      */
11368     timeout : 30000,
11369     /**
11370      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11371      * @type Boolean
11372      */
11373     autoAbort:false,
11374
11375     /**
11376      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11377      * @type Boolean
11378      */
11379     disableCaching: true,
11380
11381     /**
11382      * Sends an HTTP request to a remote server.
11383      * @param {Object} options An object which may contain the following properties:<ul>
11384      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11385      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11386      * request, a url encoded string or a function to call to get either.</li>
11387      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11388      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11389      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11390      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11391      * <li>options {Object} The parameter to the request call.</li>
11392      * <li>success {Boolean} True if the request succeeded.</li>
11393      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11394      * </ul></li>
11395      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11396      * The callback is passed the following parameters:<ul>
11397      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11398      * <li>options {Object} The parameter to the request call.</li>
11399      * </ul></li>
11400      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11401      * The callback is passed the following parameters:<ul>
11402      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11403      * <li>options {Object} The parameter to the request call.</li>
11404      * </ul></li>
11405      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11406      * for the callback function. Defaults to the browser window.</li>
11407      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11408      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11409      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11410      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11411      * params for the post data. Any params will be appended to the URL.</li>
11412      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11413      * </ul>
11414      * @return {Number} transactionId
11415      */
11416     request : function(o){
11417         if(this.fireEvent("beforerequest", this, o) !== false){
11418             var p = o.params;
11419
11420             if(typeof p == "function"){
11421                 p = p.call(o.scope||window, o);
11422             }
11423             if(typeof p == "object"){
11424                 p = Roo.urlEncode(o.params);
11425             }
11426             if(this.extraParams){
11427                 var extras = Roo.urlEncode(this.extraParams);
11428                 p = p ? (p + '&' + extras) : extras;
11429             }
11430
11431             var url = o.url || this.url;
11432             if(typeof url == 'function'){
11433                 url = url.call(o.scope||window, o);
11434             }
11435
11436             if(o.form){
11437                 var form = Roo.getDom(o.form);
11438                 url = url || form.action;
11439
11440                 var enctype = form.getAttribute("enctype");
11441                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11442                     return this.doFormUpload(o, p, url);
11443                 }
11444                 var f = Roo.lib.Ajax.serializeForm(form);
11445                 p = p ? (p + '&' + f) : f;
11446             }
11447
11448             var hs = o.headers;
11449             if(this.defaultHeaders){
11450                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11451                 if(!o.headers){
11452                     o.headers = hs;
11453                 }
11454             }
11455
11456             var cb = {
11457                 success: this.handleResponse,
11458                 failure: this.handleFailure,
11459                 scope: this,
11460                 argument: {options: o},
11461                 timeout : o.timeout || this.timeout
11462             };
11463
11464             var method = o.method||this.method||(p ? "POST" : "GET");
11465
11466             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11467                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11468             }
11469
11470             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11471                 if(o.autoAbort){
11472                     this.abort();
11473                 }
11474             }else if(this.autoAbort !== false){
11475                 this.abort();
11476             }
11477
11478             if((method == 'GET' && p) || o.xmlData){
11479                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11480                 p = '';
11481             }
11482             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11483             return this.transId;
11484         }else{
11485             Roo.callback(o.callback, o.scope, [o, null, null]);
11486             return null;
11487         }
11488     },
11489
11490     /**
11491      * Determine whether this object has a request outstanding.
11492      * @param {Number} transactionId (Optional) defaults to the last transaction
11493      * @return {Boolean} True if there is an outstanding request.
11494      */
11495     isLoading : function(transId){
11496         if(transId){
11497             return Roo.lib.Ajax.isCallInProgress(transId);
11498         }else{
11499             return this.transId ? true : false;
11500         }
11501     },
11502
11503     /**
11504      * Aborts any outstanding request.
11505      * @param {Number} transactionId (Optional) defaults to the last transaction
11506      */
11507     abort : function(transId){
11508         if(transId || this.isLoading()){
11509             Roo.lib.Ajax.abort(transId || this.transId);
11510         }
11511     },
11512
11513     // private
11514     handleResponse : function(response){
11515         this.transId = false;
11516         var options = response.argument.options;
11517         response.argument = options ? options.argument : null;
11518         this.fireEvent("requestcomplete", this, response, options);
11519         Roo.callback(options.success, options.scope, [response, options]);
11520         Roo.callback(options.callback, options.scope, [options, true, response]);
11521     },
11522
11523     // private
11524     handleFailure : function(response, e){
11525         this.transId = false;
11526         var options = response.argument.options;
11527         response.argument = options ? options.argument : null;
11528         this.fireEvent("requestexception", this, response, options, e);
11529         Roo.callback(options.failure, options.scope, [response, options]);
11530         Roo.callback(options.callback, options.scope, [options, false, response]);
11531     },
11532
11533     // private
11534     doFormUpload : function(o, ps, url){
11535         var id = Roo.id();
11536         var frame = document.createElement('iframe');
11537         frame.id = id;
11538         frame.name = id;
11539         frame.className = 'x-hidden';
11540         if(Roo.isIE){
11541             frame.src = Roo.SSL_SECURE_URL;
11542         }
11543         document.body.appendChild(frame);
11544
11545         if(Roo.isIE){
11546            document.frames[id].name = id;
11547         }
11548
11549         var form = Roo.getDom(o.form);
11550         form.target = id;
11551         form.method = 'POST';
11552         form.enctype = form.encoding = 'multipart/form-data';
11553         if(url){
11554             form.action = url;
11555         }
11556
11557         var hiddens, hd;
11558         if(ps){ // add dynamic params
11559             hiddens = [];
11560             ps = Roo.urlDecode(ps, false);
11561             for(var k in ps){
11562                 if(ps.hasOwnProperty(k)){
11563                     hd = document.createElement('input');
11564                     hd.type = 'hidden';
11565                     hd.name = k;
11566                     hd.value = ps[k];
11567                     form.appendChild(hd);
11568                     hiddens.push(hd);
11569                 }
11570             }
11571         }
11572
11573         function cb(){
11574             var r = {  // bogus response object
11575                 responseText : '',
11576                 responseXML : null
11577             };
11578
11579             r.argument = o ? o.argument : null;
11580
11581             try { //
11582                 var doc;
11583                 if(Roo.isIE){
11584                     doc = frame.contentWindow.document;
11585                 }else {
11586                     doc = (frame.contentDocument || window.frames[id].document);
11587                 }
11588                 if(doc && doc.body){
11589                     r.responseText = doc.body.innerHTML;
11590                 }
11591                 if(doc && doc.XMLDocument){
11592                     r.responseXML = doc.XMLDocument;
11593                 }else {
11594                     r.responseXML = doc;
11595                 }
11596             }
11597             catch(e) {
11598                 // ignore
11599             }
11600
11601             Roo.EventManager.removeListener(frame, 'load', cb, this);
11602
11603             this.fireEvent("requestcomplete", this, r, o);
11604             Roo.callback(o.success, o.scope, [r, o]);
11605             Roo.callback(o.callback, o.scope, [o, true, r]);
11606
11607             setTimeout(function(){document.body.removeChild(frame);}, 100);
11608         }
11609
11610         Roo.EventManager.on(frame, 'load', cb, this);
11611         form.submit();
11612
11613         if(hiddens){ // remove dynamic params
11614             for(var i = 0, len = hiddens.length; i < len; i++){
11615                 form.removeChild(hiddens[i]);
11616             }
11617         }
11618     }
11619 });
11620 /*
11621  * Based on:
11622  * Ext JS Library 1.1.1
11623  * Copyright(c) 2006-2007, Ext JS, LLC.
11624  *
11625  * Originally Released Under LGPL - original licence link has changed is not relivant.
11626  *
11627  * Fork - LGPL
11628  * <script type="text/javascript">
11629  */
11630  
11631 /**
11632  * Global Ajax request class.
11633  * 
11634  * @class Roo.Ajax
11635  * @extends Roo.data.Connection
11636  * @static
11637  * 
11638  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11639  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11640  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11641  * @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)
11642  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11643  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11644  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11645  */
11646 Roo.Ajax = new Roo.data.Connection({
11647     // fix up the docs
11648     /**
11649      * @scope Roo.Ajax
11650      * @type {Boolear} 
11651      */
11652     autoAbort : false,
11653
11654     /**
11655      * Serialize the passed form into a url encoded string
11656      * @scope Roo.Ajax
11657      * @param {String/HTMLElement} form
11658      * @return {String}
11659      */
11660     serializeForm : function(form){
11661         return Roo.lib.Ajax.serializeForm(form);
11662     }
11663 });/*
11664  * Based on:
11665  * Ext JS Library 1.1.1
11666  * Copyright(c) 2006-2007, Ext JS, LLC.
11667  *
11668  * Originally Released Under LGPL - original licence link has changed is not relivant.
11669  *
11670  * Fork - LGPL
11671  * <script type="text/javascript">
11672  */
11673
11674  
11675 /**
11676  * @class Roo.UpdateManager
11677  * @extends Roo.util.Observable
11678  * Provides AJAX-style update for Element object.<br><br>
11679  * Usage:<br>
11680  * <pre><code>
11681  * // Get it from a Roo.Element object
11682  * var el = Roo.get("foo");
11683  * var mgr = el.getUpdateManager();
11684  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11685  * ...
11686  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11687  * <br>
11688  * // or directly (returns the same UpdateManager instance)
11689  * var mgr = new Roo.UpdateManager("myElementId");
11690  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11691  * mgr.on("update", myFcnNeedsToKnow);
11692  * <br>
11693    // short handed call directly from the element object
11694    Roo.get("foo").load({
11695         url: "bar.php",
11696         scripts:true,
11697         params: "for=bar",
11698         text: "Loading Foo..."
11699    });
11700  * </code></pre>
11701  * @constructor
11702  * Create new UpdateManager directly.
11703  * @param {String/HTMLElement/Roo.Element} el The element to update
11704  * @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).
11705  */
11706 Roo.UpdateManager = function(el, forceNew){
11707     el = Roo.get(el);
11708     if(!forceNew && el.updateManager){
11709         return el.updateManager;
11710     }
11711     /**
11712      * The Element object
11713      * @type Roo.Element
11714      */
11715     this.el = el;
11716     /**
11717      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11718      * @type String
11719      */
11720     this.defaultUrl = null;
11721
11722     this.addEvents({
11723         /**
11724          * @event beforeupdate
11725          * Fired before an update is made, return false from your handler and the update is cancelled.
11726          * @param {Roo.Element} el
11727          * @param {String/Object/Function} url
11728          * @param {String/Object} params
11729          */
11730         "beforeupdate": true,
11731         /**
11732          * @event update
11733          * Fired after successful update is made.
11734          * @param {Roo.Element} el
11735          * @param {Object} oResponseObject The response Object
11736          */
11737         "update": true,
11738         /**
11739          * @event failure
11740          * Fired on update failure.
11741          * @param {Roo.Element} el
11742          * @param {Object} oResponseObject The response Object
11743          */
11744         "failure": true
11745     });
11746     var d = Roo.UpdateManager.defaults;
11747     /**
11748      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11749      * @type String
11750      */
11751     this.sslBlankUrl = d.sslBlankUrl;
11752     /**
11753      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11754      * @type Boolean
11755      */
11756     this.disableCaching = d.disableCaching;
11757     /**
11758      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11759      * @type String
11760      */
11761     this.indicatorText = d.indicatorText;
11762     /**
11763      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11764      * @type String
11765      */
11766     this.showLoadIndicator = d.showLoadIndicator;
11767     /**
11768      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11769      * @type Number
11770      */
11771     this.timeout = d.timeout;
11772
11773     /**
11774      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11775      * @type Boolean
11776      */
11777     this.loadScripts = d.loadScripts;
11778
11779     /**
11780      * Transaction object of current executing transaction
11781      */
11782     this.transaction = null;
11783
11784     /**
11785      * @private
11786      */
11787     this.autoRefreshProcId = null;
11788     /**
11789      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11790      * @type Function
11791      */
11792     this.refreshDelegate = this.refresh.createDelegate(this);
11793     /**
11794      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11795      * @type Function
11796      */
11797     this.updateDelegate = this.update.createDelegate(this);
11798     /**
11799      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11800      * @type Function
11801      */
11802     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11803     /**
11804      * @private
11805      */
11806     this.successDelegate = this.processSuccess.createDelegate(this);
11807     /**
11808      * @private
11809      */
11810     this.failureDelegate = this.processFailure.createDelegate(this);
11811
11812     if(!this.renderer){
11813      /**
11814       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11815       */
11816     this.renderer = new Roo.UpdateManager.BasicRenderer();
11817     }
11818     
11819     Roo.UpdateManager.superclass.constructor.call(this);
11820 };
11821
11822 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11823     /**
11824      * Get the Element this UpdateManager is bound to
11825      * @return {Roo.Element} The element
11826      */
11827     getEl : function(){
11828         return this.el;
11829     },
11830     /**
11831      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11832      * @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:
11833 <pre><code>
11834 um.update({<br/>
11835     url: "your-url.php",<br/>
11836     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11837     callback: yourFunction,<br/>
11838     scope: yourObject, //(optional scope)  <br/>
11839     discardUrl: false, <br/>
11840     nocache: false,<br/>
11841     text: "Loading...",<br/>
11842     timeout: 30,<br/>
11843     scripts: false<br/>
11844 });
11845 </code></pre>
11846      * The only required property is url. The optional properties nocache, text and scripts
11847      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11848      * @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}
11849      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11850      * @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.
11851      */
11852     update : function(url, params, callback, discardUrl){
11853         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11854             var method = this.method,
11855                 cfg;
11856             if(typeof url == "object"){ // must be config object
11857                 cfg = url;
11858                 url = cfg.url;
11859                 params = params || cfg.params;
11860                 callback = callback || cfg.callback;
11861                 discardUrl = discardUrl || cfg.discardUrl;
11862                 if(callback && cfg.scope){
11863                     callback = callback.createDelegate(cfg.scope);
11864                 }
11865                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11866                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11867                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11868                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11869                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11870             }
11871             this.showLoading();
11872             if(!discardUrl){
11873                 this.defaultUrl = url;
11874             }
11875             if(typeof url == "function"){
11876                 url = url.call(this);
11877             }
11878
11879             method = method || (params ? "POST" : "GET");
11880             if(method == "GET"){
11881                 url = this.prepareUrl(url);
11882             }
11883
11884             var o = Roo.apply(cfg ||{}, {
11885                 url : url,
11886                 params: params,
11887                 success: this.successDelegate,
11888                 failure: this.failureDelegate,
11889                 callback: undefined,
11890                 timeout: (this.timeout*1000),
11891                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11892             });
11893             Roo.log("updated manager called with timeout of " + o.timeout);
11894             this.transaction = Roo.Ajax.request(o);
11895         }
11896     },
11897
11898     /**
11899      * 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.
11900      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11901      * @param {String/HTMLElement} form The form Id or form element
11902      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11903      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11904      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11905      */
11906     formUpdate : function(form, url, reset, callback){
11907         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11908             if(typeof url == "function"){
11909                 url = url.call(this);
11910             }
11911             form = Roo.getDom(form);
11912             this.transaction = Roo.Ajax.request({
11913                 form: form,
11914                 url:url,
11915                 success: this.successDelegate,
11916                 failure: this.failureDelegate,
11917                 timeout: (this.timeout*1000),
11918                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11919             });
11920             this.showLoading.defer(1, this);
11921         }
11922     },
11923
11924     /**
11925      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11926      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11927      */
11928     refresh : function(callback){
11929         if(this.defaultUrl == null){
11930             return;
11931         }
11932         this.update(this.defaultUrl, null, callback, true);
11933     },
11934
11935     /**
11936      * Set this element to auto refresh.
11937      * @param {Number} interval How often to update (in seconds).
11938      * @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)
11939      * @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}
11940      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11941      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11942      */
11943     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11944         if(refreshNow){
11945             this.update(url || this.defaultUrl, params, callback, true);
11946         }
11947         if(this.autoRefreshProcId){
11948             clearInterval(this.autoRefreshProcId);
11949         }
11950         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11951     },
11952
11953     /**
11954      * Stop auto refresh on this element.
11955      */
11956      stopAutoRefresh : function(){
11957         if(this.autoRefreshProcId){
11958             clearInterval(this.autoRefreshProcId);
11959             delete this.autoRefreshProcId;
11960         }
11961     },
11962
11963     isAutoRefreshing : function(){
11964        return this.autoRefreshProcId ? true : false;
11965     },
11966     /**
11967      * Called to update the element to "Loading" state. Override to perform custom action.
11968      */
11969     showLoading : function(){
11970         if(this.showLoadIndicator){
11971             this.el.update(this.indicatorText);
11972         }
11973     },
11974
11975     /**
11976      * Adds unique parameter to query string if disableCaching = true
11977      * @private
11978      */
11979     prepareUrl : function(url){
11980         if(this.disableCaching){
11981             var append = "_dc=" + (new Date().getTime());
11982             if(url.indexOf("?") !== -1){
11983                 url += "&" + append;
11984             }else{
11985                 url += "?" + append;
11986             }
11987         }
11988         return url;
11989     },
11990
11991     /**
11992      * @private
11993      */
11994     processSuccess : function(response){
11995         this.transaction = null;
11996         if(response.argument.form && response.argument.reset){
11997             try{ // put in try/catch since some older FF releases had problems with this
11998                 response.argument.form.reset();
11999             }catch(e){}
12000         }
12001         if(this.loadScripts){
12002             this.renderer.render(this.el, response, this,
12003                 this.updateComplete.createDelegate(this, [response]));
12004         }else{
12005             this.renderer.render(this.el, response, this);
12006             this.updateComplete(response);
12007         }
12008     },
12009
12010     updateComplete : function(response){
12011         this.fireEvent("update", this.el, response);
12012         if(typeof response.argument.callback == "function"){
12013             response.argument.callback(this.el, true, response);
12014         }
12015     },
12016
12017     /**
12018      * @private
12019      */
12020     processFailure : function(response){
12021         this.transaction = null;
12022         this.fireEvent("failure", this.el, response);
12023         if(typeof response.argument.callback == "function"){
12024             response.argument.callback(this.el, false, response);
12025         }
12026     },
12027
12028     /**
12029      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12030      * @param {Object} renderer The object implementing the render() method
12031      */
12032     setRenderer : function(renderer){
12033         this.renderer = renderer;
12034     },
12035
12036     getRenderer : function(){
12037        return this.renderer;
12038     },
12039
12040     /**
12041      * Set the defaultUrl used for updates
12042      * @param {String/Function} defaultUrl The url or a function to call to get the url
12043      */
12044     setDefaultUrl : function(defaultUrl){
12045         this.defaultUrl = defaultUrl;
12046     },
12047
12048     /**
12049      * Aborts the executing transaction
12050      */
12051     abort : function(){
12052         if(this.transaction){
12053             Roo.Ajax.abort(this.transaction);
12054         }
12055     },
12056
12057     /**
12058      * Returns true if an update is in progress
12059      * @return {Boolean}
12060      */
12061     isUpdating : function(){
12062         if(this.transaction){
12063             return Roo.Ajax.isLoading(this.transaction);
12064         }
12065         return false;
12066     }
12067 });
12068
12069 /**
12070  * @class Roo.UpdateManager.defaults
12071  * @static (not really - but it helps the doc tool)
12072  * The defaults collection enables customizing the default properties of UpdateManager
12073  */
12074    Roo.UpdateManager.defaults = {
12075        /**
12076          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12077          * @type Number
12078          */
12079          timeout : 30,
12080
12081          /**
12082          * True to process scripts by default (Defaults to false).
12083          * @type Boolean
12084          */
12085         loadScripts : false,
12086
12087         /**
12088         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12089         * @type String
12090         */
12091         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12092         /**
12093          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12094          * @type Boolean
12095          */
12096         disableCaching : false,
12097         /**
12098          * Whether to show indicatorText when loading (Defaults to true).
12099          * @type Boolean
12100          */
12101         showLoadIndicator : true,
12102         /**
12103          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12104          * @type String
12105          */
12106         indicatorText : '<div class="loading-indicator">Loading...</div>'
12107    };
12108
12109 /**
12110  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12111  *Usage:
12112  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12113  * @param {String/HTMLElement/Roo.Element} el The element to update
12114  * @param {String} url The url
12115  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12116  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12117  * @static
12118  * @deprecated
12119  * @member Roo.UpdateManager
12120  */
12121 Roo.UpdateManager.updateElement = function(el, url, params, options){
12122     var um = Roo.get(el, true).getUpdateManager();
12123     Roo.apply(um, options);
12124     um.update(url, params, options ? options.callback : null);
12125 };
12126 // alias for backwards compat
12127 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12128 /**
12129  * @class Roo.UpdateManager.BasicRenderer
12130  * Default Content renderer. Updates the elements innerHTML with the responseText.
12131  */
12132 Roo.UpdateManager.BasicRenderer = function(){};
12133
12134 Roo.UpdateManager.BasicRenderer.prototype = {
12135     /**
12136      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12137      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12138      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12139      * @param {Roo.Element} el The element being rendered
12140      * @param {Object} response The YUI Connect response object
12141      * @param {UpdateManager} updateManager The calling update manager
12142      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12143      */
12144      render : function(el, response, updateManager, callback){
12145         el.update(response.responseText, updateManager.loadScripts, callback);
12146     }
12147 };
12148 /*
12149  * Based on:
12150  * Roo JS
12151  * (c)) Alan Knowles
12152  * Licence : LGPL
12153  */
12154
12155
12156 /**
12157  * @class Roo.DomTemplate
12158  * @extends Roo.Template
12159  * An effort at a dom based template engine..
12160  *
12161  * Similar to XTemplate, except it uses dom parsing to create the template..
12162  *
12163  * Supported features:
12164  *
12165  *  Tags:
12166
12167 <pre><code>
12168       {a_variable} - output encoded.
12169       {a_variable.format:("Y-m-d")} - call a method on the variable
12170       {a_variable:raw} - unencoded output
12171       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12172       {a_variable:this.method_on_template(...)} - call a method on the template object.
12173  
12174 </code></pre>
12175  *  The tpl tag:
12176 <pre><code>
12177         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12178         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12179         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12180         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12181   
12182 </code></pre>
12183  *      
12184  */
12185 Roo.DomTemplate = function()
12186 {
12187      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12188      if (this.html) {
12189         this.compile();
12190      }
12191 };
12192
12193
12194 Roo.extend(Roo.DomTemplate, Roo.Template, {
12195     /**
12196      * id counter for sub templates.
12197      */
12198     id : 0,
12199     /**
12200      * flag to indicate if dom parser is inside a pre,
12201      * it will strip whitespace if not.
12202      */
12203     inPre : false,
12204     
12205     /**
12206      * The various sub templates
12207      */
12208     tpls : false,
12209     
12210     
12211     
12212     /**
12213      *
12214      * basic tag replacing syntax
12215      * WORD:WORD()
12216      *
12217      * // you can fake an object call by doing this
12218      *  x.t:(test,tesT) 
12219      * 
12220      */
12221     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12222     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12223     
12224     iterChild : function (node, method) {
12225         
12226         var oldPre = this.inPre;
12227         if (node.tagName == 'PRE') {
12228             this.inPre = true;
12229         }
12230         for( var i = 0; i < node.childNodes.length; i++) {
12231             method.call(this, node.childNodes[i]);
12232         }
12233         this.inPre = oldPre;
12234     },
12235     
12236     
12237     
12238     /**
12239      * compile the template
12240      *
12241      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12242      *
12243      */
12244     compile: function()
12245     {
12246         var s = this.html;
12247         
12248         // covert the html into DOM...
12249         var doc = false;
12250         var div =false;
12251         try {
12252             doc = document.implementation.createHTMLDocument("");
12253             doc.documentElement.innerHTML =   this.html  ;
12254             div = doc.documentElement;
12255         } catch (e) {
12256             // old IE... - nasty -- it causes all sorts of issues.. with
12257             // images getting pulled from server..
12258             div = document.createElement('div');
12259             div.innerHTML = this.html;
12260         }
12261         //doc.documentElement.innerHTML = htmlBody
12262          
12263         
12264         
12265         this.tpls = [];
12266         var _t = this;
12267         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12268         
12269         var tpls = this.tpls;
12270         
12271         // create a top level template from the snippet..
12272         
12273         //Roo.log(div.innerHTML);
12274         
12275         var tpl = {
12276             uid : 'master',
12277             id : this.id++,
12278             attr : false,
12279             value : false,
12280             body : div.innerHTML,
12281             
12282             forCall : false,
12283             execCall : false,
12284             dom : div,
12285             isTop : true
12286             
12287         };
12288         tpls.unshift(tpl);
12289         
12290         
12291         // compile them...
12292         this.tpls = [];
12293         Roo.each(tpls, function(tp){
12294             this.compileTpl(tp);
12295             this.tpls[tp.id] = tp;
12296         }, this);
12297         
12298         this.master = tpls[0];
12299         return this;
12300         
12301         
12302     },
12303     
12304     compileNode : function(node, istop) {
12305         // test for
12306         //Roo.log(node);
12307         
12308         
12309         // skip anything not a tag..
12310         if (node.nodeType != 1) {
12311             if (node.nodeType == 3 && !this.inPre) {
12312                 // reduce white space..
12313                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12314                 
12315             }
12316             return;
12317         }
12318         
12319         var tpl = {
12320             uid : false,
12321             id : false,
12322             attr : false,
12323             value : false,
12324             body : '',
12325             
12326             forCall : false,
12327             execCall : false,
12328             dom : false,
12329             isTop : istop
12330             
12331             
12332         };
12333         
12334         
12335         switch(true) {
12336             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12337             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12338             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12339             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12340             // no default..
12341         }
12342         
12343         
12344         if (!tpl.attr) {
12345             // just itterate children..
12346             this.iterChild(node,this.compileNode);
12347             return;
12348         }
12349         tpl.uid = this.id++;
12350         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12351         node.removeAttribute('roo-'+ tpl.attr);
12352         if (tpl.attr != 'name') {
12353             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12354             node.parentNode.replaceChild(placeholder,  node);
12355         } else {
12356             
12357             var placeholder =  document.createElement('span');
12358             placeholder.className = 'roo-tpl-' + tpl.value;
12359             node.parentNode.replaceChild(placeholder,  node);
12360         }
12361         
12362         // parent now sees '{domtplXXXX}
12363         this.iterChild(node,this.compileNode);
12364         
12365         // we should now have node body...
12366         var div = document.createElement('div');
12367         div.appendChild(node);
12368         tpl.dom = node;
12369         // this has the unfortunate side effect of converting tagged attributes
12370         // eg. href="{...}" into %7C...%7D
12371         // this has been fixed by searching for those combo's although it's a bit hacky..
12372         
12373         
12374         tpl.body = div.innerHTML;
12375         
12376         
12377          
12378         tpl.id = tpl.uid;
12379         switch(tpl.attr) {
12380             case 'for' :
12381                 switch (tpl.value) {
12382                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12383                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12384                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12385                 }
12386                 break;
12387             
12388             case 'exec':
12389                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12390                 break;
12391             
12392             case 'if':     
12393                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12394                 break;
12395             
12396             case 'name':
12397                 tpl.id  = tpl.value; // replace non characters???
12398                 break;
12399             
12400         }
12401         
12402         
12403         this.tpls.push(tpl);
12404         
12405         
12406         
12407     },
12408     
12409     
12410     
12411     
12412     /**
12413      * Compile a segment of the template into a 'sub-template'
12414      *
12415      * 
12416      * 
12417      *
12418      */
12419     compileTpl : function(tpl)
12420     {
12421         var fm = Roo.util.Format;
12422         var useF = this.disableFormats !== true;
12423         
12424         var sep = Roo.isGecko ? "+\n" : ",\n";
12425         
12426         var undef = function(str) {
12427             Roo.debug && Roo.log("Property not found :"  + str);
12428             return '';
12429         };
12430           
12431         //Roo.log(tpl.body);
12432         
12433         
12434         
12435         var fn = function(m, lbrace, name, format, args)
12436         {
12437             //Roo.log("ARGS");
12438             //Roo.log(arguments);
12439             args = args ? args.replace(/\\'/g,"'") : args;
12440             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12441             if (typeof(format) == 'undefined') {
12442                 format =  'htmlEncode'; 
12443             }
12444             if (format == 'raw' ) {
12445                 format = false;
12446             }
12447             
12448             if(name.substr(0, 6) == 'domtpl'){
12449                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12450             }
12451             
12452             // build an array of options to determine if value is undefined..
12453             
12454             // basically get 'xxxx.yyyy' then do
12455             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12456             //    (function () { Roo.log("Property not found"); return ''; })() :
12457             //    ......
12458             
12459             var udef_ar = [];
12460             var lookfor = '';
12461             Roo.each(name.split('.'), function(st) {
12462                 lookfor += (lookfor.length ? '.': '') + st;
12463                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12464             });
12465             
12466             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12467             
12468             
12469             if(format && useF){
12470                 
12471                 args = args ? ',' + args : "";
12472                  
12473                 if(format.substr(0, 5) != "this."){
12474                     format = "fm." + format + '(';
12475                 }else{
12476                     format = 'this.call("'+ format.substr(5) + '", ';
12477                     args = ", values";
12478                 }
12479                 
12480                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12481             }
12482              
12483             if (args && args.length) {
12484                 // called with xxyx.yuu:(test,test)
12485                 // change to ()
12486                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12487             }
12488             // raw.. - :raw modifier..
12489             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12490             
12491         };
12492         var body;
12493         // branched to use + in gecko and [].join() in others
12494         if(Roo.isGecko){
12495             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12496                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12497                     "';};};";
12498         }else{
12499             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12500             body.push(tpl.body.replace(/(\r\n|\n)/g,
12501                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12502             body.push("'].join('');};};");
12503             body = body.join('');
12504         }
12505         
12506         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12507        
12508         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12509         eval(body);
12510         
12511         return this;
12512     },
12513      
12514     /**
12515      * same as applyTemplate, except it's done to one of the subTemplates
12516      * when using named templates, you can do:
12517      *
12518      * var str = pl.applySubTemplate('your-name', values);
12519      *
12520      * 
12521      * @param {Number} id of the template
12522      * @param {Object} values to apply to template
12523      * @param {Object} parent (normaly the instance of this object)
12524      */
12525     applySubTemplate : function(id, values, parent)
12526     {
12527         
12528         
12529         var t = this.tpls[id];
12530         
12531         
12532         try { 
12533             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12534                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12535                 return '';
12536             }
12537         } catch(e) {
12538             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12539             Roo.log(values);
12540           
12541             return '';
12542         }
12543         try { 
12544             
12545             if(t.execCall && t.execCall.call(this, values, parent)){
12546                 return '';
12547             }
12548         } catch(e) {
12549             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12550             Roo.log(values);
12551             return '';
12552         }
12553         
12554         try {
12555             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12556             parent = t.target ? values : parent;
12557             if(t.forCall && vs instanceof Array){
12558                 var buf = [];
12559                 for(var i = 0, len = vs.length; i < len; i++){
12560                     try {
12561                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12562                     } catch (e) {
12563                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12564                         Roo.log(e.body);
12565                         //Roo.log(t.compiled);
12566                         Roo.log(vs[i]);
12567                     }   
12568                 }
12569                 return buf.join('');
12570             }
12571         } catch (e) {
12572             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12573             Roo.log(values);
12574             return '';
12575         }
12576         try {
12577             return t.compiled.call(this, vs, parent);
12578         } catch (e) {
12579             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12580             Roo.log(e.body);
12581             //Roo.log(t.compiled);
12582             Roo.log(values);
12583             return '';
12584         }
12585     },
12586
12587    
12588
12589     applyTemplate : function(values){
12590         return this.master.compiled.call(this, values, {});
12591         //var s = this.subs;
12592     },
12593
12594     apply : function(){
12595         return this.applyTemplate.apply(this, arguments);
12596     }
12597
12598  });
12599
12600 Roo.DomTemplate.from = function(el){
12601     el = Roo.getDom(el);
12602     return new Roo.Domtemplate(el.value || el.innerHTML);
12603 };/*
12604  * Based on:
12605  * Ext JS Library 1.1.1
12606  * Copyright(c) 2006-2007, Ext JS, LLC.
12607  *
12608  * Originally Released Under LGPL - original licence link has changed is not relivant.
12609  *
12610  * Fork - LGPL
12611  * <script type="text/javascript">
12612  */
12613
12614 /**
12615  * @class Roo.util.DelayedTask
12616  * Provides a convenient method of performing setTimeout where a new
12617  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12618  * You can use this class to buffer
12619  * the keypress events for a certain number of milliseconds, and perform only if they stop
12620  * for that amount of time.
12621  * @constructor The parameters to this constructor serve as defaults and are not required.
12622  * @param {Function} fn (optional) The default function to timeout
12623  * @param {Object} scope (optional) The default scope of that timeout
12624  * @param {Array} args (optional) The default Array of arguments
12625  */
12626 Roo.util.DelayedTask = function(fn, scope, args){
12627     var id = null, d, t;
12628
12629     var call = function(){
12630         var now = new Date().getTime();
12631         if(now - t >= d){
12632             clearInterval(id);
12633             id = null;
12634             fn.apply(scope, args || []);
12635         }
12636     };
12637     /**
12638      * Cancels any pending timeout and queues a new one
12639      * @param {Number} delay The milliseconds to delay
12640      * @param {Function} newFn (optional) Overrides function passed to constructor
12641      * @param {Object} newScope (optional) Overrides scope passed to constructor
12642      * @param {Array} newArgs (optional) Overrides args passed to constructor
12643      */
12644     this.delay = function(delay, newFn, newScope, newArgs){
12645         if(id && delay != d){
12646             this.cancel();
12647         }
12648         d = delay;
12649         t = new Date().getTime();
12650         fn = newFn || fn;
12651         scope = newScope || scope;
12652         args = newArgs || args;
12653         if(!id){
12654             id = setInterval(call, d);
12655         }
12656     };
12657
12658     /**
12659      * Cancel the last queued timeout
12660      */
12661     this.cancel = function(){
12662         if(id){
12663             clearInterval(id);
12664             id = null;
12665         }
12666     };
12667 };/*
12668  * Based on:
12669  * Ext JS Library 1.1.1
12670  * Copyright(c) 2006-2007, Ext JS, LLC.
12671  *
12672  * Originally Released Under LGPL - original licence link has changed is not relivant.
12673  *
12674  * Fork - LGPL
12675  * <script type="text/javascript">
12676  */
12677  
12678  
12679 Roo.util.TaskRunner = function(interval){
12680     interval = interval || 10;
12681     var tasks = [], removeQueue = [];
12682     var id = 0;
12683     var running = false;
12684
12685     var stopThread = function(){
12686         running = false;
12687         clearInterval(id);
12688         id = 0;
12689     };
12690
12691     var startThread = function(){
12692         if(!running){
12693             running = true;
12694             id = setInterval(runTasks, interval);
12695         }
12696     };
12697
12698     var removeTask = function(task){
12699         removeQueue.push(task);
12700         if(task.onStop){
12701             task.onStop();
12702         }
12703     };
12704
12705     var runTasks = function(){
12706         if(removeQueue.length > 0){
12707             for(var i = 0, len = removeQueue.length; i < len; i++){
12708                 tasks.remove(removeQueue[i]);
12709             }
12710             removeQueue = [];
12711             if(tasks.length < 1){
12712                 stopThread();
12713                 return;
12714             }
12715         }
12716         var now = new Date().getTime();
12717         for(var i = 0, len = tasks.length; i < len; ++i){
12718             var t = tasks[i];
12719             var itime = now - t.taskRunTime;
12720             if(t.interval <= itime){
12721                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12722                 t.taskRunTime = now;
12723                 if(rt === false || t.taskRunCount === t.repeat){
12724                     removeTask(t);
12725                     return;
12726                 }
12727             }
12728             if(t.duration && t.duration <= (now - t.taskStartTime)){
12729                 removeTask(t);
12730             }
12731         }
12732     };
12733
12734     /**
12735      * Queues a new task.
12736      * @param {Object} task
12737      */
12738     this.start = function(task){
12739         tasks.push(task);
12740         task.taskStartTime = new Date().getTime();
12741         task.taskRunTime = 0;
12742         task.taskRunCount = 0;
12743         startThread();
12744         return task;
12745     };
12746
12747     this.stop = function(task){
12748         removeTask(task);
12749         return task;
12750     };
12751
12752     this.stopAll = function(){
12753         stopThread();
12754         for(var i = 0, len = tasks.length; i < len; i++){
12755             if(tasks[i].onStop){
12756                 tasks[i].onStop();
12757             }
12758         }
12759         tasks = [];
12760         removeQueue = [];
12761     };
12762 };
12763
12764 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12765  * Based on:
12766  * Ext JS Library 1.1.1
12767  * Copyright(c) 2006-2007, Ext JS, LLC.
12768  *
12769  * Originally Released Under LGPL - original licence link has changed is not relivant.
12770  *
12771  * Fork - LGPL
12772  * <script type="text/javascript">
12773  */
12774
12775  
12776 /**
12777  * @class Roo.util.MixedCollection
12778  * @extends Roo.util.Observable
12779  * A Collection class that maintains both numeric indexes and keys and exposes events.
12780  * @constructor
12781  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12782  * collection (defaults to false)
12783  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12784  * and return the key value for that item.  This is used when available to look up the key on items that
12785  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12786  * equivalent to providing an implementation for the {@link #getKey} method.
12787  */
12788 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12789     this.items = [];
12790     this.map = {};
12791     this.keys = [];
12792     this.length = 0;
12793     this.addEvents({
12794         /**
12795          * @event clear
12796          * Fires when the collection is cleared.
12797          */
12798         "clear" : true,
12799         /**
12800          * @event add
12801          * Fires when an item is added to the collection.
12802          * @param {Number} index The index at which the item was added.
12803          * @param {Object} o The item added.
12804          * @param {String} key The key associated with the added item.
12805          */
12806         "add" : true,
12807         /**
12808          * @event replace
12809          * Fires when an item is replaced in the collection.
12810          * @param {String} key he key associated with the new added.
12811          * @param {Object} old The item being replaced.
12812          * @param {Object} new The new item.
12813          */
12814         "replace" : true,
12815         /**
12816          * @event remove
12817          * Fires when an item is removed from the collection.
12818          * @param {Object} o The item being removed.
12819          * @param {String} key (optional) The key associated with the removed item.
12820          */
12821         "remove" : true,
12822         "sort" : true
12823     });
12824     this.allowFunctions = allowFunctions === true;
12825     if(keyFn){
12826         this.getKey = keyFn;
12827     }
12828     Roo.util.MixedCollection.superclass.constructor.call(this);
12829 };
12830
12831 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12832     allowFunctions : false,
12833     
12834 /**
12835  * Adds an item to the collection.
12836  * @param {String} key The key to associate with the item
12837  * @param {Object} o The item to add.
12838  * @return {Object} The item added.
12839  */
12840     add : function(key, o){
12841         if(arguments.length == 1){
12842             o = arguments[0];
12843             key = this.getKey(o);
12844         }
12845         if(typeof key == "undefined" || key === null){
12846             this.length++;
12847             this.items.push(o);
12848             this.keys.push(null);
12849         }else{
12850             var old = this.map[key];
12851             if(old){
12852                 return this.replace(key, o);
12853             }
12854             this.length++;
12855             this.items.push(o);
12856             this.map[key] = o;
12857             this.keys.push(key);
12858         }
12859         this.fireEvent("add", this.length-1, o, key);
12860         return o;
12861     },
12862        
12863 /**
12864   * MixedCollection has a generic way to fetch keys if you implement getKey.
12865 <pre><code>
12866 // normal way
12867 var mc = new Roo.util.MixedCollection();
12868 mc.add(someEl.dom.id, someEl);
12869 mc.add(otherEl.dom.id, otherEl);
12870 //and so on
12871
12872 // using getKey
12873 var mc = new Roo.util.MixedCollection();
12874 mc.getKey = function(el){
12875    return el.dom.id;
12876 };
12877 mc.add(someEl);
12878 mc.add(otherEl);
12879
12880 // or via the constructor
12881 var mc = new Roo.util.MixedCollection(false, function(el){
12882    return el.dom.id;
12883 });
12884 mc.add(someEl);
12885 mc.add(otherEl);
12886 </code></pre>
12887  * @param o {Object} The item for which to find the key.
12888  * @return {Object} The key for the passed item.
12889  */
12890     getKey : function(o){
12891          return o.id; 
12892     },
12893    
12894 /**
12895  * Replaces an item in the collection.
12896  * @param {String} key The key associated with the item to replace, or the item to replace.
12897  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12898  * @return {Object}  The new item.
12899  */
12900     replace : function(key, o){
12901         if(arguments.length == 1){
12902             o = arguments[0];
12903             key = this.getKey(o);
12904         }
12905         var old = this.item(key);
12906         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12907              return this.add(key, o);
12908         }
12909         var index = this.indexOfKey(key);
12910         this.items[index] = o;
12911         this.map[key] = o;
12912         this.fireEvent("replace", key, old, o);
12913         return o;
12914     },
12915    
12916 /**
12917  * Adds all elements of an Array or an Object to the collection.
12918  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12919  * an Array of values, each of which are added to the collection.
12920  */
12921     addAll : function(objs){
12922         if(arguments.length > 1 || objs instanceof Array){
12923             var args = arguments.length > 1 ? arguments : objs;
12924             for(var i = 0, len = args.length; i < len; i++){
12925                 this.add(args[i]);
12926             }
12927         }else{
12928             for(var key in objs){
12929                 if(this.allowFunctions || typeof objs[key] != "function"){
12930                     this.add(key, objs[key]);
12931                 }
12932             }
12933         }
12934     },
12935    
12936 /**
12937  * Executes the specified function once for every item in the collection, passing each
12938  * item as the first and only parameter. returning false from the function will stop the iteration.
12939  * @param {Function} fn The function to execute for each item.
12940  * @param {Object} scope (optional) The scope in which to execute the function.
12941  */
12942     each : function(fn, scope){
12943         var items = [].concat(this.items); // each safe for removal
12944         for(var i = 0, len = items.length; i < len; i++){
12945             if(fn.call(scope || items[i], items[i], i, len) === false){
12946                 break;
12947             }
12948         }
12949     },
12950    
12951 /**
12952  * Executes the specified function once for every key in the collection, passing each
12953  * key, and its associated item as the first two parameters.
12954  * @param {Function} fn The function to execute for each item.
12955  * @param {Object} scope (optional) The scope in which to execute the function.
12956  */
12957     eachKey : function(fn, scope){
12958         for(var i = 0, len = this.keys.length; i < len; i++){
12959             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12960         }
12961     },
12962    
12963 /**
12964  * Returns the first item in the collection which elicits a true return value from the
12965  * passed selection function.
12966  * @param {Function} fn The selection function to execute for each item.
12967  * @param {Object} scope (optional) The scope in which to execute the function.
12968  * @return {Object} The first item in the collection which returned true from the selection function.
12969  */
12970     find : function(fn, scope){
12971         for(var i = 0, len = this.items.length; i < len; i++){
12972             if(fn.call(scope || window, this.items[i], this.keys[i])){
12973                 return this.items[i];
12974             }
12975         }
12976         return null;
12977     },
12978    
12979 /**
12980  * Inserts an item at the specified index in the collection.
12981  * @param {Number} index The index to insert the item at.
12982  * @param {String} key The key to associate with the new item, or the item itself.
12983  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12984  * @return {Object} The item inserted.
12985  */
12986     insert : function(index, key, o){
12987         if(arguments.length == 2){
12988             o = arguments[1];
12989             key = this.getKey(o);
12990         }
12991         if(index >= this.length){
12992             return this.add(key, o);
12993         }
12994         this.length++;
12995         this.items.splice(index, 0, o);
12996         if(typeof key != "undefined" && key != null){
12997             this.map[key] = o;
12998         }
12999         this.keys.splice(index, 0, key);
13000         this.fireEvent("add", index, o, key);
13001         return o;
13002     },
13003    
13004 /**
13005  * Removed an item from the collection.
13006  * @param {Object} o The item to remove.
13007  * @return {Object} The item removed.
13008  */
13009     remove : function(o){
13010         return this.removeAt(this.indexOf(o));
13011     },
13012    
13013 /**
13014  * Remove an item from a specified index in the collection.
13015  * @param {Number} index The index within the collection of the item to remove.
13016  */
13017     removeAt : function(index){
13018         if(index < this.length && index >= 0){
13019             this.length--;
13020             var o = this.items[index];
13021             this.items.splice(index, 1);
13022             var key = this.keys[index];
13023             if(typeof key != "undefined"){
13024                 delete this.map[key];
13025             }
13026             this.keys.splice(index, 1);
13027             this.fireEvent("remove", o, key);
13028         }
13029     },
13030    
13031 /**
13032  * Removed an item associated with the passed key fom the collection.
13033  * @param {String} key The key of the item to remove.
13034  */
13035     removeKey : function(key){
13036         return this.removeAt(this.indexOfKey(key));
13037     },
13038    
13039 /**
13040  * Returns the number of items in the collection.
13041  * @return {Number} the number of items in the collection.
13042  */
13043     getCount : function(){
13044         return this.length; 
13045     },
13046    
13047 /**
13048  * Returns index within the collection of the passed Object.
13049  * @param {Object} o The item to find the index of.
13050  * @return {Number} index of the item.
13051  */
13052     indexOf : function(o){
13053         if(!this.items.indexOf){
13054             for(var i = 0, len = this.items.length; i < len; i++){
13055                 if(this.items[i] == o) return i;
13056             }
13057             return -1;
13058         }else{
13059             return this.items.indexOf(o);
13060         }
13061     },
13062    
13063 /**
13064  * Returns index within the collection of the passed key.
13065  * @param {String} key The key to find the index of.
13066  * @return {Number} index of the key.
13067  */
13068     indexOfKey : function(key){
13069         if(!this.keys.indexOf){
13070             for(var i = 0, len = this.keys.length; i < len; i++){
13071                 if(this.keys[i] == key) return i;
13072             }
13073             return -1;
13074         }else{
13075             return this.keys.indexOf(key);
13076         }
13077     },
13078    
13079 /**
13080  * Returns the item associated with the passed key OR index. Key has priority over index.
13081  * @param {String/Number} key The key or index of the item.
13082  * @return {Object} The item associated with the passed key.
13083  */
13084     item : function(key){
13085         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13086         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13087     },
13088     
13089 /**
13090  * Returns the item at the specified index.
13091  * @param {Number} index The index of the item.
13092  * @return {Object}
13093  */
13094     itemAt : function(index){
13095         return this.items[index];
13096     },
13097     
13098 /**
13099  * Returns the item associated with the passed key.
13100  * @param {String/Number} key The key of the item.
13101  * @return {Object} The item associated with the passed key.
13102  */
13103     key : function(key){
13104         return this.map[key];
13105     },
13106    
13107 /**
13108  * Returns true if the collection contains the passed Object as an item.
13109  * @param {Object} o  The Object to look for in the collection.
13110  * @return {Boolean} True if the collection contains the Object as an item.
13111  */
13112     contains : function(o){
13113         return this.indexOf(o) != -1;
13114     },
13115    
13116 /**
13117  * Returns true if the collection contains the passed Object as a key.
13118  * @param {String} key The key to look for in the collection.
13119  * @return {Boolean} True if the collection contains the Object as a key.
13120  */
13121     containsKey : function(key){
13122         return typeof this.map[key] != "undefined";
13123     },
13124    
13125 /**
13126  * Removes all items from the collection.
13127  */
13128     clear : function(){
13129         this.length = 0;
13130         this.items = [];
13131         this.keys = [];
13132         this.map = {};
13133         this.fireEvent("clear");
13134     },
13135    
13136 /**
13137  * Returns the first item in the collection.
13138  * @return {Object} the first item in the collection..
13139  */
13140     first : function(){
13141         return this.items[0]; 
13142     },
13143    
13144 /**
13145  * Returns the last item in the collection.
13146  * @return {Object} the last item in the collection..
13147  */
13148     last : function(){
13149         return this.items[this.length-1];   
13150     },
13151     
13152     _sort : function(property, dir, fn){
13153         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13154         fn = fn || function(a, b){
13155             return a-b;
13156         };
13157         var c = [], k = this.keys, items = this.items;
13158         for(var i = 0, len = items.length; i < len; i++){
13159             c[c.length] = {key: k[i], value: items[i], index: i};
13160         }
13161         c.sort(function(a, b){
13162             var v = fn(a[property], b[property]) * dsc;
13163             if(v == 0){
13164                 v = (a.index < b.index ? -1 : 1);
13165             }
13166             return v;
13167         });
13168         for(var i = 0, len = c.length; i < len; i++){
13169             items[i] = c[i].value;
13170             k[i] = c[i].key;
13171         }
13172         this.fireEvent("sort", this);
13173     },
13174     
13175     /**
13176      * Sorts this collection with the passed comparison function
13177      * @param {String} direction (optional) "ASC" or "DESC"
13178      * @param {Function} fn (optional) comparison function
13179      */
13180     sort : function(dir, fn){
13181         this._sort("value", dir, fn);
13182     },
13183     
13184     /**
13185      * Sorts this collection by keys
13186      * @param {String} direction (optional) "ASC" or "DESC"
13187      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13188      */
13189     keySort : function(dir, fn){
13190         this._sort("key", dir, fn || function(a, b){
13191             return String(a).toUpperCase()-String(b).toUpperCase();
13192         });
13193     },
13194     
13195     /**
13196      * Returns a range of items in this collection
13197      * @param {Number} startIndex (optional) defaults to 0
13198      * @param {Number} endIndex (optional) default to the last item
13199      * @return {Array} An array of items
13200      */
13201     getRange : function(start, end){
13202         var items = this.items;
13203         if(items.length < 1){
13204             return [];
13205         }
13206         start = start || 0;
13207         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13208         var r = [];
13209         if(start <= end){
13210             for(var i = start; i <= end; i++) {
13211                     r[r.length] = items[i];
13212             }
13213         }else{
13214             for(var i = start; i >= end; i--) {
13215                     r[r.length] = items[i];
13216             }
13217         }
13218         return r;
13219     },
13220         
13221     /**
13222      * Filter the <i>objects</i> in this collection by a specific property. 
13223      * Returns a new collection that has been filtered.
13224      * @param {String} property A property on your objects
13225      * @param {String/RegExp} value Either string that the property values 
13226      * should start with or a RegExp to test against the property
13227      * @return {MixedCollection} The new filtered collection
13228      */
13229     filter : function(property, value){
13230         if(!value.exec){ // not a regex
13231             value = String(value);
13232             if(value.length == 0){
13233                 return this.clone();
13234             }
13235             value = new RegExp("^" + Roo.escapeRe(value), "i");
13236         }
13237         return this.filterBy(function(o){
13238             return o && value.test(o[property]);
13239         });
13240         },
13241     
13242     /**
13243      * Filter by a function. * Returns a new collection that has been filtered.
13244      * The passed function will be called with each 
13245      * object in the collection. If the function returns true, the value is included 
13246      * otherwise it is filtered.
13247      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13248      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13249      * @return {MixedCollection} The new filtered collection
13250      */
13251     filterBy : function(fn, scope){
13252         var r = new Roo.util.MixedCollection();
13253         r.getKey = this.getKey;
13254         var k = this.keys, it = this.items;
13255         for(var i = 0, len = it.length; i < len; i++){
13256             if(fn.call(scope||this, it[i], k[i])){
13257                                 r.add(k[i], it[i]);
13258                         }
13259         }
13260         return r;
13261     },
13262     
13263     /**
13264      * Creates a duplicate of this collection
13265      * @return {MixedCollection}
13266      */
13267     clone : function(){
13268         var r = new Roo.util.MixedCollection();
13269         var k = this.keys, it = this.items;
13270         for(var i = 0, len = it.length; i < len; i++){
13271             r.add(k[i], it[i]);
13272         }
13273         r.getKey = this.getKey;
13274         return r;
13275     }
13276 });
13277 /**
13278  * Returns the item associated with the passed key or index.
13279  * @method
13280  * @param {String/Number} key The key or index of the item.
13281  * @return {Object} The item associated with the passed key.
13282  */
13283 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13284  * Based on:
13285  * Ext JS Library 1.1.1
13286  * Copyright(c) 2006-2007, Ext JS, LLC.
13287  *
13288  * Originally Released Under LGPL - original licence link has changed is not relivant.
13289  *
13290  * Fork - LGPL
13291  * <script type="text/javascript">
13292  */
13293 /**
13294  * @class Roo.util.JSON
13295  * Modified version of Douglas Crockford"s json.js that doesn"t
13296  * mess with the Object prototype 
13297  * http://www.json.org/js.html
13298  * @singleton
13299  */
13300 Roo.util.JSON = new (function(){
13301     var useHasOwn = {}.hasOwnProperty ? true : false;
13302     
13303     // crashes Safari in some instances
13304     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13305     
13306     var pad = function(n) {
13307         return n < 10 ? "0" + n : n;
13308     };
13309     
13310     var m = {
13311         "\b": '\\b',
13312         "\t": '\\t',
13313         "\n": '\\n',
13314         "\f": '\\f',
13315         "\r": '\\r',
13316         '"' : '\\"',
13317         "\\": '\\\\'
13318     };
13319
13320     var encodeString = function(s){
13321         if (/["\\\x00-\x1f]/.test(s)) {
13322             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13323                 var c = m[b];
13324                 if(c){
13325                     return c;
13326                 }
13327                 c = b.charCodeAt();
13328                 return "\\u00" +
13329                     Math.floor(c / 16).toString(16) +
13330                     (c % 16).toString(16);
13331             }) + '"';
13332         }
13333         return '"' + s + '"';
13334     };
13335     
13336     var encodeArray = function(o){
13337         var a = ["["], b, i, l = o.length, v;
13338             for (i = 0; i < l; i += 1) {
13339                 v = o[i];
13340                 switch (typeof v) {
13341                     case "undefined":
13342                     case "function":
13343                     case "unknown":
13344                         break;
13345                     default:
13346                         if (b) {
13347                             a.push(',');
13348                         }
13349                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13350                         b = true;
13351                 }
13352             }
13353             a.push("]");
13354             return a.join("");
13355     };
13356     
13357     var encodeDate = function(o){
13358         return '"' + o.getFullYear() + "-" +
13359                 pad(o.getMonth() + 1) + "-" +
13360                 pad(o.getDate()) + "T" +
13361                 pad(o.getHours()) + ":" +
13362                 pad(o.getMinutes()) + ":" +
13363                 pad(o.getSeconds()) + '"';
13364     };
13365     
13366     /**
13367      * Encodes an Object, Array or other value
13368      * @param {Mixed} o The variable to encode
13369      * @return {String} The JSON string
13370      */
13371     this.encode = function(o)
13372     {
13373         // should this be extended to fully wrap stringify..
13374         
13375         if(typeof o == "undefined" || o === null){
13376             return "null";
13377         }else if(o instanceof Array){
13378             return encodeArray(o);
13379         }else if(o instanceof Date){
13380             return encodeDate(o);
13381         }else if(typeof o == "string"){
13382             return encodeString(o);
13383         }else if(typeof o == "number"){
13384             return isFinite(o) ? String(o) : "null";
13385         }else if(typeof o == "boolean"){
13386             return String(o);
13387         }else {
13388             var a = ["{"], b, i, v;
13389             for (i in o) {
13390                 if(!useHasOwn || o.hasOwnProperty(i)) {
13391                     v = o[i];
13392                     switch (typeof v) {
13393                     case "undefined":
13394                     case "function":
13395                     case "unknown":
13396                         break;
13397                     default:
13398                         if(b){
13399                             a.push(',');
13400                         }
13401                         a.push(this.encode(i), ":",
13402                                 v === null ? "null" : this.encode(v));
13403                         b = true;
13404                     }
13405                 }
13406             }
13407             a.push("}");
13408             return a.join("");
13409         }
13410     };
13411     
13412     /**
13413      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13414      * @param {String} json The JSON string
13415      * @return {Object} The resulting object
13416      */
13417     this.decode = function(json){
13418         
13419         return  /** eval:var:json */ eval("(" + json + ')');
13420     };
13421 })();
13422 /** 
13423  * Shorthand for {@link Roo.util.JSON#encode}
13424  * @member Roo encode 
13425  * @method */
13426 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13427 /** 
13428  * Shorthand for {@link Roo.util.JSON#decode}
13429  * @member Roo decode 
13430  * @method */
13431 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13432 /*
13433  * Based on:
13434  * Ext JS Library 1.1.1
13435  * Copyright(c) 2006-2007, Ext JS, LLC.
13436  *
13437  * Originally Released Under LGPL - original licence link has changed is not relivant.
13438  *
13439  * Fork - LGPL
13440  * <script type="text/javascript">
13441  */
13442  
13443 /**
13444  * @class Roo.util.Format
13445  * Reusable data formatting functions
13446  * @singleton
13447  */
13448 Roo.util.Format = function(){
13449     var trimRe = /^\s+|\s+$/g;
13450     return {
13451         /**
13452          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13453          * @param {String} value The string to truncate
13454          * @param {Number} length The maximum length to allow before truncating
13455          * @return {String} The converted text
13456          */
13457         ellipsis : function(value, len){
13458             if(value && value.length > len){
13459                 return value.substr(0, len-3)+"...";
13460             }
13461             return value;
13462         },
13463
13464         /**
13465          * Checks a reference and converts it to empty string if it is undefined
13466          * @param {Mixed} value Reference to check
13467          * @return {Mixed} Empty string if converted, otherwise the original value
13468          */
13469         undef : function(value){
13470             return typeof value != "undefined" ? value : "";
13471         },
13472
13473         /**
13474          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13475          * @param {String} value The string to encode
13476          * @return {String} The encoded text
13477          */
13478         htmlEncode : function(value){
13479             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13480         },
13481
13482         /**
13483          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13484          * @param {String} value The string to decode
13485          * @return {String} The decoded text
13486          */
13487         htmlDecode : function(value){
13488             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13489         },
13490
13491         /**
13492          * Trims any whitespace from either side of a string
13493          * @param {String} value The text to trim
13494          * @return {String} The trimmed text
13495          */
13496         trim : function(value){
13497             return String(value).replace(trimRe, "");
13498         },
13499
13500         /**
13501          * Returns a substring from within an original string
13502          * @param {String} value The original text
13503          * @param {Number} start The start index of the substring
13504          * @param {Number} length The length of the substring
13505          * @return {String} The substring
13506          */
13507         substr : function(value, start, length){
13508             return String(value).substr(start, length);
13509         },
13510
13511         /**
13512          * Converts a string to all lower case letters
13513          * @param {String} value The text to convert
13514          * @return {String} The converted text
13515          */
13516         lowercase : function(value){
13517             return String(value).toLowerCase();
13518         },
13519
13520         /**
13521          * Converts a string to all upper case letters
13522          * @param {String} value The text to convert
13523          * @return {String} The converted text
13524          */
13525         uppercase : function(value){
13526             return String(value).toUpperCase();
13527         },
13528
13529         /**
13530          * Converts the first character only of a string to upper case
13531          * @param {String} value The text to convert
13532          * @return {String} The converted text
13533          */
13534         capitalize : function(value){
13535             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13536         },
13537
13538         // private
13539         call : function(value, fn){
13540             if(arguments.length > 2){
13541                 var args = Array.prototype.slice.call(arguments, 2);
13542                 args.unshift(value);
13543                  
13544                 return /** eval:var:value */  eval(fn).apply(window, args);
13545             }else{
13546                 /** eval:var:value */
13547                 return /** eval:var:value */ eval(fn).call(window, value);
13548             }
13549         },
13550
13551        
13552         /**
13553          * safer version of Math.toFixed..??/
13554          * @param {Number/String} value The numeric value to format
13555          * @param {Number/String} value Decimal places 
13556          * @return {String} The formatted currency string
13557          */
13558         toFixed : function(v, n)
13559         {
13560             // why not use to fixed - precision is buggered???
13561             if (!n) {
13562                 return Math.round(v-0);
13563             }
13564             var fact = Math.pow(10,n+1);
13565             v = (Math.round((v-0)*fact))/fact;
13566             var z = (''+fact).substring(2);
13567             if (v == Math.floor(v)) {
13568                 return Math.floor(v) + '.' + z;
13569             }
13570             
13571             // now just padd decimals..
13572             var ps = String(v).split('.');
13573             var fd = (ps[1] + z);
13574             var r = fd.substring(0,n); 
13575             var rm = fd.substring(n); 
13576             if (rm < 5) {
13577                 return ps[0] + '.' + r;
13578             }
13579             r*=1; // turn it into a number;
13580             r++;
13581             if (String(r).length != n) {
13582                 ps[0]*=1;
13583                 ps[0]++;
13584                 r = String(r).substring(1); // chop the end off.
13585             }
13586             
13587             return ps[0] + '.' + r;
13588              
13589         },
13590         
13591         /**
13592          * Format a number as US currency
13593          * @param {Number/String} value The numeric value to format
13594          * @return {String} The formatted currency string
13595          */
13596         usMoney : function(v){
13597             return '$' + Roo.util.Format.number(v);
13598         },
13599         
13600         /**
13601          * Format a number
13602          * eventually this should probably emulate php's number_format
13603          * @param {Number/String} value The numeric value to format
13604          * @param {Number} decimals number of decimal places
13605          * @return {String} The formatted currency string
13606          */
13607         number : function(v,decimals)
13608         {
13609             // multiply and round.
13610             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13611             var mul = Math.pow(10, decimals);
13612             var zero = String(mul).substring(1);
13613             v = (Math.round((v-0)*mul))/mul;
13614             
13615             // if it's '0' number.. then
13616             
13617             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13618             v = String(v);
13619             var ps = v.split('.');
13620             var whole = ps[0];
13621             
13622             
13623             var r = /(\d+)(\d{3})/;
13624             // add comma's
13625             while (r.test(whole)) {
13626                 whole = whole.replace(r, '$1' + ',' + '$2');
13627             }
13628             
13629             
13630             var sub = ps[1] ?
13631                     // has decimals..
13632                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13633                     // does not have decimals
13634                     (decimals ? ('.' + zero) : '');
13635             
13636             
13637             return whole + sub ;
13638         },
13639         
13640         /**
13641          * Parse a value into a formatted date using the specified format pattern.
13642          * @param {Mixed} value The value to format
13643          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13644          * @return {String} The formatted date string
13645          */
13646         date : function(v, format){
13647             if(!v){
13648                 return "";
13649             }
13650             if(!(v instanceof Date)){
13651                 v = new Date(Date.parse(v));
13652             }
13653             return v.dateFormat(format || Roo.util.Format.defaults.date);
13654         },
13655
13656         /**
13657          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13658          * @param {String} format Any valid date format string
13659          * @return {Function} The date formatting function
13660          */
13661         dateRenderer : function(format){
13662             return function(v){
13663                 return Roo.util.Format.date(v, format);  
13664             };
13665         },
13666
13667         // private
13668         stripTagsRE : /<\/?[^>]+>/gi,
13669         
13670         /**
13671          * Strips all HTML tags
13672          * @param {Mixed} value The text from which to strip tags
13673          * @return {String} The stripped text
13674          */
13675         stripTags : function(v){
13676             return !v ? v : String(v).replace(this.stripTagsRE, "");
13677         }
13678     };
13679 }();
13680 Roo.util.Format.defaults = {
13681     date : 'd/M/Y'
13682 };/*
13683  * Based on:
13684  * Ext JS Library 1.1.1
13685  * Copyright(c) 2006-2007, Ext JS, LLC.
13686  *
13687  * Originally Released Under LGPL - original licence link has changed is not relivant.
13688  *
13689  * Fork - LGPL
13690  * <script type="text/javascript">
13691  */
13692
13693
13694  
13695
13696 /**
13697  * @class Roo.MasterTemplate
13698  * @extends Roo.Template
13699  * Provides a template that can have child templates. The syntax is:
13700 <pre><code>
13701 var t = new Roo.MasterTemplate(
13702         '&lt;select name="{name}"&gt;',
13703                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13704         '&lt;/select&gt;'
13705 );
13706 t.add('options', {value: 'foo', text: 'bar'});
13707 // or you can add multiple child elements in one shot
13708 t.addAll('options', [
13709     {value: 'foo', text: 'bar'},
13710     {value: 'foo2', text: 'bar2'},
13711     {value: 'foo3', text: 'bar3'}
13712 ]);
13713 // then append, applying the master template values
13714 t.append('my-form', {name: 'my-select'});
13715 </code></pre>
13716 * A name attribute for the child template is not required if you have only one child
13717 * template or you want to refer to them by index.
13718  */
13719 Roo.MasterTemplate = function(){
13720     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13721     this.originalHtml = this.html;
13722     var st = {};
13723     var m, re = this.subTemplateRe;
13724     re.lastIndex = 0;
13725     var subIndex = 0;
13726     while(m = re.exec(this.html)){
13727         var name = m[1], content = m[2];
13728         st[subIndex] = {
13729             name: name,
13730             index: subIndex,
13731             buffer: [],
13732             tpl : new Roo.Template(content)
13733         };
13734         if(name){
13735             st[name] = st[subIndex];
13736         }
13737         st[subIndex].tpl.compile();
13738         st[subIndex].tpl.call = this.call.createDelegate(this);
13739         subIndex++;
13740     }
13741     this.subCount = subIndex;
13742     this.subs = st;
13743 };
13744 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13745     /**
13746     * The regular expression used to match sub templates
13747     * @type RegExp
13748     * @property
13749     */
13750     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13751
13752     /**
13753      * Applies the passed values to a child template.
13754      * @param {String/Number} name (optional) The name or index of the child template
13755      * @param {Array/Object} values The values to be applied to the template
13756      * @return {MasterTemplate} this
13757      */
13758      add : function(name, values){
13759         if(arguments.length == 1){
13760             values = arguments[0];
13761             name = 0;
13762         }
13763         var s = this.subs[name];
13764         s.buffer[s.buffer.length] = s.tpl.apply(values);
13765         return this;
13766     },
13767
13768     /**
13769      * Applies all the passed values to a child template.
13770      * @param {String/Number} name (optional) The name or index of the child template
13771      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13772      * @param {Boolean} reset (optional) True to reset the template first
13773      * @return {MasterTemplate} this
13774      */
13775     fill : function(name, values, reset){
13776         var a = arguments;
13777         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13778             values = a[0];
13779             name = 0;
13780             reset = a[1];
13781         }
13782         if(reset){
13783             this.reset();
13784         }
13785         for(var i = 0, len = values.length; i < len; i++){
13786             this.add(name, values[i]);
13787         }
13788         return this;
13789     },
13790
13791     /**
13792      * Resets the template for reuse
13793      * @return {MasterTemplate} this
13794      */
13795      reset : function(){
13796         var s = this.subs;
13797         for(var i = 0; i < this.subCount; i++){
13798             s[i].buffer = [];
13799         }
13800         return this;
13801     },
13802
13803     applyTemplate : function(values){
13804         var s = this.subs;
13805         var replaceIndex = -1;
13806         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13807             return s[++replaceIndex].buffer.join("");
13808         });
13809         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13810     },
13811
13812     apply : function(){
13813         return this.applyTemplate.apply(this, arguments);
13814     },
13815
13816     compile : function(){return this;}
13817 });
13818
13819 /**
13820  * Alias for fill().
13821  * @method
13822  */
13823 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13824  /**
13825  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13826  * var tpl = Roo.MasterTemplate.from('element-id');
13827  * @param {String/HTMLElement} el
13828  * @param {Object} config
13829  * @static
13830  */
13831 Roo.MasterTemplate.from = function(el, config){
13832     el = Roo.getDom(el);
13833     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13834 };/*
13835  * Based on:
13836  * Ext JS Library 1.1.1
13837  * Copyright(c) 2006-2007, Ext JS, LLC.
13838  *
13839  * Originally Released Under LGPL - original licence link has changed is not relivant.
13840  *
13841  * Fork - LGPL
13842  * <script type="text/javascript">
13843  */
13844
13845  
13846 /**
13847  * @class Roo.util.CSS
13848  * Utility class for manipulating CSS rules
13849  * @singleton
13850  */
13851 Roo.util.CSS = function(){
13852         var rules = null;
13853         var doc = document;
13854
13855     var camelRe = /(-[a-z])/gi;
13856     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13857
13858    return {
13859    /**
13860     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13861     * tag and appended to the HEAD of the document.
13862     * @param {String|Object} cssText The text containing the css rules
13863     * @param {String} id An id to add to the stylesheet for later removal
13864     * @return {StyleSheet}
13865     */
13866     createStyleSheet : function(cssText, id){
13867         var ss;
13868         var head = doc.getElementsByTagName("head")[0];
13869         var nrules = doc.createElement("style");
13870         nrules.setAttribute("type", "text/css");
13871         if(id){
13872             nrules.setAttribute("id", id);
13873         }
13874         if (typeof(cssText) != 'string') {
13875             // support object maps..
13876             // not sure if this a good idea.. 
13877             // perhaps it should be merged with the general css handling
13878             // and handle js style props.
13879             var cssTextNew = [];
13880             for(var n in cssText) {
13881                 var citems = [];
13882                 for(var k in cssText[n]) {
13883                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13884                 }
13885                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13886                 
13887             }
13888             cssText = cssTextNew.join("\n");
13889             
13890         }
13891        
13892        
13893        if(Roo.isIE){
13894            head.appendChild(nrules);
13895            ss = nrules.styleSheet;
13896            ss.cssText = cssText;
13897        }else{
13898            try{
13899                 nrules.appendChild(doc.createTextNode(cssText));
13900            }catch(e){
13901                nrules.cssText = cssText; 
13902            }
13903            head.appendChild(nrules);
13904            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13905        }
13906        this.cacheStyleSheet(ss);
13907        return ss;
13908    },
13909
13910    /**
13911     * Removes a style or link tag by id
13912     * @param {String} id The id of the tag
13913     */
13914    removeStyleSheet : function(id){
13915        var existing = doc.getElementById(id);
13916        if(existing){
13917            existing.parentNode.removeChild(existing);
13918        }
13919    },
13920
13921    /**
13922     * Dynamically swaps an existing stylesheet reference for a new one
13923     * @param {String} id The id of an existing link tag to remove
13924     * @param {String} url The href of the new stylesheet to include
13925     */
13926    swapStyleSheet : function(id, url){
13927        this.removeStyleSheet(id);
13928        var ss = doc.createElement("link");
13929        ss.setAttribute("rel", "stylesheet");
13930        ss.setAttribute("type", "text/css");
13931        ss.setAttribute("id", id);
13932        ss.setAttribute("href", url);
13933        doc.getElementsByTagName("head")[0].appendChild(ss);
13934    },
13935    
13936    /**
13937     * Refresh the rule cache if you have dynamically added stylesheets
13938     * @return {Object} An object (hash) of rules indexed by selector
13939     */
13940    refreshCache : function(){
13941        return this.getRules(true);
13942    },
13943
13944    // private
13945    cacheStyleSheet : function(stylesheet){
13946        if(!rules){
13947            rules = {};
13948        }
13949        try{// try catch for cross domain access issue
13950            var ssRules = stylesheet.cssRules || stylesheet.rules;
13951            for(var j = ssRules.length-1; j >= 0; --j){
13952                rules[ssRules[j].selectorText] = ssRules[j];
13953            }
13954        }catch(e){}
13955    },
13956    
13957    /**
13958     * Gets all css rules for the document
13959     * @param {Boolean} refreshCache true to refresh the internal cache
13960     * @return {Object} An object (hash) of rules indexed by selector
13961     */
13962    getRules : function(refreshCache){
13963                 if(rules == null || refreshCache){
13964                         rules = {};
13965                         var ds = doc.styleSheets;
13966                         for(var i =0, len = ds.length; i < len; i++){
13967                             try{
13968                         this.cacheStyleSheet(ds[i]);
13969                     }catch(e){} 
13970                 }
13971                 }
13972                 return rules;
13973         },
13974         
13975         /**
13976     * Gets an an individual CSS rule by selector(s)
13977     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13978     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13979     * @return {CSSRule} The CSS rule or null if one is not found
13980     */
13981    getRule : function(selector, refreshCache){
13982                 var rs = this.getRules(refreshCache);
13983                 if(!(selector instanceof Array)){
13984                     return rs[selector];
13985                 }
13986                 for(var i = 0; i < selector.length; i++){
13987                         if(rs[selector[i]]){
13988                                 return rs[selector[i]];
13989                         }
13990                 }
13991                 return null;
13992         },
13993         
13994         
13995         /**
13996     * Updates a rule property
13997     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13998     * @param {String} property The css property
13999     * @param {String} value The new value for the property
14000     * @return {Boolean} true If a rule was found and updated
14001     */
14002    updateRule : function(selector, property, value){
14003                 if(!(selector instanceof Array)){
14004                         var rule = this.getRule(selector);
14005                         if(rule){
14006                                 rule.style[property.replace(camelRe, camelFn)] = value;
14007                                 return true;
14008                         }
14009                 }else{
14010                         for(var i = 0; i < selector.length; i++){
14011                                 if(this.updateRule(selector[i], property, value)){
14012                                         return true;
14013                                 }
14014                         }
14015                 }
14016                 return false;
14017         }
14018    };   
14019 }();/*
14020  * Based on:
14021  * Ext JS Library 1.1.1
14022  * Copyright(c) 2006-2007, Ext JS, LLC.
14023  *
14024  * Originally Released Under LGPL - original licence link has changed is not relivant.
14025  *
14026  * Fork - LGPL
14027  * <script type="text/javascript">
14028  */
14029
14030  
14031
14032 /**
14033  * @class Roo.util.ClickRepeater
14034  * @extends Roo.util.Observable
14035  * 
14036  * A wrapper class which can be applied to any element. Fires a "click" event while the
14037  * mouse is pressed. The interval between firings may be specified in the config but
14038  * defaults to 10 milliseconds.
14039  * 
14040  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14041  * 
14042  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14043  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14044  * Similar to an autorepeat key delay.
14045  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14046  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14047  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14048  *           "interval" and "delay" are ignored. "immediate" is honored.
14049  * @cfg {Boolean} preventDefault True to prevent the default click event
14050  * @cfg {Boolean} stopDefault True to stop the default click event
14051  * 
14052  * @history
14053  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14054  *     2007-02-02 jvs Renamed to ClickRepeater
14055  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14056  *
14057  *  @constructor
14058  * @param {String/HTMLElement/Element} el The element to listen on
14059  * @param {Object} config
14060  **/
14061 Roo.util.ClickRepeater = function(el, config)
14062 {
14063     this.el = Roo.get(el);
14064     this.el.unselectable();
14065
14066     Roo.apply(this, config);
14067
14068     this.addEvents({
14069     /**
14070      * @event mousedown
14071      * Fires when the mouse button is depressed.
14072      * @param {Roo.util.ClickRepeater} this
14073      */
14074         "mousedown" : true,
14075     /**
14076      * @event click
14077      * Fires on a specified interval during the time the element is pressed.
14078      * @param {Roo.util.ClickRepeater} this
14079      */
14080         "click" : true,
14081     /**
14082      * @event mouseup
14083      * Fires when the mouse key is released.
14084      * @param {Roo.util.ClickRepeater} this
14085      */
14086         "mouseup" : true
14087     });
14088
14089     this.el.on("mousedown", this.handleMouseDown, this);
14090     if(this.preventDefault || this.stopDefault){
14091         this.el.on("click", function(e){
14092             if(this.preventDefault){
14093                 e.preventDefault();
14094             }
14095             if(this.stopDefault){
14096                 e.stopEvent();
14097             }
14098         }, this);
14099     }
14100
14101     // allow inline handler
14102     if(this.handler){
14103         this.on("click", this.handler,  this.scope || this);
14104     }
14105
14106     Roo.util.ClickRepeater.superclass.constructor.call(this);
14107 };
14108
14109 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14110     interval : 20,
14111     delay: 250,
14112     preventDefault : true,
14113     stopDefault : false,
14114     timer : 0,
14115
14116     // private
14117     handleMouseDown : function(){
14118         clearTimeout(this.timer);
14119         this.el.blur();
14120         if(this.pressClass){
14121             this.el.addClass(this.pressClass);
14122         }
14123         this.mousedownTime = new Date();
14124
14125         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14126         this.el.on("mouseout", this.handleMouseOut, this);
14127
14128         this.fireEvent("mousedown", this);
14129         this.fireEvent("click", this);
14130         
14131         this.timer = this.click.defer(this.delay || this.interval, this);
14132     },
14133
14134     // private
14135     click : function(){
14136         this.fireEvent("click", this);
14137         this.timer = this.click.defer(this.getInterval(), this);
14138     },
14139
14140     // private
14141     getInterval: function(){
14142         if(!this.accelerate){
14143             return this.interval;
14144         }
14145         var pressTime = this.mousedownTime.getElapsed();
14146         if(pressTime < 500){
14147             return 400;
14148         }else if(pressTime < 1700){
14149             return 320;
14150         }else if(pressTime < 2600){
14151             return 250;
14152         }else if(pressTime < 3500){
14153             return 180;
14154         }else if(pressTime < 4400){
14155             return 140;
14156         }else if(pressTime < 5300){
14157             return 80;
14158         }else if(pressTime < 6200){
14159             return 50;
14160         }else{
14161             return 10;
14162         }
14163     },
14164
14165     // private
14166     handleMouseOut : function(){
14167         clearTimeout(this.timer);
14168         if(this.pressClass){
14169             this.el.removeClass(this.pressClass);
14170         }
14171         this.el.on("mouseover", this.handleMouseReturn, this);
14172     },
14173
14174     // private
14175     handleMouseReturn : function(){
14176         this.el.un("mouseover", this.handleMouseReturn);
14177         if(this.pressClass){
14178             this.el.addClass(this.pressClass);
14179         }
14180         this.click();
14181     },
14182
14183     // private
14184     handleMouseUp : function(){
14185         clearTimeout(this.timer);
14186         this.el.un("mouseover", this.handleMouseReturn);
14187         this.el.un("mouseout", this.handleMouseOut);
14188         Roo.get(document).un("mouseup", this.handleMouseUp);
14189         this.el.removeClass(this.pressClass);
14190         this.fireEvent("mouseup", this);
14191     }
14192 });/*
14193  * Based on:
14194  * Ext JS Library 1.1.1
14195  * Copyright(c) 2006-2007, Ext JS, LLC.
14196  *
14197  * Originally Released Under LGPL - original licence link has changed is not relivant.
14198  *
14199  * Fork - LGPL
14200  * <script type="text/javascript">
14201  */
14202
14203  
14204 /**
14205  * @class Roo.KeyNav
14206  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14207  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14208  * way to implement custom navigation schemes for any UI component.</p>
14209  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14210  * pageUp, pageDown, del, home, end.  Usage:</p>
14211  <pre><code>
14212 var nav = new Roo.KeyNav("my-element", {
14213     "left" : function(e){
14214         this.moveLeft(e.ctrlKey);
14215     },
14216     "right" : function(e){
14217         this.moveRight(e.ctrlKey);
14218     },
14219     "enter" : function(e){
14220         this.save();
14221     },
14222     scope : this
14223 });
14224 </code></pre>
14225  * @constructor
14226  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14227  * @param {Object} config The config
14228  */
14229 Roo.KeyNav = function(el, config){
14230     this.el = Roo.get(el);
14231     Roo.apply(this, config);
14232     if(!this.disabled){
14233         this.disabled = true;
14234         this.enable();
14235     }
14236 };
14237
14238 Roo.KeyNav.prototype = {
14239     /**
14240      * @cfg {Boolean} disabled
14241      * True to disable this KeyNav instance (defaults to false)
14242      */
14243     disabled : false,
14244     /**
14245      * @cfg {String} defaultEventAction
14246      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14247      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14248      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14249      */
14250     defaultEventAction: "stopEvent",
14251     /**
14252      * @cfg {Boolean} forceKeyDown
14253      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14254      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14255      * handle keydown instead of keypress.
14256      */
14257     forceKeyDown : false,
14258
14259     // private
14260     prepareEvent : function(e){
14261         var k = e.getKey();
14262         var h = this.keyToHandler[k];
14263         //if(h && this[h]){
14264         //    e.stopPropagation();
14265         //}
14266         if(Roo.isSafari && h && k >= 37 && k <= 40){
14267             e.stopEvent();
14268         }
14269     },
14270
14271     // private
14272     relay : function(e){
14273         var k = e.getKey();
14274         var h = this.keyToHandler[k];
14275         if(h && this[h]){
14276             if(this.doRelay(e, this[h], h) !== true){
14277                 e[this.defaultEventAction]();
14278             }
14279         }
14280     },
14281
14282     // private
14283     doRelay : function(e, h, hname){
14284         return h.call(this.scope || this, e);
14285     },
14286
14287     // possible handlers
14288     enter : false,
14289     left : false,
14290     right : false,
14291     up : false,
14292     down : false,
14293     tab : false,
14294     esc : false,
14295     pageUp : false,
14296     pageDown : false,
14297     del : false,
14298     home : false,
14299     end : false,
14300
14301     // quick lookup hash
14302     keyToHandler : {
14303         37 : "left",
14304         39 : "right",
14305         38 : "up",
14306         40 : "down",
14307         33 : "pageUp",
14308         34 : "pageDown",
14309         46 : "del",
14310         36 : "home",
14311         35 : "end",
14312         13 : "enter",
14313         27 : "esc",
14314         9  : "tab"
14315     },
14316
14317         /**
14318          * Enable this KeyNav
14319          */
14320         enable: function(){
14321                 if(this.disabled){
14322             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14323             // the EventObject will normalize Safari automatically
14324             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14325                 this.el.on("keydown", this.relay,  this);
14326             }else{
14327                 this.el.on("keydown", this.prepareEvent,  this);
14328                 this.el.on("keypress", this.relay,  this);
14329             }
14330                     this.disabled = false;
14331                 }
14332         },
14333
14334         /**
14335          * Disable this KeyNav
14336          */
14337         disable: function(){
14338                 if(!this.disabled){
14339                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14340                 this.el.un("keydown", this.relay);
14341             }else{
14342                 this.el.un("keydown", this.prepareEvent);
14343                 this.el.un("keypress", this.relay);
14344             }
14345                     this.disabled = true;
14346                 }
14347         }
14348 };/*
14349  * Based on:
14350  * Ext JS Library 1.1.1
14351  * Copyright(c) 2006-2007, Ext JS, LLC.
14352  *
14353  * Originally Released Under LGPL - original licence link has changed is not relivant.
14354  *
14355  * Fork - LGPL
14356  * <script type="text/javascript">
14357  */
14358
14359  
14360 /**
14361  * @class Roo.KeyMap
14362  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14363  * The constructor accepts the same config object as defined by {@link #addBinding}.
14364  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14365  * combination it will call the function with this signature (if the match is a multi-key
14366  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14367  * A KeyMap can also handle a string representation of keys.<br />
14368  * Usage:
14369  <pre><code>
14370 // map one key by key code
14371 var map = new Roo.KeyMap("my-element", {
14372     key: 13, // or Roo.EventObject.ENTER
14373     fn: myHandler,
14374     scope: myObject
14375 });
14376
14377 // map multiple keys to one action by string
14378 var map = new Roo.KeyMap("my-element", {
14379     key: "a\r\n\t",
14380     fn: myHandler,
14381     scope: myObject
14382 });
14383
14384 // map multiple keys to multiple actions by strings and array of codes
14385 var map = new Roo.KeyMap("my-element", [
14386     {
14387         key: [10,13],
14388         fn: function(){ alert("Return was pressed"); }
14389     }, {
14390         key: "abc",
14391         fn: function(){ alert('a, b or c was pressed'); }
14392     }, {
14393         key: "\t",
14394         ctrl:true,
14395         shift:true,
14396         fn: function(){ alert('Control + shift + tab was pressed.'); }
14397     }
14398 ]);
14399 </code></pre>
14400  * <b>Note: A KeyMap starts enabled</b>
14401  * @constructor
14402  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14403  * @param {Object} config The config (see {@link #addBinding})
14404  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14405  */
14406 Roo.KeyMap = function(el, config, eventName){
14407     this.el  = Roo.get(el);
14408     this.eventName = eventName || "keydown";
14409     this.bindings = [];
14410     if(config){
14411         this.addBinding(config);
14412     }
14413     this.enable();
14414 };
14415
14416 Roo.KeyMap.prototype = {
14417     /**
14418      * True to stop the event from bubbling and prevent the default browser action if the
14419      * key was handled by the KeyMap (defaults to false)
14420      * @type Boolean
14421      */
14422     stopEvent : false,
14423
14424     /**
14425      * Add a new binding to this KeyMap. The following config object properties are supported:
14426      * <pre>
14427 Property    Type             Description
14428 ----------  ---------------  ----------------------------------------------------------------------
14429 key         String/Array     A single keycode or an array of keycodes to handle
14430 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14431 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14432 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14433 fn          Function         The function to call when KeyMap finds the expected key combination
14434 scope       Object           The scope of the callback function
14435 </pre>
14436      *
14437      * Usage:
14438      * <pre><code>
14439 // Create a KeyMap
14440 var map = new Roo.KeyMap(document, {
14441     key: Roo.EventObject.ENTER,
14442     fn: handleKey,
14443     scope: this
14444 });
14445
14446 //Add a new binding to the existing KeyMap later
14447 map.addBinding({
14448     key: 'abc',
14449     shift: true,
14450     fn: handleKey,
14451     scope: this
14452 });
14453 </code></pre>
14454      * @param {Object/Array} config A single KeyMap config or an array of configs
14455      */
14456         addBinding : function(config){
14457         if(config instanceof Array){
14458             for(var i = 0, len = config.length; i < len; i++){
14459                 this.addBinding(config[i]);
14460             }
14461             return;
14462         }
14463         var keyCode = config.key,
14464             shift = config.shift, 
14465             ctrl = config.ctrl, 
14466             alt = config.alt,
14467             fn = config.fn,
14468             scope = config.scope;
14469         if(typeof keyCode == "string"){
14470             var ks = [];
14471             var keyString = keyCode.toUpperCase();
14472             for(var j = 0, len = keyString.length; j < len; j++){
14473                 ks.push(keyString.charCodeAt(j));
14474             }
14475             keyCode = ks;
14476         }
14477         var keyArray = keyCode instanceof Array;
14478         var handler = function(e){
14479             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14480                 var k = e.getKey();
14481                 if(keyArray){
14482                     for(var i = 0, len = keyCode.length; i < len; i++){
14483                         if(keyCode[i] == k){
14484                           if(this.stopEvent){
14485                               e.stopEvent();
14486                           }
14487                           fn.call(scope || window, k, e);
14488                           return;
14489                         }
14490                     }
14491                 }else{
14492                     if(k == keyCode){
14493                         if(this.stopEvent){
14494                            e.stopEvent();
14495                         }
14496                         fn.call(scope || window, k, e);
14497                     }
14498                 }
14499             }
14500         };
14501         this.bindings.push(handler);  
14502         },
14503
14504     /**
14505      * Shorthand for adding a single key listener
14506      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14507      * following options:
14508      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14509      * @param {Function} fn The function to call
14510      * @param {Object} scope (optional) The scope of the function
14511      */
14512     on : function(key, fn, scope){
14513         var keyCode, shift, ctrl, alt;
14514         if(typeof key == "object" && !(key instanceof Array)){
14515             keyCode = key.key;
14516             shift = key.shift;
14517             ctrl = key.ctrl;
14518             alt = key.alt;
14519         }else{
14520             keyCode = key;
14521         }
14522         this.addBinding({
14523             key: keyCode,
14524             shift: shift,
14525             ctrl: ctrl,
14526             alt: alt,
14527             fn: fn,
14528             scope: scope
14529         })
14530     },
14531
14532     // private
14533     handleKeyDown : function(e){
14534             if(this.enabled){ //just in case
14535             var b = this.bindings;
14536             for(var i = 0, len = b.length; i < len; i++){
14537                 b[i].call(this, e);
14538             }
14539             }
14540         },
14541         
14542         /**
14543          * Returns true if this KeyMap is enabled
14544          * @return {Boolean} 
14545          */
14546         isEnabled : function(){
14547             return this.enabled;  
14548         },
14549         
14550         /**
14551          * Enables this KeyMap
14552          */
14553         enable: function(){
14554                 if(!this.enabled){
14555                     this.el.on(this.eventName, this.handleKeyDown, this);
14556                     this.enabled = true;
14557                 }
14558         },
14559
14560         /**
14561          * Disable this KeyMap
14562          */
14563         disable: function(){
14564                 if(this.enabled){
14565                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14566                     this.enabled = false;
14567                 }
14568         }
14569 };/*
14570  * Based on:
14571  * Ext JS Library 1.1.1
14572  * Copyright(c) 2006-2007, Ext JS, LLC.
14573  *
14574  * Originally Released Under LGPL - original licence link has changed is not relivant.
14575  *
14576  * Fork - LGPL
14577  * <script type="text/javascript">
14578  */
14579
14580  
14581 /**
14582  * @class Roo.util.TextMetrics
14583  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14584  * wide, in pixels, a given block of text will be.
14585  * @singleton
14586  */
14587 Roo.util.TextMetrics = function(){
14588     var shared;
14589     return {
14590         /**
14591          * Measures the size of the specified text
14592          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14593          * that can affect the size of the rendered text
14594          * @param {String} text The text to measure
14595          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14596          * in order to accurately measure the text height
14597          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14598          */
14599         measure : function(el, text, fixedWidth){
14600             if(!shared){
14601                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14602             }
14603             shared.bind(el);
14604             shared.setFixedWidth(fixedWidth || 'auto');
14605             return shared.getSize(text);
14606         },
14607
14608         /**
14609          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14610          * the overhead of multiple calls to initialize the style properties on each measurement.
14611          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14612          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14613          * in order to accurately measure the text height
14614          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14615          */
14616         createInstance : function(el, fixedWidth){
14617             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14618         }
14619     };
14620 }();
14621
14622  
14623
14624 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14625     var ml = new Roo.Element(document.createElement('div'));
14626     document.body.appendChild(ml.dom);
14627     ml.position('absolute');
14628     ml.setLeftTop(-1000, -1000);
14629     ml.hide();
14630
14631     if(fixedWidth){
14632         ml.setWidth(fixedWidth);
14633     }
14634      
14635     var instance = {
14636         /**
14637          * Returns the size of the specified text based on the internal element's style and width properties
14638          * @memberOf Roo.util.TextMetrics.Instance#
14639          * @param {String} text The text to measure
14640          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14641          */
14642         getSize : function(text){
14643             ml.update(text);
14644             var s = ml.getSize();
14645             ml.update('');
14646             return s;
14647         },
14648
14649         /**
14650          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14651          * that can affect the size of the rendered text
14652          * @memberOf Roo.util.TextMetrics.Instance#
14653          * @param {String/HTMLElement} el The element, dom node or id
14654          */
14655         bind : function(el){
14656             ml.setStyle(
14657                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14658             );
14659         },
14660
14661         /**
14662          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14663          * to set a fixed width in order to accurately measure the text height.
14664          * @memberOf Roo.util.TextMetrics.Instance#
14665          * @param {Number} width The width to set on the element
14666          */
14667         setFixedWidth : function(width){
14668             ml.setWidth(width);
14669         },
14670
14671         /**
14672          * Returns the measured width of the specified text
14673          * @memberOf Roo.util.TextMetrics.Instance#
14674          * @param {String} text The text to measure
14675          * @return {Number} width The width in pixels
14676          */
14677         getWidth : function(text){
14678             ml.dom.style.width = 'auto';
14679             return this.getSize(text).width;
14680         },
14681
14682         /**
14683          * Returns the measured height of the specified text.  For multiline text, be sure to call
14684          * {@link #setFixedWidth} if necessary.
14685          * @memberOf Roo.util.TextMetrics.Instance#
14686          * @param {String} text The text to measure
14687          * @return {Number} height The height in pixels
14688          */
14689         getHeight : function(text){
14690             return this.getSize(text).height;
14691         }
14692     };
14693
14694     instance.bind(bindTo);
14695
14696     return instance;
14697 };
14698
14699 // backwards compat
14700 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14701  * Based on:
14702  * Ext JS Library 1.1.1
14703  * Copyright(c) 2006-2007, Ext JS, LLC.
14704  *
14705  * Originally Released Under LGPL - original licence link has changed is not relivant.
14706  *
14707  * Fork - LGPL
14708  * <script type="text/javascript">
14709  */
14710
14711 /**
14712  * @class Roo.state.Provider
14713  * Abstract base class for state provider implementations. This class provides methods
14714  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14715  * Provider interface.
14716  */
14717 Roo.state.Provider = function(){
14718     /**
14719      * @event statechange
14720      * Fires when a state change occurs.
14721      * @param {Provider} this This state provider
14722      * @param {String} key The state key which was changed
14723      * @param {String} value The encoded value for the state
14724      */
14725     this.addEvents({
14726         "statechange": true
14727     });
14728     this.state = {};
14729     Roo.state.Provider.superclass.constructor.call(this);
14730 };
14731 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14732     /**
14733      * Returns the current value for a key
14734      * @param {String} name The key name
14735      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14736      * @return {Mixed} The state data
14737      */
14738     get : function(name, defaultValue){
14739         return typeof this.state[name] == "undefined" ?
14740             defaultValue : this.state[name];
14741     },
14742     
14743     /**
14744      * Clears a value from the state
14745      * @param {String} name The key name
14746      */
14747     clear : function(name){
14748         delete this.state[name];
14749         this.fireEvent("statechange", this, name, null);
14750     },
14751     
14752     /**
14753      * Sets the value for a key
14754      * @param {String} name The key name
14755      * @param {Mixed} value The value to set
14756      */
14757     set : function(name, value){
14758         this.state[name] = value;
14759         this.fireEvent("statechange", this, name, value);
14760     },
14761     
14762     /**
14763      * Decodes a string previously encoded with {@link #encodeValue}.
14764      * @param {String} value The value to decode
14765      * @return {Mixed} The decoded value
14766      */
14767     decodeValue : function(cookie){
14768         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14769         var matches = re.exec(unescape(cookie));
14770         if(!matches || !matches[1]) return; // non state cookie
14771         var type = matches[1];
14772         var v = matches[2];
14773         switch(type){
14774             case "n":
14775                 return parseFloat(v);
14776             case "d":
14777                 return new Date(Date.parse(v));
14778             case "b":
14779                 return (v == "1");
14780             case "a":
14781                 var all = [];
14782                 var values = v.split("^");
14783                 for(var i = 0, len = values.length; i < len; i++){
14784                     all.push(this.decodeValue(values[i]));
14785                 }
14786                 return all;
14787            case "o":
14788                 var all = {};
14789                 var values = v.split("^");
14790                 for(var i = 0, len = values.length; i < len; i++){
14791                     var kv = values[i].split("=");
14792                     all[kv[0]] = this.decodeValue(kv[1]);
14793                 }
14794                 return all;
14795            default:
14796                 return v;
14797         }
14798     },
14799     
14800     /**
14801      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14802      * @param {Mixed} value The value to encode
14803      * @return {String} The encoded value
14804      */
14805     encodeValue : function(v){
14806         var enc;
14807         if(typeof v == "number"){
14808             enc = "n:" + v;
14809         }else if(typeof v == "boolean"){
14810             enc = "b:" + (v ? "1" : "0");
14811         }else if(v instanceof Date){
14812             enc = "d:" + v.toGMTString();
14813         }else if(v instanceof Array){
14814             var flat = "";
14815             for(var i = 0, len = v.length; i < len; i++){
14816                 flat += this.encodeValue(v[i]);
14817                 if(i != len-1) flat += "^";
14818             }
14819             enc = "a:" + flat;
14820         }else if(typeof v == "object"){
14821             var flat = "";
14822             for(var key in v){
14823                 if(typeof v[key] != "function"){
14824                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14825                 }
14826             }
14827             enc = "o:" + flat.substring(0, flat.length-1);
14828         }else{
14829             enc = "s:" + v;
14830         }
14831         return escape(enc);        
14832     }
14833 });
14834
14835 /*
14836  * Based on:
14837  * Ext JS Library 1.1.1
14838  * Copyright(c) 2006-2007, Ext JS, LLC.
14839  *
14840  * Originally Released Under LGPL - original licence link has changed is not relivant.
14841  *
14842  * Fork - LGPL
14843  * <script type="text/javascript">
14844  */
14845 /**
14846  * @class Roo.state.Manager
14847  * This is the global state manager. By default all components that are "state aware" check this class
14848  * for state information if you don't pass them a custom state provider. In order for this class
14849  * to be useful, it must be initialized with a provider when your application initializes.
14850  <pre><code>
14851 // in your initialization function
14852 init : function(){
14853    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14854    ...
14855    // supposed you have a {@link Roo.BorderLayout}
14856    var layout = new Roo.BorderLayout(...);
14857    layout.restoreState();
14858    // or a {Roo.BasicDialog}
14859    var dialog = new Roo.BasicDialog(...);
14860    dialog.restoreState();
14861  </code></pre>
14862  * @singleton
14863  */
14864 Roo.state.Manager = function(){
14865     var provider = new Roo.state.Provider();
14866     
14867     return {
14868         /**
14869          * Configures the default state provider for your application
14870          * @param {Provider} stateProvider The state provider to set
14871          */
14872         setProvider : function(stateProvider){
14873             provider = stateProvider;
14874         },
14875         
14876         /**
14877          * Returns the current value for a key
14878          * @param {String} name The key name
14879          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14880          * @return {Mixed} The state data
14881          */
14882         get : function(key, defaultValue){
14883             return provider.get(key, defaultValue);
14884         },
14885         
14886         /**
14887          * Sets the value for a key
14888          * @param {String} name The key name
14889          * @param {Mixed} value The state data
14890          */
14891          set : function(key, value){
14892             provider.set(key, value);
14893         },
14894         
14895         /**
14896          * Clears a value from the state
14897          * @param {String} name The key name
14898          */
14899         clear : function(key){
14900             provider.clear(key);
14901         },
14902         
14903         /**
14904          * Gets the currently configured state provider
14905          * @return {Provider} The state provider
14906          */
14907         getProvider : function(){
14908             return provider;
14909         }
14910     };
14911 }();
14912 /*
14913  * Based on:
14914  * Ext JS Library 1.1.1
14915  * Copyright(c) 2006-2007, Ext JS, LLC.
14916  *
14917  * Originally Released Under LGPL - original licence link has changed is not relivant.
14918  *
14919  * Fork - LGPL
14920  * <script type="text/javascript">
14921  */
14922 /**
14923  * @class Roo.state.CookieProvider
14924  * @extends Roo.state.Provider
14925  * The default Provider implementation which saves state via cookies.
14926  * <br />Usage:
14927  <pre><code>
14928    var cp = new Roo.state.CookieProvider({
14929        path: "/cgi-bin/",
14930        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14931        domain: "roojs.com"
14932    })
14933    Roo.state.Manager.setProvider(cp);
14934  </code></pre>
14935  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14936  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14937  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14938  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14939  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14940  * domain the page is running on including the 'www' like 'www.roojs.com')
14941  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14942  * @constructor
14943  * Create a new CookieProvider
14944  * @param {Object} config The configuration object
14945  */
14946 Roo.state.CookieProvider = function(config){
14947     Roo.state.CookieProvider.superclass.constructor.call(this);
14948     this.path = "/";
14949     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14950     this.domain = null;
14951     this.secure = false;
14952     Roo.apply(this, config);
14953     this.state = this.readCookies();
14954 };
14955
14956 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14957     // private
14958     set : function(name, value){
14959         if(typeof value == "undefined" || value === null){
14960             this.clear(name);
14961             return;
14962         }
14963         this.setCookie(name, value);
14964         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14965     },
14966
14967     // private
14968     clear : function(name){
14969         this.clearCookie(name);
14970         Roo.state.CookieProvider.superclass.clear.call(this, name);
14971     },
14972
14973     // private
14974     readCookies : function(){
14975         var cookies = {};
14976         var c = document.cookie + ";";
14977         var re = /\s?(.*?)=(.*?);/g;
14978         var matches;
14979         while((matches = re.exec(c)) != null){
14980             var name = matches[1];
14981             var value = matches[2];
14982             if(name && name.substring(0,3) == "ys-"){
14983                 cookies[name.substr(3)] = this.decodeValue(value);
14984             }
14985         }
14986         return cookies;
14987     },
14988
14989     // private
14990     setCookie : function(name, value){
14991         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14992            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14993            ((this.path == null) ? "" : ("; path=" + this.path)) +
14994            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14995            ((this.secure == true) ? "; secure" : "");
14996     },
14997
14998     // private
14999     clearCookie : function(name){
15000         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15001            ((this.path == null) ? "" : ("; path=" + this.path)) +
15002            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15003            ((this.secure == true) ? "; secure" : "");
15004     }
15005 });/*
15006  * Based on:
15007  * Ext JS Library 1.1.1
15008  * Copyright(c) 2006-2007, Ext JS, LLC.
15009  *
15010  * Originally Released Under LGPL - original licence link has changed is not relivant.
15011  *
15012  * Fork - LGPL
15013  * <script type="text/javascript">
15014  */
15015  
15016
15017 /**
15018  * @class Roo.ComponentMgr
15019  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15020  * @singleton
15021  */
15022 Roo.ComponentMgr = function(){
15023     var all = new Roo.util.MixedCollection();
15024
15025     return {
15026         /**
15027          * Registers a component.
15028          * @param {Roo.Component} c The component
15029          */
15030         register : function(c){
15031             all.add(c);
15032         },
15033
15034         /**
15035          * Unregisters a component.
15036          * @param {Roo.Component} c The component
15037          */
15038         unregister : function(c){
15039             all.remove(c);
15040         },
15041
15042         /**
15043          * Returns a component by id
15044          * @param {String} id The component id
15045          */
15046         get : function(id){
15047             return all.get(id);
15048         },
15049
15050         /**
15051          * Registers a function that will be called when a specified component is added to ComponentMgr
15052          * @param {String} id The component id
15053          * @param {Funtction} fn The callback function
15054          * @param {Object} scope The scope of the callback
15055          */
15056         onAvailable : function(id, fn, scope){
15057             all.on("add", function(index, o){
15058                 if(o.id == id){
15059                     fn.call(scope || o, o);
15060                     all.un("add", fn, scope);
15061                 }
15062             });
15063         }
15064     };
15065 }();/*
15066  * Based on:
15067  * Ext JS Library 1.1.1
15068  * Copyright(c) 2006-2007, Ext JS, LLC.
15069  *
15070  * Originally Released Under LGPL - original licence link has changed is not relivant.
15071  *
15072  * Fork - LGPL
15073  * <script type="text/javascript">
15074  */
15075  
15076 /**
15077  * @class Roo.Component
15078  * @extends Roo.util.Observable
15079  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15080  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15081  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15082  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15083  * All visual components (widgets) that require rendering into a layout should subclass Component.
15084  * @constructor
15085  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15086  * 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
15087  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15088  */
15089 Roo.Component = function(config){
15090     config = config || {};
15091     if(config.tagName || config.dom || typeof config == "string"){ // element object
15092         config = {el: config, id: config.id || config};
15093     }
15094     this.initialConfig = config;
15095
15096     Roo.apply(this, config);
15097     this.addEvents({
15098         /**
15099          * @event disable
15100          * Fires after the component is disabled.
15101              * @param {Roo.Component} this
15102              */
15103         disable : true,
15104         /**
15105          * @event enable
15106          * Fires after the component is enabled.
15107              * @param {Roo.Component} this
15108              */
15109         enable : true,
15110         /**
15111          * @event beforeshow
15112          * Fires before the component is shown.  Return false to stop the show.
15113              * @param {Roo.Component} this
15114              */
15115         beforeshow : true,
15116         /**
15117          * @event show
15118          * Fires after the component is shown.
15119              * @param {Roo.Component} this
15120              */
15121         show : true,
15122         /**
15123          * @event beforehide
15124          * Fires before the component is hidden. Return false to stop the hide.
15125              * @param {Roo.Component} this
15126              */
15127         beforehide : true,
15128         /**
15129          * @event hide
15130          * Fires after the component is hidden.
15131              * @param {Roo.Component} this
15132              */
15133         hide : true,
15134         /**
15135          * @event beforerender
15136          * Fires before the component is rendered. Return false to stop the render.
15137              * @param {Roo.Component} this
15138              */
15139         beforerender : true,
15140         /**
15141          * @event render
15142          * Fires after the component is rendered.
15143              * @param {Roo.Component} this
15144              */
15145         render : true,
15146         /**
15147          * @event beforedestroy
15148          * Fires before the component is destroyed. Return false to stop the destroy.
15149              * @param {Roo.Component} this
15150              */
15151         beforedestroy : true,
15152         /**
15153          * @event destroy
15154          * Fires after the component is destroyed.
15155              * @param {Roo.Component} this
15156              */
15157         destroy : true
15158     });
15159     if(!this.id){
15160         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15161     }
15162     Roo.ComponentMgr.register(this);
15163     Roo.Component.superclass.constructor.call(this);
15164     this.initComponent();
15165     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15166         this.render(this.renderTo);
15167         delete this.renderTo;
15168     }
15169 };
15170
15171 /** @private */
15172 Roo.Component.AUTO_ID = 1000;
15173
15174 Roo.extend(Roo.Component, Roo.util.Observable, {
15175     /**
15176      * @scope Roo.Component.prototype
15177      * @type {Boolean}
15178      * true if this component is hidden. Read-only.
15179      */
15180     hidden : false,
15181     /**
15182      * @type {Boolean}
15183      * true if this component is disabled. Read-only.
15184      */
15185     disabled : false,
15186     /**
15187      * @type {Boolean}
15188      * true if this component has been rendered. Read-only.
15189      */
15190     rendered : false,
15191     
15192     /** @cfg {String} disableClass
15193      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15194      */
15195     disabledClass : "x-item-disabled",
15196         /** @cfg {Boolean} allowDomMove
15197          * Whether the component can move the Dom node when rendering (defaults to true).
15198          */
15199     allowDomMove : true,
15200     /** @cfg {String} hideMode
15201      * How this component should hidden. Supported values are
15202      * "visibility" (css visibility), "offsets" (negative offset position) and
15203      * "display" (css display) - defaults to "display".
15204      */
15205     hideMode: 'display',
15206
15207     /** @private */
15208     ctype : "Roo.Component",
15209
15210     /**
15211      * @cfg {String} actionMode 
15212      * which property holds the element that used for  hide() / show() / disable() / enable()
15213      * default is 'el' 
15214      */
15215     actionMode : "el",
15216
15217     /** @private */
15218     getActionEl : function(){
15219         return this[this.actionMode];
15220     },
15221
15222     initComponent : Roo.emptyFn,
15223     /**
15224      * If this is a lazy rendering component, render it to its container element.
15225      * @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.
15226      */
15227     render : function(container, position){
15228         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15229             if(!container && this.el){
15230                 this.el = Roo.get(this.el);
15231                 container = this.el.dom.parentNode;
15232                 this.allowDomMove = false;
15233             }
15234             this.container = Roo.get(container);
15235             this.rendered = true;
15236             if(position !== undefined){
15237                 if(typeof position == 'number'){
15238                     position = this.container.dom.childNodes[position];
15239                 }else{
15240                     position = Roo.getDom(position);
15241                 }
15242             }
15243             this.onRender(this.container, position || null);
15244             if(this.cls){
15245                 this.el.addClass(this.cls);
15246                 delete this.cls;
15247             }
15248             if(this.style){
15249                 this.el.applyStyles(this.style);
15250                 delete this.style;
15251             }
15252             this.fireEvent("render", this);
15253             this.afterRender(this.container);
15254             if(this.hidden){
15255                 this.hide();
15256             }
15257             if(this.disabled){
15258                 this.disable();
15259             }
15260         }
15261         return this;
15262     },
15263
15264     /** @private */
15265     // default function is not really useful
15266     onRender : function(ct, position){
15267         if(this.el){
15268             this.el = Roo.get(this.el);
15269             if(this.allowDomMove !== false){
15270                 ct.dom.insertBefore(this.el.dom, position);
15271             }
15272         }
15273     },
15274
15275     /** @private */
15276     getAutoCreate : function(){
15277         var cfg = typeof this.autoCreate == "object" ?
15278                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15279         if(this.id && !cfg.id){
15280             cfg.id = this.id;
15281         }
15282         return cfg;
15283     },
15284
15285     /** @private */
15286     afterRender : Roo.emptyFn,
15287
15288     /**
15289      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15290      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15291      */
15292     destroy : function(){
15293         if(this.fireEvent("beforedestroy", this) !== false){
15294             this.purgeListeners();
15295             this.beforeDestroy();
15296             if(this.rendered){
15297                 this.el.removeAllListeners();
15298                 this.el.remove();
15299                 if(this.actionMode == "container"){
15300                     this.container.remove();
15301                 }
15302             }
15303             this.onDestroy();
15304             Roo.ComponentMgr.unregister(this);
15305             this.fireEvent("destroy", this);
15306         }
15307     },
15308
15309         /** @private */
15310     beforeDestroy : function(){
15311
15312     },
15313
15314         /** @private */
15315         onDestroy : function(){
15316
15317     },
15318
15319     /**
15320      * Returns the underlying {@link Roo.Element}.
15321      * @return {Roo.Element} The element
15322      */
15323     getEl : function(){
15324         return this.el;
15325     },
15326
15327     /**
15328      * Returns the id of this component.
15329      * @return {String}
15330      */
15331     getId : function(){
15332         return this.id;
15333     },
15334
15335     /**
15336      * Try to focus this component.
15337      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15338      * @return {Roo.Component} this
15339      */
15340     focus : function(selectText){
15341         if(this.rendered){
15342             this.el.focus();
15343             if(selectText === true){
15344                 this.el.dom.select();
15345             }
15346         }
15347         return this;
15348     },
15349
15350     /** @private */
15351     blur : function(){
15352         if(this.rendered){
15353             this.el.blur();
15354         }
15355         return this;
15356     },
15357
15358     /**
15359      * Disable this component.
15360      * @return {Roo.Component} this
15361      */
15362     disable : function(){
15363         if(this.rendered){
15364             this.onDisable();
15365         }
15366         this.disabled = true;
15367         this.fireEvent("disable", this);
15368         return this;
15369     },
15370
15371         // private
15372     onDisable : function(){
15373         this.getActionEl().addClass(this.disabledClass);
15374         this.el.dom.disabled = true;
15375     },
15376
15377     /**
15378      * Enable this component.
15379      * @return {Roo.Component} this
15380      */
15381     enable : function(){
15382         if(this.rendered){
15383             this.onEnable();
15384         }
15385         this.disabled = false;
15386         this.fireEvent("enable", this);
15387         return this;
15388     },
15389
15390         // private
15391     onEnable : function(){
15392         this.getActionEl().removeClass(this.disabledClass);
15393         this.el.dom.disabled = false;
15394     },
15395
15396     /**
15397      * Convenience function for setting disabled/enabled by boolean.
15398      * @param {Boolean} disabled
15399      */
15400     setDisabled : function(disabled){
15401         this[disabled ? "disable" : "enable"]();
15402     },
15403
15404     /**
15405      * Show this component.
15406      * @return {Roo.Component} this
15407      */
15408     show: function(){
15409         if(this.fireEvent("beforeshow", this) !== false){
15410             this.hidden = false;
15411             if(this.rendered){
15412                 this.onShow();
15413             }
15414             this.fireEvent("show", this);
15415         }
15416         return this;
15417     },
15418
15419     // private
15420     onShow : function(){
15421         var ae = this.getActionEl();
15422         if(this.hideMode == 'visibility'){
15423             ae.dom.style.visibility = "visible";
15424         }else if(this.hideMode == 'offsets'){
15425             ae.removeClass('x-hidden');
15426         }else{
15427             ae.dom.style.display = "";
15428         }
15429     },
15430
15431     /**
15432      * Hide this component.
15433      * @return {Roo.Component} this
15434      */
15435     hide: function(){
15436         if(this.fireEvent("beforehide", this) !== false){
15437             this.hidden = true;
15438             if(this.rendered){
15439                 this.onHide();
15440             }
15441             this.fireEvent("hide", this);
15442         }
15443         return this;
15444     },
15445
15446     // private
15447     onHide : function(){
15448         var ae = this.getActionEl();
15449         if(this.hideMode == 'visibility'){
15450             ae.dom.style.visibility = "hidden";
15451         }else if(this.hideMode == 'offsets'){
15452             ae.addClass('x-hidden');
15453         }else{
15454             ae.dom.style.display = "none";
15455         }
15456     },
15457
15458     /**
15459      * Convenience function to hide or show this component by boolean.
15460      * @param {Boolean} visible True to show, false to hide
15461      * @return {Roo.Component} this
15462      */
15463     setVisible: function(visible){
15464         if(visible) {
15465             this.show();
15466         }else{
15467             this.hide();
15468         }
15469         return this;
15470     },
15471
15472     /**
15473      * Returns true if this component is visible.
15474      */
15475     isVisible : function(){
15476         return this.getActionEl().isVisible();
15477     },
15478
15479     cloneConfig : function(overrides){
15480         overrides = overrides || {};
15481         var id = overrides.id || Roo.id();
15482         var cfg = Roo.applyIf(overrides, this.initialConfig);
15483         cfg.id = id; // prevent dup id
15484         return new this.constructor(cfg);
15485     }
15486 });/*
15487  * Based on:
15488  * Ext JS Library 1.1.1
15489  * Copyright(c) 2006-2007, Ext JS, LLC.
15490  *
15491  * Originally Released Under LGPL - original licence link has changed is not relivant.
15492  *
15493  * Fork - LGPL
15494  * <script type="text/javascript">
15495  */
15496
15497 /**
15498  * @class Roo.BoxComponent
15499  * @extends Roo.Component
15500  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15501  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15502  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15503  * layout containers.
15504  * @constructor
15505  * @param {Roo.Element/String/Object} config The configuration options.
15506  */
15507 Roo.BoxComponent = function(config){
15508     Roo.Component.call(this, config);
15509     this.addEvents({
15510         /**
15511          * @event resize
15512          * Fires after the component is resized.
15513              * @param {Roo.Component} this
15514              * @param {Number} adjWidth The box-adjusted width that was set
15515              * @param {Number} adjHeight The box-adjusted height that was set
15516              * @param {Number} rawWidth The width that was originally specified
15517              * @param {Number} rawHeight The height that was originally specified
15518              */
15519         resize : true,
15520         /**
15521          * @event move
15522          * Fires after the component is moved.
15523              * @param {Roo.Component} this
15524              * @param {Number} x The new x position
15525              * @param {Number} y The new y position
15526              */
15527         move : true
15528     });
15529 };
15530
15531 Roo.extend(Roo.BoxComponent, Roo.Component, {
15532     // private, set in afterRender to signify that the component has been rendered
15533     boxReady : false,
15534     // private, used to defer height settings to subclasses
15535     deferHeight: false,
15536     /** @cfg {Number} width
15537      * width (optional) size of component
15538      */
15539      /** @cfg {Number} height
15540      * height (optional) size of component
15541      */
15542      
15543     /**
15544      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15545      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15546      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15547      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15548      * @return {Roo.BoxComponent} this
15549      */
15550     setSize : function(w, h){
15551         // support for standard size objects
15552         if(typeof w == 'object'){
15553             h = w.height;
15554             w = w.width;
15555         }
15556         // not rendered
15557         if(!this.boxReady){
15558             this.width = w;
15559             this.height = h;
15560             return this;
15561         }
15562
15563         // prevent recalcs when not needed
15564         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15565             return this;
15566         }
15567         this.lastSize = {width: w, height: h};
15568
15569         var adj = this.adjustSize(w, h);
15570         var aw = adj.width, ah = adj.height;
15571         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15572             var rz = this.getResizeEl();
15573             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15574                 rz.setSize(aw, ah);
15575             }else if(!this.deferHeight && ah !== undefined){
15576                 rz.setHeight(ah);
15577             }else if(aw !== undefined){
15578                 rz.setWidth(aw);
15579             }
15580             this.onResize(aw, ah, w, h);
15581             this.fireEvent('resize', this, aw, ah, w, h);
15582         }
15583         return this;
15584     },
15585
15586     /**
15587      * Gets the current size of the component's underlying element.
15588      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15589      */
15590     getSize : function(){
15591         return this.el.getSize();
15592     },
15593
15594     /**
15595      * Gets the current XY position of the component's underlying element.
15596      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15597      * @return {Array} The XY position of the element (e.g., [100, 200])
15598      */
15599     getPosition : function(local){
15600         if(local === true){
15601             return [this.el.getLeft(true), this.el.getTop(true)];
15602         }
15603         return this.xy || this.el.getXY();
15604     },
15605
15606     /**
15607      * Gets the current box measurements of the component's underlying element.
15608      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15609      * @returns {Object} box An object in the format {x, y, width, height}
15610      */
15611     getBox : function(local){
15612         var s = this.el.getSize();
15613         if(local){
15614             s.x = this.el.getLeft(true);
15615             s.y = this.el.getTop(true);
15616         }else{
15617             var xy = this.xy || this.el.getXY();
15618             s.x = xy[0];
15619             s.y = xy[1];
15620         }
15621         return s;
15622     },
15623
15624     /**
15625      * Sets the current box measurements of the component's underlying element.
15626      * @param {Object} box An object in the format {x, y, width, height}
15627      * @returns {Roo.BoxComponent} this
15628      */
15629     updateBox : function(box){
15630         this.setSize(box.width, box.height);
15631         this.setPagePosition(box.x, box.y);
15632         return this;
15633     },
15634
15635     // protected
15636     getResizeEl : function(){
15637         return this.resizeEl || this.el;
15638     },
15639
15640     // protected
15641     getPositionEl : function(){
15642         return this.positionEl || this.el;
15643     },
15644
15645     /**
15646      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15647      * This method fires the move event.
15648      * @param {Number} left The new left
15649      * @param {Number} top The new top
15650      * @returns {Roo.BoxComponent} this
15651      */
15652     setPosition : function(x, y){
15653         this.x = x;
15654         this.y = y;
15655         if(!this.boxReady){
15656             return this;
15657         }
15658         var adj = this.adjustPosition(x, y);
15659         var ax = adj.x, ay = adj.y;
15660
15661         var el = this.getPositionEl();
15662         if(ax !== undefined || ay !== undefined){
15663             if(ax !== undefined && ay !== undefined){
15664                 el.setLeftTop(ax, ay);
15665             }else if(ax !== undefined){
15666                 el.setLeft(ax);
15667             }else if(ay !== undefined){
15668                 el.setTop(ay);
15669             }
15670             this.onPosition(ax, ay);
15671             this.fireEvent('move', this, ax, ay);
15672         }
15673         return this;
15674     },
15675
15676     /**
15677      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15678      * This method fires the move event.
15679      * @param {Number} x The new x position
15680      * @param {Number} y The new y position
15681      * @returns {Roo.BoxComponent} this
15682      */
15683     setPagePosition : function(x, y){
15684         this.pageX = x;
15685         this.pageY = y;
15686         if(!this.boxReady){
15687             return;
15688         }
15689         if(x === undefined || y === undefined){ // cannot translate undefined points
15690             return;
15691         }
15692         var p = this.el.translatePoints(x, y);
15693         this.setPosition(p.left, p.top);
15694         return this;
15695     },
15696
15697     // private
15698     onRender : function(ct, position){
15699         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15700         if(this.resizeEl){
15701             this.resizeEl = Roo.get(this.resizeEl);
15702         }
15703         if(this.positionEl){
15704             this.positionEl = Roo.get(this.positionEl);
15705         }
15706     },
15707
15708     // private
15709     afterRender : function(){
15710         Roo.BoxComponent.superclass.afterRender.call(this);
15711         this.boxReady = true;
15712         this.setSize(this.width, this.height);
15713         if(this.x || this.y){
15714             this.setPosition(this.x, this.y);
15715         }
15716         if(this.pageX || this.pageY){
15717             this.setPagePosition(this.pageX, this.pageY);
15718         }
15719     },
15720
15721     /**
15722      * Force the component's size to recalculate based on the underlying element's current height and width.
15723      * @returns {Roo.BoxComponent} this
15724      */
15725     syncSize : function(){
15726         delete this.lastSize;
15727         this.setSize(this.el.getWidth(), this.el.getHeight());
15728         return this;
15729     },
15730
15731     /**
15732      * Called after the component is resized, this method is empty by default but can be implemented by any
15733      * subclass that needs to perform custom logic after a resize occurs.
15734      * @param {Number} adjWidth The box-adjusted width that was set
15735      * @param {Number} adjHeight The box-adjusted height that was set
15736      * @param {Number} rawWidth The width that was originally specified
15737      * @param {Number} rawHeight The height that was originally specified
15738      */
15739     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15740
15741     },
15742
15743     /**
15744      * Called after the component is moved, this method is empty by default but can be implemented by any
15745      * subclass that needs to perform custom logic after a move occurs.
15746      * @param {Number} x The new x position
15747      * @param {Number} y The new y position
15748      */
15749     onPosition : function(x, y){
15750
15751     },
15752
15753     // private
15754     adjustSize : function(w, h){
15755         if(this.autoWidth){
15756             w = 'auto';
15757         }
15758         if(this.autoHeight){
15759             h = 'auto';
15760         }
15761         return {width : w, height: h};
15762     },
15763
15764     // private
15765     adjustPosition : function(x, y){
15766         return {x : x, y: y};
15767     }
15768 });/*
15769  * Original code for Roojs - LGPL
15770  * <script type="text/javascript">
15771  */
15772  
15773 /**
15774  * @class Roo.XComponent
15775  * A delayed Element creator...
15776  * Or a way to group chunks of interface together.
15777  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15778  *  used in conjunction with XComponent.build() it will create an instance of each element,
15779  *  then call addxtype() to build the User interface.
15780  * 
15781  * Mypart.xyx = new Roo.XComponent({
15782
15783     parent : 'Mypart.xyz', // empty == document.element.!!
15784     order : '001',
15785     name : 'xxxx'
15786     region : 'xxxx'
15787     disabled : function() {} 
15788      
15789     tree : function() { // return an tree of xtype declared components
15790         var MODULE = this;
15791         return 
15792         {
15793             xtype : 'NestedLayoutPanel',
15794             // technicall
15795         }
15796      ]
15797  *})
15798  *
15799  *
15800  * It can be used to build a big heiracy, with parent etc.
15801  * or you can just use this to render a single compoent to a dom element
15802  * MYPART.render(Roo.Element | String(id) | dom_element )
15803  *
15804  *
15805  * Usage patterns.
15806  *
15807  * Classic Roo
15808  *
15809  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15810  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15811  *
15812  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15813  *
15814  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15815  * - if mulitple topModules exist, the last one is defined as the top module.
15816  *
15817  * Embeded Roo
15818  * 
15819  * When the top level or multiple modules are to embedded into a existing HTML page,
15820  * the parent element can container '#id' of the element where the module will be drawn.
15821  *
15822  * Bootstrap Roo
15823  *
15824  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15825  * it relies more on a include mechanism, where sub modules are included into an outer page.
15826  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15827  * 
15828  * Bootstrap Roo Included elements
15829  *
15830  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15831  * hence confusing the component builder as it thinks there are multiple top level elements. 
15832  *
15833  * 
15834  * 
15835  * @extends Roo.util.Observable
15836  * @constructor
15837  * @param cfg {Object} configuration of component
15838  * 
15839  */
15840 Roo.XComponent = function(cfg) {
15841     Roo.apply(this, cfg);
15842     this.addEvents({ 
15843         /**
15844              * @event built
15845              * Fires when this the componnt is built
15846              * @param {Roo.XComponent} c the component
15847              */
15848         'built' : true
15849         
15850     });
15851     this.region = this.region || 'center'; // default..
15852     Roo.XComponent.register(this);
15853     this.modules = false;
15854     this.el = false; // where the layout goes..
15855     
15856     
15857 }
15858 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15859     /**
15860      * @property el
15861      * The created element (with Roo.factory())
15862      * @type {Roo.Layout}
15863      */
15864     el  : false,
15865     
15866     /**
15867      * @property el
15868      * for BC  - use el in new code
15869      * @type {Roo.Layout}
15870      */
15871     panel : false,
15872     
15873     /**
15874      * @property layout
15875      * for BC  - use el in new code
15876      * @type {Roo.Layout}
15877      */
15878     layout : false,
15879     
15880      /**
15881      * @cfg {Function|boolean} disabled
15882      * If this module is disabled by some rule, return true from the funtion
15883      */
15884     disabled : false,
15885     
15886     /**
15887      * @cfg {String} parent 
15888      * Name of parent element which it get xtype added to..
15889      */
15890     parent: false,
15891     
15892     /**
15893      * @cfg {String} order
15894      * Used to set the order in which elements are created (usefull for multiple tabs)
15895      */
15896     
15897     order : false,
15898     /**
15899      * @cfg {String} name
15900      * String to display while loading.
15901      */
15902     name : false,
15903     /**
15904      * @cfg {String} region
15905      * Region to render component to (defaults to center)
15906      */
15907     region : 'center',
15908     
15909     /**
15910      * @cfg {Array} items
15911      * A single item array - the first element is the root of the tree..
15912      * It's done this way to stay compatible with the Xtype system...
15913      */
15914     items : false,
15915     
15916     /**
15917      * @property _tree
15918      * The method that retuns the tree of parts that make up this compoennt 
15919      * @type {function}
15920      */
15921     _tree  : false,
15922     
15923      /**
15924      * render
15925      * render element to dom or tree
15926      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15927      */
15928     
15929     render : function(el)
15930     {
15931         
15932         el = el || false;
15933         var hp = this.parent ? 1 : 0;
15934         Roo.log(this);
15935         
15936         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15937             // if parent is a '#.....' string, then let's use that..
15938             var ename = this.parent.substr(1);
15939             this.parent = false;
15940             Roo.log(ename);
15941             switch (ename) {
15942                 case 'bootstrap-body' :
15943                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15944                         this.parent = { el :  new  Roo.bootstrap.Body() };
15945                         Roo.log("setting el to doc body");
15946                          
15947                     } else {
15948                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15949                     }
15950                     break;
15951                 case 'bootstrap':
15952                     this.parent = { el : true};
15953                     // fall through
15954                 default:
15955                     el = Roo.get(ename);
15956                     break;
15957             }
15958                 
15959             
15960             if (!el && !this.parent) {
15961                 Roo.log("Warning - element can not be found :#" + ename );
15962                 return;
15963             }
15964         }
15965         Roo.log("EL:");Roo.log(el);
15966         Roo.log("this.parent.el:");Roo.log(this.parent.el);
15967         
15968         var tree = this._tree ? this._tree() : this.tree();
15969
15970         // altertive root elements ??? - we need a better way to indicate these.
15971         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15972                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15973         
15974         if (!this.parent && is_alt) {
15975             //el = Roo.get(document.body);
15976             this.parent = { el : true };
15977         }
15978             
15979             
15980         
15981         if (!this.parent) {
15982             
15983             Roo.log("no parent - creating one");
15984             
15985             el = el ? Roo.get(el) : false;      
15986             
15987             // it's a top level one..
15988             this.parent =  {
15989                 el : new Roo.BorderLayout(el || document.body, {
15990                 
15991                      center: {
15992                          titlebar: false,
15993                          autoScroll:false,
15994                          closeOnTab: true,
15995                          tabPosition: 'top',
15996                           //resizeTabs: true,
15997                          alwaysShowTabs: el && hp? false :  true,
15998                          hideTabs: el || !hp ? true :  false,
15999                          minTabWidth: 140
16000                      }
16001                  })
16002             }
16003         }
16004         
16005                 if (!this.parent.el) {
16006                         // probably an old style ctor, which has been disabled.
16007                         return;
16008                         
16009                 }
16010                 // The 'tree' method is  '_tree now' 
16011             
16012         tree.region = tree.region || this.region;
16013         
16014         if (this.parent.el === true) {
16015             // bootstrap... - body..
16016             this.parent.el = Roo.factory(tree);
16017         }
16018         
16019         this.el = this.parent.el.addxtype(tree);
16020         this.fireEvent('built', this);
16021         
16022         this.panel = this.el;
16023         this.layout = this.panel.layout;
16024                 this.parentLayout = this.parent.layout  || false;  
16025          
16026     }
16027     
16028 });
16029
16030 Roo.apply(Roo.XComponent, {
16031     /**
16032      * @property  hideProgress
16033      * true to disable the building progress bar.. usefull on single page renders.
16034      * @type Boolean
16035      */
16036     hideProgress : false,
16037     /**
16038      * @property  buildCompleted
16039      * True when the builder has completed building the interface.
16040      * @type Boolean
16041      */
16042     buildCompleted : false,
16043      
16044     /**
16045      * @property  topModule
16046      * the upper most module - uses document.element as it's constructor.
16047      * @type Object
16048      */
16049      
16050     topModule  : false,
16051       
16052     /**
16053      * @property  modules
16054      * array of modules to be created by registration system.
16055      * @type {Array} of Roo.XComponent
16056      */
16057     
16058     modules : [],
16059     /**
16060      * @property  elmodules
16061      * array of modules to be created by which use #ID 
16062      * @type {Array} of Roo.XComponent
16063      */
16064      
16065     elmodules : [],
16066
16067      /**
16068      * @property  build_from_html
16069      * Build elements from html - used by bootstrap HTML stuff 
16070      *    - this is cleared after build is completed
16071      * @type {boolean} true  (default false)
16072      */
16073      
16074     build_from_html : false,
16075
16076     /**
16077      * Register components to be built later.
16078      *
16079      * This solves the following issues
16080      * - Building is not done on page load, but after an authentication process has occured.
16081      * - Interface elements are registered on page load
16082      * - Parent Interface elements may not be loaded before child, so this handles that..
16083      * 
16084      *
16085      * example:
16086      * 
16087      * MyApp.register({
16088           order : '000001',
16089           module : 'Pman.Tab.projectMgr',
16090           region : 'center',
16091           parent : 'Pman.layout',
16092           disabled : false,  // or use a function..
16093         })
16094      
16095      * * @param {Object} details about module
16096      */
16097     register : function(obj) {
16098                 
16099         Roo.XComponent.event.fireEvent('register', obj);
16100         switch(typeof(obj.disabled) ) {
16101                 
16102             case 'undefined':
16103                 break;
16104             
16105             case 'function':
16106                 if ( obj.disabled() ) {
16107                         return;
16108                 }
16109                 break;
16110             
16111             default:
16112                 if (obj.disabled) {
16113                         return;
16114                 }
16115                 break;
16116         }
16117                 
16118         this.modules.push(obj);
16119          
16120     },
16121     /**
16122      * convert a string to an object..
16123      * eg. 'AAA.BBB' -> finds AAA.BBB
16124
16125      */
16126     
16127     toObject : function(str)
16128     {
16129         if (!str || typeof(str) == 'object') {
16130             return str;
16131         }
16132         if (str.substring(0,1) == '#') {
16133             return str;
16134         }
16135
16136         var ar = str.split('.');
16137         var rt, o;
16138         rt = ar.shift();
16139             /** eval:var:o */
16140         try {
16141             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16142         } catch (e) {
16143             throw "Module not found : " + str;
16144         }
16145         
16146         if (o === false) {
16147             throw "Module not found : " + str;
16148         }
16149         Roo.each(ar, function(e) {
16150             if (typeof(o[e]) == 'undefined') {
16151                 throw "Module not found : " + str;
16152             }
16153             o = o[e];
16154         });
16155         
16156         return o;
16157         
16158     },
16159     
16160     
16161     /**
16162      * move modules into their correct place in the tree..
16163      * 
16164      */
16165     preBuild : function ()
16166     {
16167         var _t = this;
16168         Roo.each(this.modules , function (obj)
16169         {
16170             Roo.XComponent.event.fireEvent('beforebuild', obj);
16171             
16172             var opar = obj.parent;
16173             try { 
16174                 obj.parent = this.toObject(opar);
16175             } catch(e) {
16176                 Roo.log("parent:toObject failed: " + e.toString());
16177                 return;
16178             }
16179             
16180             if (!obj.parent) {
16181                 Roo.debug && Roo.log("GOT top level module");
16182                 Roo.debug && Roo.log(obj);
16183                 obj.modules = new Roo.util.MixedCollection(false, 
16184                     function(o) { return o.order + '' }
16185                 );
16186                 this.topModule = obj;
16187                 return;
16188             }
16189                         // parent is a string (usually a dom element name..)
16190             if (typeof(obj.parent) == 'string') {
16191                 this.elmodules.push(obj);
16192                 return;
16193             }
16194             if (obj.parent.constructor != Roo.XComponent) {
16195                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16196             }
16197             if (!obj.parent.modules) {
16198                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16199                     function(o) { return o.order + '' }
16200                 );
16201             }
16202             if (obj.parent.disabled) {
16203                 obj.disabled = true;
16204             }
16205             obj.parent.modules.add(obj);
16206         }, this);
16207     },
16208     
16209      /**
16210      * make a list of modules to build.
16211      * @return {Array} list of modules. 
16212      */ 
16213     
16214     buildOrder : function()
16215     {
16216         var _this = this;
16217         var cmp = function(a,b) {   
16218             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16219         };
16220         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16221             throw "No top level modules to build";
16222         }
16223         
16224         // make a flat list in order of modules to build.
16225         var mods = this.topModule ? [ this.topModule ] : [];
16226                 
16227         
16228         // elmodules (is a list of DOM based modules )
16229         Roo.each(this.elmodules, function(e) {
16230             mods.push(e);
16231             if (!this.topModule &&
16232                 typeof(e.parent) == 'string' &&
16233                 e.parent.substring(0,1) == '#' &&
16234                 Roo.get(e.parent.substr(1))
16235                ) {
16236                 
16237                 _this.topModule = e;
16238             }
16239             
16240         });
16241
16242         
16243         // add modules to their parents..
16244         var addMod = function(m) {
16245             Roo.debug && Roo.log("build Order: add: " + m.name);
16246                 
16247             mods.push(m);
16248             if (m.modules && !m.disabled) {
16249                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16250                 m.modules.keySort('ASC',  cmp );
16251                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16252     
16253                 m.modules.each(addMod);
16254             } else {
16255                 Roo.debug && Roo.log("build Order: no child modules");
16256             }
16257             // not sure if this is used any more..
16258             if (m.finalize) {
16259                 m.finalize.name = m.name + " (clean up) ";
16260                 mods.push(m.finalize);
16261             }
16262             
16263         }
16264         if (this.topModule && this.topModule.modules) { 
16265             this.topModule.modules.keySort('ASC',  cmp );
16266             this.topModule.modules.each(addMod);
16267         } 
16268         return mods;
16269     },
16270     
16271      /**
16272      * Build the registered modules.
16273      * @param {Object} parent element.
16274      * @param {Function} optional method to call after module has been added.
16275      * 
16276      */ 
16277    
16278     build : function(opts) 
16279     {
16280         
16281         if (typeof(opts) != 'undefined') {
16282             Roo.apply(this,opts);
16283         }
16284         
16285         this.preBuild();
16286         var mods = this.buildOrder();
16287       
16288         //this.allmods = mods;
16289         //Roo.debug && Roo.log(mods);
16290         //return;
16291         if (!mods.length) { // should not happen
16292             throw "NO modules!!!";
16293         }
16294         
16295         
16296         var msg = "Building Interface...";
16297         // flash it up as modal - so we store the mask!?
16298         if (!this.hideProgress && Roo.MessageBox) {
16299             Roo.MessageBox.show({ title: 'loading' });
16300             Roo.MessageBox.show({
16301                title: "Please wait...",
16302                msg: msg,
16303                width:450,
16304                progress:true,
16305                closable:false,
16306                modal: false
16307               
16308             });
16309         }
16310         var total = mods.length;
16311         
16312         var _this = this;
16313         var progressRun = function() {
16314             if (!mods.length) {
16315                 Roo.debug && Roo.log('hide?');
16316                 if (!this.hideProgress && Roo.MessageBox) {
16317                     Roo.MessageBox.hide();
16318                 }
16319                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16320                 
16321                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16322                 
16323                 // THE END...
16324                 return false;   
16325             }
16326             
16327             var m = mods.shift();
16328             
16329             
16330             Roo.debug && Roo.log(m);
16331             // not sure if this is supported any more.. - modules that are are just function
16332             if (typeof(m) == 'function') { 
16333                 m.call(this);
16334                 return progressRun.defer(10, _this);
16335             } 
16336             
16337             
16338             msg = "Building Interface " + (total  - mods.length) + 
16339                     " of " + total + 
16340                     (m.name ? (' - ' + m.name) : '');
16341                         Roo.debug && Roo.log(msg);
16342             if (!this.hideProgress &&  Roo.MessageBox) { 
16343                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16344             }
16345             
16346          
16347             // is the module disabled?
16348             var disabled = (typeof(m.disabled) == 'function') ?
16349                 m.disabled.call(m.module.disabled) : m.disabled;    
16350             
16351             
16352             if (disabled) {
16353                 return progressRun(); // we do not update the display!
16354             }
16355             
16356             // now build 
16357             
16358                         
16359                         
16360             m.render();
16361             // it's 10 on top level, and 1 on others??? why...
16362             return progressRun.defer(10, _this);
16363              
16364         }
16365         progressRun.defer(1, _this);
16366      
16367         
16368         
16369     },
16370         
16371         
16372         /**
16373          * Event Object.
16374          *
16375          *
16376          */
16377         event: false, 
16378     /**
16379          * wrapper for event.on - aliased later..  
16380          * Typically use to register a event handler for register:
16381          *
16382          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16383          *
16384          */
16385     on : false
16386    
16387     
16388     
16389 });
16390
16391 Roo.XComponent.event = new Roo.util.Observable({
16392                 events : { 
16393                         /**
16394                          * @event register
16395                          * Fires when an Component is registered,
16396                          * set the disable property on the Component to stop registration.
16397                          * @param {Roo.XComponent} c the component being registerd.
16398                          * 
16399                          */
16400                         'register' : true,
16401             /**
16402                          * @event beforebuild
16403                          * Fires before each Component is built
16404                          * can be used to apply permissions.
16405                          * @param {Roo.XComponent} c the component being registerd.
16406                          * 
16407                          */
16408                         'beforebuild' : true,
16409                         /**
16410                          * @event buildcomplete
16411                          * Fires on the top level element when all elements have been built
16412                          * @param {Roo.XComponent} the top level component.
16413                          */
16414                         'buildcomplete' : true
16415                         
16416                 }
16417 });
16418
16419 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16420