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         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isTouch =  (function() {
67             try {  
68                 document.createEvent("TouchEvent");  
69                 return true;  
70             } catch (e) {  
71                 return false;  
72             } 
73             
74         })();
75     // remove css image flicker
76         if(isIE && !isIE7){
77         try{
78             document.execCommand("BackgroundImageCache", false, true);
79         }catch(e){}
80     }
81     
82     Roo.apply(Roo, {
83         /**
84          * True if the browser is in strict mode
85          * @type Boolean
86          */
87         isStrict : isStrict,
88         /**
89          * True if the page is running over SSL
90          * @type Boolean
91          */
92         isSecure : isSecure,
93         /**
94          * True when the document is fully initialized and ready for action
95          * @type Boolean
96          */
97         isReady : false,
98         /**
99          * Turn on debugging output (currently only the factory uses this)
100          * @type Boolean
101          */
102         
103         debug: false,
104
105         /**
106          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
107          * @type Boolean
108          */
109         enableGarbageCollector : true,
110
111         /**
112          * True to automatically purge event listeners after uncaching an element (defaults to false).
113          * Note: this only happens if enableGarbageCollector is true.
114          * @type Boolean
115          */
116         enableListenerCollection:false,
117
118         /**
119          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
120          * the IE insecure content warning (defaults to javascript:false).
121          * @type String
122          */
123         SSL_SECURE_URL : "javascript:false",
124
125         /**
126          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
127          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
128          * @type String
129          */
130         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
131
132         emptyFn : function(){},
133         
134         /**
135          * Copies all the properties of config to obj if they don't already exist.
136          * @param {Object} obj The receiver of the properties
137          * @param {Object} config The source of the properties
138          * @return {Object} returns obj
139          */
140         applyIf : function(o, c){
141             if(o && c){
142                 for(var p in c){
143                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
144                 }
145             }
146             return o;
147         },
148
149         /**
150          * Applies event listeners to elements by selectors when the document is ready.
151          * The event name is specified with an @ suffix.
152 <pre><code>
153 Roo.addBehaviors({
154    // add a listener for click on all anchors in element with id foo
155    '#foo a@click' : function(e, t){
156        // do something
157    },
158
159    // add the same listener to multiple selectors (separated by comma BEFORE the @)
160    '#foo a, #bar span.some-class@mouseover' : function(){
161        // do something
162    }
163 });
164 </code></pre>
165          * @param {Object} obj The list of behaviors to apply
166          */
167         addBehaviors : function(o){
168             if(!Roo.isReady){
169                 Roo.onReady(function(){
170                     Roo.addBehaviors(o);
171                 });
172                 return;
173             }
174             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
175             for(var b in o){
176                 var parts = b.split('@');
177                 if(parts[1]){ // for Object prototype breakers
178                     var s = parts[0];
179                     if(!cache[s]){
180                         cache[s] = Roo.select(s);
181                     }
182                     cache[s].on(parts[1], o[b]);
183                 }
184             }
185             cache = null;
186         },
187
188         /**
189          * Generates unique ids. If the element already has an id, it is unchanged
190          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
191          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
192          * @return {String} The generated Id.
193          */
194         id : function(el, prefix){
195             prefix = prefix || "roo-gen";
196             el = Roo.getDom(el);
197             var id = prefix + (++idSeed);
198             return el ? (el.id ? el.id : (el.id = id)) : id;
199         },
200          
201        
202         /**
203          * Extends one class with another class and optionally overrides members with the passed literal. This class
204          * also adds the function "override()" to the class that can be used to override
205          * members on an instance.
206          * @param {Object} subclass The class inheriting the functionality
207          * @param {Object} superclass The class being extended
208          * @param {Object} overrides (optional) A literal with members
209          * @method extend
210          */
211         extend : function(){
212             // inline overrides
213             var io = function(o){
214                 for(var m in o){
215                     this[m] = o[m];
216                 }
217             };
218             return function(sb, sp, overrides){
219                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
220                     overrides = sp;
221                     sp = sb;
222                     sb = function(){sp.apply(this, arguments);};
223                 }
224                 var F = function(){}, sbp, spp = sp.prototype;
225                 F.prototype = spp;
226                 sbp = sb.prototype = new F();
227                 sbp.constructor=sb;
228                 sb.superclass=spp;
229                 
230                 if(spp.constructor == Object.prototype.constructor){
231                     spp.constructor=sp;
232                    
233                 }
234                 
235                 sb.override = function(o){
236                     Roo.override(sb, o);
237                 };
238                 sbp.override = io;
239                 Roo.override(sb, overrides);
240                 return sb;
241             };
242         }(),
243
244         /**
245          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
246          * Usage:<pre><code>
247 Roo.override(MyClass, {
248     newMethod1: function(){
249         // etc.
250     },
251     newMethod2: function(foo){
252         // etc.
253     }
254 });
255  </code></pre>
256          * @param {Object} origclass The class to override
257          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
258          * containing one or more methods.
259          * @method override
260          */
261         override : function(origclass, overrides){
262             if(overrides){
263                 var p = origclass.prototype;
264                 for(var method in overrides){
265                     p[method] = overrides[method];
266                 }
267             }
268         },
269         /**
270          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
271          * <pre><code>
272 Roo.namespace('Company', 'Company.data');
273 Company.Widget = function() { ... }
274 Company.data.CustomStore = function(config) { ... }
275 </code></pre>
276          * @param {String} namespace1
277          * @param {String} namespace2
278          * @param {String} etc
279          * @method namespace
280          */
281         namespace : function(){
282             var a=arguments, o=null, i, j, d, rt;
283             for (i=0; i<a.length; ++i) {
284                 d=a[i].split(".");
285                 rt = d[0];
286                 /** eval:var:o */
287                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
288                 for (j=1; j<d.length; ++j) {
289                     o[d[j]]=o[d[j]] || {};
290                     o=o[d[j]];
291                 }
292             }
293         },
294         /**
295          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
296          * <pre><code>
297 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
298 Roo.factory(conf, Roo.data);
299 </code></pre>
300          * @param {String} classname
301          * @param {String} namespace (optional)
302          * @method factory
303          */
304          
305         factory : function(c, ns)
306         {
307             // no xtype, no ns or c.xns - or forced off by c.xns
308             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
309                 return c;
310             }
311             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
312             if (c.constructor == ns[c.xtype]) {// already created...
313                 return c;
314             }
315             if (ns[c.xtype]) {
316                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
317                 var ret = new ns[c.xtype](c);
318                 ret.xns = false;
319                 return ret;
320             }
321             c.xns = false; // prevent recursion..
322             return c;
323         },
324          /**
325          * Logs to console if it can.
326          *
327          * @param {String|Object} string
328          * @method log
329          */
330         log : function(s)
331         {
332             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
333                 return; // alerT?
334             }
335             console.log(s);
336             
337         },
338         /**
339          * 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.
340          * @param {Object} o
341          * @return {String}
342          */
343         urlEncode : function(o){
344             if(!o){
345                 return "";
346             }
347             var buf = [];
348             for(var key in o){
349                 var ov = o[key], k = Roo.encodeURIComponent(key);
350                 var type = typeof ov;
351                 if(type == 'undefined'){
352                     buf.push(k, "=&");
353                 }else if(type != "function" && type != "object"){
354                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
355                 }else if(ov instanceof Array){
356                     if (ov.length) {
357                             for(var i = 0, len = ov.length; i < len; i++) {
358                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
359                             }
360                         } else {
361                             buf.push(k, "=&");
362                         }
363                 }
364             }
365             buf.pop();
366             return buf.join("");
367         },
368          /**
369          * Safe version of encodeURIComponent
370          * @param {String} data 
371          * @return {String} 
372          */
373         
374         encodeURIComponent : function (data)
375         {
376             try {
377                 return encodeURIComponent(data);
378             } catch(e) {} // should be an uri encode error.
379             
380             if (data == '' || data == null){
381                return '';
382             }
383             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
384             function nibble_to_hex(nibble){
385                 var chars = '0123456789ABCDEF';
386                 return chars.charAt(nibble);
387             }
388             data = data.toString();
389             var buffer = '';
390             for(var i=0; i<data.length; i++){
391                 var c = data.charCodeAt(i);
392                 var bs = new Array();
393                 if (c > 0x10000){
394                         // 4 bytes
395                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
396                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
397                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
398                     bs[3] = 0x80 | (c & 0x3F);
399                 }else if (c > 0x800){
400                          // 3 bytes
401                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
402                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
403                     bs[2] = 0x80 | (c & 0x3F);
404                 }else if (c > 0x80){
405                        // 2 bytes
406                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
407                     bs[1] = 0x80 | (c & 0x3F);
408                 }else{
409                         // 1 byte
410                     bs[0] = c;
411                 }
412                 for(var j=0; j<bs.length; j++){
413                     var b = bs[j];
414                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
415                             + nibble_to_hex(b &0x0F);
416                     buffer += '%'+hex;
417                }
418             }
419             return buffer;    
420              
421         },
422
423         /**
424          * 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]}.
425          * @param {String} string
426          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
427          * @return {Object} A literal with members
428          */
429         urlDecode : function(string, overwrite){
430             if(!string || !string.length){
431                 return {};
432             }
433             var obj = {};
434             var pairs = string.split('&');
435             var pair, name, value;
436             for(var i = 0, len = pairs.length; i < len; i++){
437                 pair = pairs[i].split('=');
438                 name = decodeURIComponent(pair[0]);
439                 value = decodeURIComponent(pair[1]);
440                 if(overwrite !== true){
441                     if(typeof obj[name] == "undefined"){
442                         obj[name] = value;
443                     }else if(typeof obj[name] == "string"){
444                         obj[name] = [obj[name]];
445                         obj[name].push(value);
446                     }else{
447                         obj[name].push(value);
448                     }
449                 }else{
450                     obj[name] = value;
451                 }
452             }
453             return obj;
454         },
455
456         /**
457          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
458          * passed array is not really an array, your function is called once with it.
459          * The supplied function is called with (Object item, Number index, Array allItems).
460          * @param {Array/NodeList/Mixed} array
461          * @param {Function} fn
462          * @param {Object} scope
463          */
464         each : function(array, fn, scope){
465             if(typeof array.length == "undefined" || typeof array == "string"){
466                 array = [array];
467             }
468             for(var i = 0, len = array.length; i < len; i++){
469                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
470             }
471         },
472
473         // deprecated
474         combine : function(){
475             var as = arguments, l = as.length, r = [];
476             for(var i = 0; i < l; i++){
477                 var a = as[i];
478                 if(a instanceof Array){
479                     r = r.concat(a);
480                 }else if(a.length !== undefined && !a.substr){
481                     r = r.concat(Array.prototype.slice.call(a, 0));
482                 }else{
483                     r.push(a);
484                 }
485             }
486             return r;
487         },
488
489         /**
490          * Escapes the passed string for use in a regular expression
491          * @param {String} str
492          * @return {String}
493          */
494         escapeRe : function(s) {
495             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
496         },
497
498         // internal
499         callback : function(cb, scope, args, delay){
500             if(typeof cb == "function"){
501                 if(delay){
502                     cb.defer(delay, scope, args || []);
503                 }else{
504                     cb.apply(scope, args || []);
505                 }
506             }
507         },
508
509         /**
510          * Return the dom node for the passed string (id), dom node, or Roo.Element
511          * @param {String/HTMLElement/Roo.Element} el
512          * @return HTMLElement
513          */
514         getDom : function(el){
515             if(!el){
516                 return null;
517             }
518             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
519         },
520
521         /**
522         * Shorthand for {@link Roo.ComponentMgr#get}
523         * @param {String} id
524         * @return Roo.Component
525         */
526         getCmp : function(id){
527             return Roo.ComponentMgr.get(id);
528         },
529          
530         num : function(v, defaultValue){
531             if(typeof v != 'number'){
532                 return defaultValue;
533             }
534             return v;
535         },
536
537         destroy : function(){
538             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
539                 var as = a[i];
540                 if(as){
541                     if(as.dom){
542                         as.removeAllListeners();
543                         as.remove();
544                         continue;
545                     }
546                     if(typeof as.purgeListeners == 'function'){
547                         as.purgeListeners();
548                     }
549                     if(typeof as.destroy == 'function'){
550                         as.destroy();
551                     }
552                 }
553             }
554         },
555
556         // inpired by a similar function in mootools library
557         /**
558          * Returns the type of object that is passed in. If the object passed in is null or undefined it
559          * return false otherwise it returns one of the following values:<ul>
560          * <li><b>string</b>: If the object passed is a string</li>
561          * <li><b>number</b>: If the object passed is a number</li>
562          * <li><b>boolean</b>: If the object passed is a boolean value</li>
563          * <li><b>function</b>: If the object passed is a function reference</li>
564          * <li><b>object</b>: If the object passed is an object</li>
565          * <li><b>array</b>: If the object passed is an array</li>
566          * <li><b>regexp</b>: If the object passed is a regular expression</li>
567          * <li><b>element</b>: If the object passed is a DOM Element</li>
568          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
569          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
570          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
571          * @param {Mixed} object
572          * @return {String}
573          */
574         type : function(o){
575             if(o === undefined || o === null){
576                 return false;
577             }
578             if(o.htmlElement){
579                 return 'element';
580             }
581             var t = typeof o;
582             if(t == 'object' && o.nodeName) {
583                 switch(o.nodeType) {
584                     case 1: return 'element';
585                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
586                 }
587             }
588             if(t == 'object' || t == 'function') {
589                 switch(o.constructor) {
590                     case Array: return 'array';
591                     case RegExp: return 'regexp';
592                 }
593                 if(typeof o.length == 'number' && typeof o.item == 'function') {
594                     return 'nodelist';
595                 }
596             }
597             return t;
598         },
599
600         /**
601          * Returns true if the passed value is null, undefined or an empty string (optional).
602          * @param {Mixed} value The value to test
603          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
604          * @return {Boolean}
605          */
606         isEmpty : function(v, allowBlank){
607             return v === null || v === undefined || (!allowBlank ? v === '' : false);
608         },
609         
610         /** @type Boolean */
611         isOpera : isOpera,
612         /** @type Boolean */
613         isSafari : isSafari,
614         /** @type Boolean */
615         isFirefox : isFirefox,
616         /** @type Boolean */
617         isIE : isIE,
618         /** @type Boolean */
619         isIE7 : isIE7,
620         /** @type Boolean */
621         isIE11 : isIE11,
622         /** @type Boolean */
623         isGecko : isGecko,
624         /** @type Boolean */
625         isBorderBox : isBorderBox,
626         /** @type Boolean */
627         isWindows : isWindows,
628         /** @type Boolean */
629         isLinux : isLinux,
630         /** @type Boolean */
631         isMac : isMac,
632         /** @type Boolean */
633         isTouch : isTouch,
634
635         /**
636          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
637          * you may want to set this to true.
638          * @type Boolean
639          */
640         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
641         
642         
643                 
644         /**
645          * Selects a single element as a Roo Element
646          * This is about as close as you can get to jQuery's $('do crazy stuff')
647          * @param {String} selector The selector/xpath query
648          * @param {Node} root (optional) The start of the query (defaults to document).
649          * @return {Roo.Element}
650          */
651         selectNode : function(selector, root) 
652         {
653             var node = Roo.DomQuery.selectNode(selector,root);
654             return node ? Roo.get(node) : new Roo.Element(false);
655         }
656         
657     });
658
659
660 })();
661
662 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
663                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
664                 "Roo.app", "Roo.ux",
665                 "Roo.bootstrap",
666                 "Roo.bootstrap.dash");
667 /*
668  * Based on:
669  * Ext JS Library 1.1.1
670  * Copyright(c) 2006-2007, Ext JS, LLC.
671  *
672  * Originally Released Under LGPL - original licence link has changed is not relivant.
673  *
674  * Fork - LGPL
675  * <script type="text/javascript">
676  */
677
678 (function() {    
679     // wrappedn so fnCleanup is not in global scope...
680     if(Roo.isIE) {
681         function fnCleanUp() {
682             var p = Function.prototype;
683             delete p.createSequence;
684             delete p.defer;
685             delete p.createDelegate;
686             delete p.createCallback;
687             delete p.createInterceptor;
688
689             window.detachEvent("onunload", fnCleanUp);
690         }
691         window.attachEvent("onunload", fnCleanUp);
692     }
693 })();
694
695
696 /**
697  * @class Function
698  * These functions are available on every Function object (any JavaScript function).
699  */
700 Roo.apply(Function.prototype, {
701      /**
702      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
703      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
704      * Will create a function that is bound to those 2 args.
705      * @return {Function} The new function
706     */
707     createCallback : function(/*args...*/){
708         // make args available, in function below
709         var args = arguments;
710         var method = this;
711         return function() {
712             return method.apply(window, args);
713         };
714     },
715
716     /**
717      * Creates a delegate (callback) that sets the scope to obj.
718      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
719      * Will create a function that is automatically scoped to this.
720      * @param {Object} obj (optional) The object for which the scope is set
721      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
722      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
723      *                                             if a number the args are inserted at the specified position
724      * @return {Function} The new function
725      */
726     createDelegate : function(obj, args, appendArgs){
727         var method = this;
728         return function() {
729             var callArgs = args || arguments;
730             if(appendArgs === true){
731                 callArgs = Array.prototype.slice.call(arguments, 0);
732                 callArgs = callArgs.concat(args);
733             }else if(typeof appendArgs == "number"){
734                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
735                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
736                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
737             }
738             return method.apply(obj || window, callArgs);
739         };
740     },
741
742     /**
743      * Calls this function after the number of millseconds specified.
744      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
745      * @param {Object} obj (optional) The object for which the scope is set
746      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
747      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
748      *                                             if a number the args are inserted at the specified position
749      * @return {Number} The timeout id that can be used with clearTimeout
750      */
751     defer : function(millis, obj, args, appendArgs){
752         var fn = this.createDelegate(obj, args, appendArgs);
753         if(millis){
754             return setTimeout(fn, millis);
755         }
756         fn();
757         return 0;
758     },
759     /**
760      * Create a combined function call sequence of the original function + the passed function.
761      * The resulting function returns the results of the original function.
762      * The passed fcn is called with the parameters of the original function
763      * @param {Function} fcn The function to sequence
764      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
765      * @return {Function} The new function
766      */
767     createSequence : function(fcn, scope){
768         if(typeof fcn != "function"){
769             return this;
770         }
771         var method = this;
772         return function() {
773             var retval = method.apply(this || window, arguments);
774             fcn.apply(scope || this || window, arguments);
775             return retval;
776         };
777     },
778
779     /**
780      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
781      * The resulting function returns the results of the original function.
782      * The passed fcn is called with the parameters of the original function.
783      * @addon
784      * @param {Function} fcn The function to call before the original
785      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
786      * @return {Function} The new function
787      */
788     createInterceptor : function(fcn, scope){
789         if(typeof fcn != "function"){
790             return this;
791         }
792         var method = this;
793         return function() {
794             fcn.target = this;
795             fcn.method = method;
796             if(fcn.apply(scope || this || window, arguments) === false){
797                 return;
798             }
799             return method.apply(this || window, arguments);
800         };
801     }
802 });
803 /*
804  * Based on:
805  * Ext JS Library 1.1.1
806  * Copyright(c) 2006-2007, Ext JS, LLC.
807  *
808  * Originally Released Under LGPL - original licence link has changed is not relivant.
809  *
810  * Fork - LGPL
811  * <script type="text/javascript">
812  */
813
814 Roo.applyIf(String, {
815     
816     /** @scope String */
817     
818     /**
819      * Escapes the passed string for ' and \
820      * @param {String} string The string to escape
821      * @return {String} The escaped string
822      * @static
823      */
824     escape : function(string) {
825         return string.replace(/('|\\)/g, "\\$1");
826     },
827
828     /**
829      * Pads the left side of a string with a specified character.  This is especially useful
830      * for normalizing number and date strings.  Example usage:
831      * <pre><code>
832 var s = String.leftPad('123', 5, '0');
833 // s now contains the string: '00123'
834 </code></pre>
835      * @param {String} string The original string
836      * @param {Number} size The total length of the output string
837      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
838      * @return {String} The padded string
839      * @static
840      */
841     leftPad : function (val, size, ch) {
842         var result = new String(val);
843         if(ch === null || ch === undefined || ch === '') {
844             ch = " ";
845         }
846         while (result.length < size) {
847             result = ch + result;
848         }
849         return result;
850     },
851
852     /**
853      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
854      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
855      * <pre><code>
856 var cls = 'my-class', text = 'Some text';
857 var s = String.format('<div class="{0}">{1}</div>', cls, text);
858 // s now contains the string: '<div class="my-class">Some text</div>'
859 </code></pre>
860      * @param {String} string The tokenized string to be formatted
861      * @param {String} value1 The value to replace token {0}
862      * @param {String} value2 Etc...
863      * @return {String} The formatted string
864      * @static
865      */
866     format : function(format){
867         var args = Array.prototype.slice.call(arguments, 1);
868         return format.replace(/\{(\d+)\}/g, function(m, i){
869             return Roo.util.Format.htmlEncode(args[i]);
870         });
871     }
872 });
873
874 /**
875  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
876  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
877  * they are already different, the first value passed in is returned.  Note that this method returns the new value
878  * but does not change the current string.
879  * <pre><code>
880 // alternate sort directions
881 sort = sort.toggle('ASC', 'DESC');
882
883 // instead of conditional logic:
884 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
885 </code></pre>
886  * @param {String} value The value to compare to the current string
887  * @param {String} other The new value to use if the string already equals the first value passed in
888  * @return {String} The new value
889  */
890  
891 String.prototype.toggle = function(value, other){
892     return this == value ? other : value;
893 };/*
894  * Based on:
895  * Ext JS Library 1.1.1
896  * Copyright(c) 2006-2007, Ext JS, LLC.
897  *
898  * Originally Released Under LGPL - original licence link has changed is not relivant.
899  *
900  * Fork - LGPL
901  * <script type="text/javascript">
902  */
903
904  /**
905  * @class Number
906  */
907 Roo.applyIf(Number.prototype, {
908     /**
909      * Checks whether or not the current number is within a desired range.  If the number is already within the
910      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
911      * exceeded.  Note that this method returns the constrained value but does not change the current number.
912      * @param {Number} min The minimum number in the range
913      * @param {Number} max The maximum number in the range
914      * @return {Number} The constrained value if outside the range, otherwise the current value
915      */
916     constrain : function(min, max){
917         return Math.min(Math.max(this, min), max);
918     }
919 });/*
920  * Based on:
921  * Ext JS Library 1.1.1
922  * Copyright(c) 2006-2007, Ext JS, LLC.
923  *
924  * Originally Released Under LGPL - original licence link has changed is not relivant.
925  *
926  * Fork - LGPL
927  * <script type="text/javascript">
928  */
929  /**
930  * @class Array
931  */
932 Roo.applyIf(Array.prototype, {
933     /**
934      * 
935      * Checks whether or not the specified object exists in the array.
936      * @param {Object} o The object to check for
937      * @return {Number} The index of o in the array (or -1 if it is not found)
938      */
939     indexOf : function(o){
940        for (var i = 0, len = this.length; i < len; i++){
941               if(this[i] == o) return i;
942        }
943            return -1;
944     },
945
946     /**
947      * Removes the specified object from the array.  If the object is not found nothing happens.
948      * @param {Object} o The object to remove
949      */
950     remove : function(o){
951        var index = this.indexOf(o);
952        if(index != -1){
953            this.splice(index, 1);
954        }
955     },
956     /**
957      * Map (JS 1.6 compatibility)
958      * @param {Function} function  to call
959      */
960     map : function(fun )
961     {
962         var len = this.length >>> 0;
963         if (typeof fun != "function")
964             throw new TypeError();
965
966         var res = new Array(len);
967         var thisp = arguments[1];
968         for (var i = 0; i < len; i++)
969         {
970             if (i in this)
971                 res[i] = fun.call(thisp, this[i], i, this);
972         }
973
974         return res;
975     }
976     
977 });
978
979
980  /*
981  * Based on:
982  * Ext JS Library 1.1.1
983  * Copyright(c) 2006-2007, Ext JS, LLC.
984  *
985  * Originally Released Under LGPL - original licence link has changed is not relivant.
986  *
987  * Fork - LGPL
988  * <script type="text/javascript">
989  */
990
991 /**
992  * @class Date
993  *
994  * The date parsing and format syntax is a subset of
995  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
996  * supported will provide results equivalent to their PHP versions.
997  *
998  * Following is the list of all currently supported formats:
999  *<pre>
1000 Sample date:
1001 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1002
1003 Format  Output      Description
1004 ------  ----------  --------------------------------------------------------------
1005   d      10         Day of the month, 2 digits with leading zeros
1006   D      Wed        A textual representation of a day, three letters
1007   j      10         Day of the month without leading zeros
1008   l      Wednesday  A full textual representation of the day of the week
1009   S      th         English ordinal day of month suffix, 2 chars (use with j)
1010   w      3          Numeric representation of the day of the week
1011   z      9          The julian date, or day of the year (0-365)
1012   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1013   F      January    A full textual representation of the month
1014   m      01         Numeric representation of a month, with leading zeros
1015   M      Jan        Month name abbreviation, three letters
1016   n      1          Numeric representation of a month, without leading zeros
1017   t      31         Number of days in the given month
1018   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1019   Y      2007       A full numeric representation of a year, 4 digits
1020   y      07         A two digit representation of a year
1021   a      pm         Lowercase Ante meridiem and Post meridiem
1022   A      PM         Uppercase Ante meridiem and Post meridiem
1023   g      3          12-hour format of an hour without leading zeros
1024   G      15         24-hour format of an hour without leading zeros
1025   h      03         12-hour format of an hour with leading zeros
1026   H      15         24-hour format of an hour with leading zeros
1027   i      05         Minutes with leading zeros
1028   s      01         Seconds, with leading zeros
1029   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1030   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1031   T      CST        Timezone setting of the machine running the code
1032   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1033 </pre>
1034  *
1035  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1036  * <pre><code>
1037 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1038 document.write(dt.format('Y-m-d'));                         //2007-01-10
1039 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1040 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
1041  </code></pre>
1042  *
1043  * Here are some standard date/time patterns that you might find helpful.  They
1044  * are not part of the source of Date.js, but to use them you can simply copy this
1045  * block of code into any script that is included after Date.js and they will also become
1046  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1047  * <pre><code>
1048 Date.patterns = {
1049     ISO8601Long:"Y-m-d H:i:s",
1050     ISO8601Short:"Y-m-d",
1051     ShortDate: "n/j/Y",
1052     LongDate: "l, F d, Y",
1053     FullDateTime: "l, F d, Y g:i:s A",
1054     MonthDay: "F d",
1055     ShortTime: "g:i A",
1056     LongTime: "g:i:s A",
1057     SortableDateTime: "Y-m-d\\TH:i:s",
1058     UniversalSortableDateTime: "Y-m-d H:i:sO",
1059     YearMonth: "F, Y"
1060 };
1061 </code></pre>
1062  *
1063  * Example usage:
1064  * <pre><code>
1065 var dt = new Date();
1066 document.write(dt.format(Date.patterns.ShortDate));
1067  </code></pre>
1068  */
1069
1070 /*
1071  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1072  * They generate precompiled functions from date formats instead of parsing and
1073  * processing the pattern every time you format a date.  These functions are available
1074  * on every Date object (any javascript function).
1075  *
1076  * The original article and download are here:
1077  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1078  *
1079  */
1080  
1081  
1082  // was in core
1083 /**
1084  Returns the number of milliseconds between this date and date
1085  @param {Date} date (optional) Defaults to now
1086  @return {Number} The diff in milliseconds
1087  @member Date getElapsed
1088  */
1089 Date.prototype.getElapsed = function(date) {
1090         return Math.abs((date || new Date()).getTime()-this.getTime());
1091 };
1092 // was in date file..
1093
1094
1095 // private
1096 Date.parseFunctions = {count:0};
1097 // private
1098 Date.parseRegexes = [];
1099 // private
1100 Date.formatFunctions = {count:0};
1101
1102 // private
1103 Date.prototype.dateFormat = function(format) {
1104     if (Date.formatFunctions[format] == null) {
1105         Date.createNewFormat(format);
1106     }
1107     var func = Date.formatFunctions[format];
1108     return this[func]();
1109 };
1110
1111
1112 /**
1113  * Formats a date given the supplied format string
1114  * @param {String} format The format string
1115  * @return {String} The formatted date
1116  * @method
1117  */
1118 Date.prototype.format = Date.prototype.dateFormat;
1119
1120 // private
1121 Date.createNewFormat = function(format) {
1122     var funcName = "format" + Date.formatFunctions.count++;
1123     Date.formatFunctions[format] = funcName;
1124     var code = "Date.prototype." + funcName + " = function(){return ";
1125     var special = false;
1126     var ch = '';
1127     for (var i = 0; i < format.length; ++i) {
1128         ch = format.charAt(i);
1129         if (!special && ch == "\\") {
1130             special = true;
1131         }
1132         else if (special) {
1133             special = false;
1134             code += "'" + String.escape(ch) + "' + ";
1135         }
1136         else {
1137             code += Date.getFormatCode(ch);
1138         }
1139     }
1140     /** eval:var:zzzzzzzzzzzzz */
1141     eval(code.substring(0, code.length - 3) + ";}");
1142 };
1143
1144 // private
1145 Date.getFormatCode = function(character) {
1146     switch (character) {
1147     case "d":
1148         return "String.leftPad(this.getDate(), 2, '0') + ";
1149     case "D":
1150         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1151     case "j":
1152         return "this.getDate() + ";
1153     case "l":
1154         return "Date.dayNames[this.getDay()] + ";
1155     case "S":
1156         return "this.getSuffix() + ";
1157     case "w":
1158         return "this.getDay() + ";
1159     case "z":
1160         return "this.getDayOfYear() + ";
1161     case "W":
1162         return "this.getWeekOfYear() + ";
1163     case "F":
1164         return "Date.monthNames[this.getMonth()] + ";
1165     case "m":
1166         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1167     case "M":
1168         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1169     case "n":
1170         return "(this.getMonth() + 1) + ";
1171     case "t":
1172         return "this.getDaysInMonth() + ";
1173     case "L":
1174         return "(this.isLeapYear() ? 1 : 0) + ";
1175     case "Y":
1176         return "this.getFullYear() + ";
1177     case "y":
1178         return "('' + this.getFullYear()).substring(2, 4) + ";
1179     case "a":
1180         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1181     case "A":
1182         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1183     case "g":
1184         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1185     case "G":
1186         return "this.getHours() + ";
1187     case "h":
1188         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1189     case "H":
1190         return "String.leftPad(this.getHours(), 2, '0') + ";
1191     case "i":
1192         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1193     case "s":
1194         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1195     case "O":
1196         return "this.getGMTOffset() + ";
1197     case "P":
1198         return "this.getGMTColonOffset() + ";
1199     case "T":
1200         return "this.getTimezone() + ";
1201     case "Z":
1202         return "(this.getTimezoneOffset() * -60) + ";
1203     default:
1204         return "'" + String.escape(character) + "' + ";
1205     }
1206 };
1207
1208 /**
1209  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1210  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1211  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1212  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1213  * string or the parse operation will fail.
1214  * Example Usage:
1215 <pre><code>
1216 //dt = Fri May 25 2007 (current date)
1217 var dt = new Date();
1218
1219 //dt = Thu May 25 2006 (today's month/day in 2006)
1220 dt = Date.parseDate("2006", "Y");
1221
1222 //dt = Sun Jan 15 2006 (all date parts specified)
1223 dt = Date.parseDate("2006-1-15", "Y-m-d");
1224
1225 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1226 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1227 </code></pre>
1228  * @param {String} input The unparsed date as a string
1229  * @param {String} format The format the date is in
1230  * @return {Date} The parsed date
1231  * @static
1232  */
1233 Date.parseDate = function(input, format) {
1234     if (Date.parseFunctions[format] == null) {
1235         Date.createParser(format);
1236     }
1237     var func = Date.parseFunctions[format];
1238     return Date[func](input);
1239 };
1240 /**
1241  * @private
1242  */
1243
1244 Date.createParser = function(format) {
1245     var funcName = "parse" + Date.parseFunctions.count++;
1246     var regexNum = Date.parseRegexes.length;
1247     var currentGroup = 1;
1248     Date.parseFunctions[format] = funcName;
1249
1250     var code = "Date." + funcName + " = function(input){\n"
1251         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1252         + "var d = new Date();\n"
1253         + "y = d.getFullYear();\n"
1254         + "m = d.getMonth();\n"
1255         + "d = d.getDate();\n"
1256         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1257         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1258         + "if (results && results.length > 0) {";
1259     var regex = "";
1260
1261     var special = false;
1262     var ch = '';
1263     for (var i = 0; i < format.length; ++i) {
1264         ch = format.charAt(i);
1265         if (!special && ch == "\\") {
1266             special = true;
1267         }
1268         else if (special) {
1269             special = false;
1270             regex += String.escape(ch);
1271         }
1272         else {
1273             var obj = Date.formatCodeToRegex(ch, currentGroup);
1274             currentGroup += obj.g;
1275             regex += obj.s;
1276             if (obj.g && obj.c) {
1277                 code += obj.c;
1278             }
1279         }
1280     }
1281
1282     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1283         + "{v = new Date(y, m, d, h, i, s);}\n"
1284         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1285         + "{v = new Date(y, m, d, h, i);}\n"
1286         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1287         + "{v = new Date(y, m, d, h);}\n"
1288         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1289         + "{v = new Date(y, m, d);}\n"
1290         + "else if (y >= 0 && m >= 0)\n"
1291         + "{v = new Date(y, m);}\n"
1292         + "else if (y >= 0)\n"
1293         + "{v = new Date(y);}\n"
1294         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1295         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1296         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1297         + ";}";
1298
1299     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1300     /** eval:var:zzzzzzzzzzzzz */
1301     eval(code);
1302 };
1303
1304 // private
1305 Date.formatCodeToRegex = function(character, currentGroup) {
1306     switch (character) {
1307     case "D":
1308         return {g:0,
1309         c:null,
1310         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1311     case "j":
1312         return {g:1,
1313             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1314             s:"(\\d{1,2})"}; // day of month without leading zeroes
1315     case "d":
1316         return {g:1,
1317             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1318             s:"(\\d{2})"}; // day of month with leading zeroes
1319     case "l":
1320         return {g:0,
1321             c:null,
1322             s:"(?:" + Date.dayNames.join("|") + ")"};
1323     case "S":
1324         return {g:0,
1325             c:null,
1326             s:"(?:st|nd|rd|th)"};
1327     case "w":
1328         return {g:0,
1329             c:null,
1330             s:"\\d"};
1331     case "z":
1332         return {g:0,
1333             c:null,
1334             s:"(?:\\d{1,3})"};
1335     case "W":
1336         return {g:0,
1337             c:null,
1338             s:"(?:\\d{2})"};
1339     case "F":
1340         return {g:1,
1341             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1342             s:"(" + Date.monthNames.join("|") + ")"};
1343     case "M":
1344         return {g:1,
1345             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1346             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1347     case "n":
1348         return {g:1,
1349             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1350             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1351     case "m":
1352         return {g:1,
1353             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1354             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1355     case "t":
1356         return {g:0,
1357             c:null,
1358             s:"\\d{1,2}"};
1359     case "L":
1360         return {g:0,
1361             c:null,
1362             s:"(?:1|0)"};
1363     case "Y":
1364         return {g:1,
1365             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1366             s:"(\\d{4})"};
1367     case "y":
1368         return {g:1,
1369             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1370                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1371             s:"(\\d{1,2})"};
1372     case "a":
1373         return {g:1,
1374             c:"if (results[" + currentGroup + "] == 'am') {\n"
1375                 + "if (h == 12) { h = 0; }\n"
1376                 + "} else { if (h < 12) { h += 12; }}",
1377             s:"(am|pm)"};
1378     case "A":
1379         return {g:1,
1380             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1381                 + "if (h == 12) { h = 0; }\n"
1382                 + "} else { if (h < 12) { h += 12; }}",
1383             s:"(AM|PM)"};
1384     case "g":
1385     case "G":
1386         return {g:1,
1387             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1388             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1389     case "h":
1390     case "H":
1391         return {g:1,
1392             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1393             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1394     case "i":
1395         return {g:1,
1396             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1397             s:"(\\d{2})"};
1398     case "s":
1399         return {g:1,
1400             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1401             s:"(\\d{2})"};
1402     case "O":
1403         return {g:1,
1404             c:[
1405                 "o = results[", currentGroup, "];\n",
1406                 "var sn = o.substring(0,1);\n", // get + / - sign
1407                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1408                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1409                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1410                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1411             ].join(""),
1412             s:"([+\-]\\d{2,4})"};
1413     
1414     
1415     case "P":
1416         return {g:1,
1417                 c:[
1418                    "o = results[", currentGroup, "];\n",
1419                    "var sn = o.substring(0,1);\n",
1420                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1421                    "var mn = o.substring(4,6) % 60;\n",
1422                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1423                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1424             ].join(""),
1425             s:"([+\-]\\d{4})"};
1426     case "T":
1427         return {g:0,
1428             c:null,
1429             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1430     case "Z":
1431         return {g:1,
1432             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1433                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1434             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1435     default:
1436         return {g:0,
1437             c:null,
1438             s:String.escape(character)};
1439     }
1440 };
1441
1442 /**
1443  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1444  * @return {String} The abbreviated timezone name (e.g. 'CST')
1445  */
1446 Date.prototype.getTimezone = function() {
1447     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1448 };
1449
1450 /**
1451  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1452  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1453  */
1454 Date.prototype.getGMTOffset = function() {
1455     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1456         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1457         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1458 };
1459
1460 /**
1461  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1462  * @return {String} 2-characters representing hours and 2-characters representing minutes
1463  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1464  */
1465 Date.prototype.getGMTColonOffset = function() {
1466         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1467                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1468                 + ":"
1469                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1470 }
1471
1472 /**
1473  * Get the numeric day number of the year, adjusted for leap year.
1474  * @return {Number} 0 through 364 (365 in leap years)
1475  */
1476 Date.prototype.getDayOfYear = function() {
1477     var num = 0;
1478     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1479     for (var i = 0; i < this.getMonth(); ++i) {
1480         num += Date.daysInMonth[i];
1481     }
1482     return num + this.getDate() - 1;
1483 };
1484
1485 /**
1486  * Get the string representation of the numeric week number of the year
1487  * (equivalent to the format specifier 'W').
1488  * @return {String} '00' through '52'
1489  */
1490 Date.prototype.getWeekOfYear = function() {
1491     // Skip to Thursday of this week
1492     var now = this.getDayOfYear() + (4 - this.getDay());
1493     // Find the first Thursday of the year
1494     var jan1 = new Date(this.getFullYear(), 0, 1);
1495     var then = (7 - jan1.getDay() + 4);
1496     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1497 };
1498
1499 /**
1500  * Whether or not the current date is in a leap year.
1501  * @return {Boolean} True if the current date is in a leap year, else false
1502  */
1503 Date.prototype.isLeapYear = function() {
1504     var year = this.getFullYear();
1505     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1506 };
1507
1508 /**
1509  * Get the first day of the current month, adjusted for leap year.  The returned value
1510  * is the numeric day index within the week (0-6) which can be used in conjunction with
1511  * the {@link #monthNames} array to retrieve the textual day name.
1512  * Example:
1513  *<pre><code>
1514 var dt = new Date('1/10/2007');
1515 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1516 </code></pre>
1517  * @return {Number} The day number (0-6)
1518  */
1519 Date.prototype.getFirstDayOfMonth = function() {
1520     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1521     return (day < 0) ? (day + 7) : day;
1522 };
1523
1524 /**
1525  * Get the last day of the current month, adjusted for leap year.  The returned value
1526  * is the numeric day index within the week (0-6) which can be used in conjunction with
1527  * the {@link #monthNames} array to retrieve the textual day name.
1528  * Example:
1529  *<pre><code>
1530 var dt = new Date('1/10/2007');
1531 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1532 </code></pre>
1533  * @return {Number} The day number (0-6)
1534  */
1535 Date.prototype.getLastDayOfMonth = function() {
1536     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1537     return (day < 0) ? (day + 7) : day;
1538 };
1539
1540
1541 /**
1542  * Get the first date of this date's month
1543  * @return {Date}
1544  */
1545 Date.prototype.getFirstDateOfMonth = function() {
1546     return new Date(this.getFullYear(), this.getMonth(), 1);
1547 };
1548
1549 /**
1550  * Get the last date of this date's month
1551  * @return {Date}
1552  */
1553 Date.prototype.getLastDateOfMonth = function() {
1554     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1555 };
1556 /**
1557  * Get the number of days in the current month, adjusted for leap year.
1558  * @return {Number} The number of days in the month
1559  */
1560 Date.prototype.getDaysInMonth = function() {
1561     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1562     return Date.daysInMonth[this.getMonth()];
1563 };
1564
1565 /**
1566  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1567  * @return {String} 'st, 'nd', 'rd' or 'th'
1568  */
1569 Date.prototype.getSuffix = function() {
1570     switch (this.getDate()) {
1571         case 1:
1572         case 21:
1573         case 31:
1574             return "st";
1575         case 2:
1576         case 22:
1577             return "nd";
1578         case 3:
1579         case 23:
1580             return "rd";
1581         default:
1582             return "th";
1583     }
1584 };
1585
1586 // private
1587 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1588
1589 /**
1590  * An array of textual month names.
1591  * Override these values for international dates, for example...
1592  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1593  * @type Array
1594  * @static
1595  */
1596 Date.monthNames =
1597    ["January",
1598     "February",
1599     "March",
1600     "April",
1601     "May",
1602     "June",
1603     "July",
1604     "August",
1605     "September",
1606     "October",
1607     "November",
1608     "December"];
1609
1610 /**
1611  * An array of textual day names.
1612  * Override these values for international dates, for example...
1613  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1614  * @type Array
1615  * @static
1616  */
1617 Date.dayNames =
1618    ["Sunday",
1619     "Monday",
1620     "Tuesday",
1621     "Wednesday",
1622     "Thursday",
1623     "Friday",
1624     "Saturday"];
1625
1626 // private
1627 Date.y2kYear = 50;
1628 // private
1629 Date.monthNumbers = {
1630     Jan:0,
1631     Feb:1,
1632     Mar:2,
1633     Apr:3,
1634     May:4,
1635     Jun:5,
1636     Jul:6,
1637     Aug:7,
1638     Sep:8,
1639     Oct:9,
1640     Nov:10,
1641     Dec:11};
1642
1643 /**
1644  * Creates and returns a new Date instance with the exact same date value as the called instance.
1645  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1646  * variable will also be changed.  When the intention is to create a new variable that will not
1647  * modify the original instance, you should create a clone.
1648  *
1649  * Example of correctly cloning a date:
1650  * <pre><code>
1651 //wrong way:
1652 var orig = new Date('10/1/2006');
1653 var copy = orig;
1654 copy.setDate(5);
1655 document.write(orig);  //returns 'Thu Oct 05 2006'!
1656
1657 //correct way:
1658 var orig = new Date('10/1/2006');
1659 var copy = orig.clone();
1660 copy.setDate(5);
1661 document.write(orig);  //returns 'Thu Oct 01 2006'
1662 </code></pre>
1663  * @return {Date} The new Date instance
1664  */
1665 Date.prototype.clone = function() {
1666         return new Date(this.getTime());
1667 };
1668
1669 /**
1670  * Clears any time information from this date
1671  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1672  @return {Date} this or the clone
1673  */
1674 Date.prototype.clearTime = function(clone){
1675     if(clone){
1676         return this.clone().clearTime();
1677     }
1678     this.setHours(0);
1679     this.setMinutes(0);
1680     this.setSeconds(0);
1681     this.setMilliseconds(0);
1682     return this;
1683 };
1684
1685 // private
1686 // safari setMonth is broken
1687 if(Roo.isSafari){
1688     Date.brokenSetMonth = Date.prototype.setMonth;
1689         Date.prototype.setMonth = function(num){
1690                 if(num <= -1){
1691                         var n = Math.ceil(-num);
1692                         var back_year = Math.ceil(n/12);
1693                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1694                         this.setFullYear(this.getFullYear() - back_year);
1695                         return Date.brokenSetMonth.call(this, month);
1696                 } else {
1697                         return Date.brokenSetMonth.apply(this, arguments);
1698                 }
1699         };
1700 }
1701
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MILLI = "ms";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.SECOND = "s";
1710 /** Date interval constant 
1711 * @static 
1712 * @type String */
1713 Date.MINUTE = "mi";
1714 /** Date interval constant 
1715 * @static 
1716 * @type String */
1717 Date.HOUR = "h";
1718 /** Date interval constant 
1719 * @static 
1720 * @type String */
1721 Date.DAY = "d";
1722 /** Date interval constant 
1723 * @static 
1724 * @type String */
1725 Date.MONTH = "mo";
1726 /** Date interval constant 
1727 * @static 
1728 * @type String */
1729 Date.YEAR = "y";
1730
1731 /**
1732  * Provides a convenient method of performing basic date arithmetic.  This method
1733  * does not modify the Date instance being called - it creates and returns
1734  * a new Date instance containing the resulting date value.
1735  *
1736  * Examples:
1737  * <pre><code>
1738 //Basic usage:
1739 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1740 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1741
1742 //Negative values will subtract correctly:
1743 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1744 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1745
1746 //You can even chain several calls together in one line!
1747 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1748 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1749  </code></pre>
1750  *
1751  * @param {String} interval   A valid date interval enum value
1752  * @param {Number} value      The amount to add to the current date
1753  * @return {Date} The new Date instance
1754  */
1755 Date.prototype.add = function(interval, value){
1756   var d = this.clone();
1757   if (!interval || value === 0) return d;
1758   switch(interval.toLowerCase()){
1759     case Date.MILLI:
1760       d.setMilliseconds(this.getMilliseconds() + value);
1761       break;
1762     case Date.SECOND:
1763       d.setSeconds(this.getSeconds() + value);
1764       break;
1765     case Date.MINUTE:
1766       d.setMinutes(this.getMinutes() + value);
1767       break;
1768     case Date.HOUR:
1769       d.setHours(this.getHours() + value);
1770       break;
1771     case Date.DAY:
1772       d.setDate(this.getDate() + value);
1773       break;
1774     case Date.MONTH:
1775       var day = this.getDate();
1776       if(day > 28){
1777           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1778       }
1779       d.setDate(day);
1780       d.setMonth(this.getMonth() + value);
1781       break;
1782     case Date.YEAR:
1783       d.setFullYear(this.getFullYear() + value);
1784       break;
1785   }
1786   return d;
1787 };
1788 /*
1789  * Based on:
1790  * Ext JS Library 1.1.1
1791  * Copyright(c) 2006-2007, Ext JS, LLC.
1792  *
1793  * Originally Released Under LGPL - original licence link has changed is not relivant.
1794  *
1795  * Fork - LGPL
1796  * <script type="text/javascript">
1797  */
1798
1799 /**
1800  * @class Roo.lib.Dom
1801  * @static
1802  * 
1803  * Dom utils (from YIU afaik)
1804  * 
1805  **/
1806 Roo.lib.Dom = {
1807     /**
1808      * Get the view width
1809      * @param {Boolean} full True will get the full document, otherwise it's the view width
1810      * @return {Number} The width
1811      */
1812      
1813     getViewWidth : function(full) {
1814         return full ? this.getDocumentWidth() : this.getViewportWidth();
1815     },
1816     /**
1817      * Get the view height
1818      * @param {Boolean} full True will get the full document, otherwise it's the view height
1819      * @return {Number} The height
1820      */
1821     getViewHeight : function(full) {
1822         return full ? this.getDocumentHeight() : this.getViewportHeight();
1823     },
1824
1825     getDocumentHeight: function() {
1826         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1827         return Math.max(scrollHeight, this.getViewportHeight());
1828     },
1829
1830     getDocumentWidth: function() {
1831         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1832         return Math.max(scrollWidth, this.getViewportWidth());
1833     },
1834
1835     getViewportHeight: function() {
1836         var height = self.innerHeight;
1837         var mode = document.compatMode;
1838
1839         if ((mode || Roo.isIE) && !Roo.isOpera) {
1840             height = (mode == "CSS1Compat") ?
1841                      document.documentElement.clientHeight :
1842                      document.body.clientHeight;
1843         }
1844
1845         return height;
1846     },
1847
1848     getViewportWidth: function() {
1849         var width = self.innerWidth;
1850         var mode = document.compatMode;
1851
1852         if (mode || Roo.isIE) {
1853             width = (mode == "CSS1Compat") ?
1854                     document.documentElement.clientWidth :
1855                     document.body.clientWidth;
1856         }
1857         return width;
1858     },
1859
1860     isAncestor : function(p, c) {
1861         p = Roo.getDom(p);
1862         c = Roo.getDom(c);
1863         if (!p || !c) {
1864             return false;
1865         }
1866
1867         if (p.contains && !Roo.isSafari) {
1868             return p.contains(c);
1869         } else if (p.compareDocumentPosition) {
1870             return !!(p.compareDocumentPosition(c) & 16);
1871         } else {
1872             var parent = c.parentNode;
1873             while (parent) {
1874                 if (parent == p) {
1875                     return true;
1876                 }
1877                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1878                     return false;
1879                 }
1880                 parent = parent.parentNode;
1881             }
1882             return false;
1883         }
1884     },
1885
1886     getRegion : function(el) {
1887         return Roo.lib.Region.getRegion(el);
1888     },
1889
1890     getY : function(el) {
1891         return this.getXY(el)[1];
1892     },
1893
1894     getX : function(el) {
1895         return this.getXY(el)[0];
1896     },
1897
1898     getXY : function(el) {
1899         var p, pe, b, scroll, bd = document.body;
1900         el = Roo.getDom(el);
1901         var fly = Roo.lib.AnimBase.fly;
1902         if (el.getBoundingClientRect) {
1903             b = el.getBoundingClientRect();
1904             scroll = fly(document).getScroll();
1905             return [b.left + scroll.left, b.top + scroll.top];
1906         }
1907         var x = 0, y = 0;
1908
1909         p = el;
1910
1911         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1912
1913         while (p) {
1914
1915             x += p.offsetLeft;
1916             y += p.offsetTop;
1917
1918             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1919                 hasAbsolute = true;
1920             }
1921
1922             if (Roo.isGecko) {
1923                 pe = fly(p);
1924
1925                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1926                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1927
1928
1929                 x += bl;
1930                 y += bt;
1931
1932
1933                 if (p != el && pe.getStyle('overflow') != 'visible') {
1934                     x += bl;
1935                     y += bt;
1936                 }
1937             }
1938             p = p.offsetParent;
1939         }
1940
1941         if (Roo.isSafari && hasAbsolute) {
1942             x -= bd.offsetLeft;
1943             y -= bd.offsetTop;
1944         }
1945
1946         if (Roo.isGecko && !hasAbsolute) {
1947             var dbd = fly(bd);
1948             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1949             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1950         }
1951
1952         p = el.parentNode;
1953         while (p && p != bd) {
1954             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1955                 x -= p.scrollLeft;
1956                 y -= p.scrollTop;
1957             }
1958             p = p.parentNode;
1959         }
1960         return [x, y];
1961     },
1962  
1963   
1964
1965
1966     setXY : function(el, xy) {
1967         el = Roo.fly(el, '_setXY');
1968         el.position();
1969         var pts = el.translatePoints(xy);
1970         if (xy[0] !== false) {
1971             el.dom.style.left = pts.left + "px";
1972         }
1973         if (xy[1] !== false) {
1974             el.dom.style.top = pts.top + "px";
1975         }
1976     },
1977
1978     setX : function(el, x) {
1979         this.setXY(el, [x, false]);
1980     },
1981
1982     setY : function(el, y) {
1983         this.setXY(el, [false, y]);
1984     }
1985 };
1986 /*
1987  * Portions of this file are based on pieces of Yahoo User Interface Library
1988  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1989  * YUI licensed under the BSD License:
1990  * http://developer.yahoo.net/yui/license.txt
1991  * <script type="text/javascript">
1992  *
1993  */
1994
1995 Roo.lib.Event = function() {
1996     var loadComplete = false;
1997     var listeners = [];
1998     var unloadListeners = [];
1999     var retryCount = 0;
2000     var onAvailStack = [];
2001     var counter = 0;
2002     var lastError = null;
2003
2004     return {
2005         POLL_RETRYS: 200,
2006         POLL_INTERVAL: 20,
2007         EL: 0,
2008         TYPE: 1,
2009         FN: 2,
2010         WFN: 3,
2011         OBJ: 3,
2012         ADJ_SCOPE: 4,
2013         _interval: null,
2014
2015         startInterval: function() {
2016             if (!this._interval) {
2017                 var self = this;
2018                 var callback = function() {
2019                     self._tryPreloadAttach();
2020                 };
2021                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2022
2023             }
2024         },
2025
2026         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2027             onAvailStack.push({ id:         p_id,
2028                 fn:         p_fn,
2029                 obj:        p_obj,
2030                 override:   p_override,
2031                 checkReady: false    });
2032
2033             retryCount = this.POLL_RETRYS;
2034             this.startInterval();
2035         },
2036
2037
2038         addListener: function(el, eventName, fn) {
2039             el = Roo.getDom(el);
2040             if (!el || !fn) {
2041                 return false;
2042             }
2043
2044             if ("unload" == eventName) {
2045                 unloadListeners[unloadListeners.length] =
2046                 [el, eventName, fn];
2047                 return true;
2048             }
2049
2050             var wrappedFn = function(e) {
2051                 return fn(Roo.lib.Event.getEvent(e));
2052             };
2053
2054             var li = [el, eventName, fn, wrappedFn];
2055
2056             var index = listeners.length;
2057             listeners[index] = li;
2058
2059             this.doAdd(el, eventName, wrappedFn, false);
2060             return true;
2061
2062         },
2063
2064
2065         removeListener: function(el, eventName, fn) {
2066             var i, len;
2067
2068             el = Roo.getDom(el);
2069
2070             if(!fn) {
2071                 return this.purgeElement(el, false, eventName);
2072             }
2073
2074
2075             if ("unload" == eventName) {
2076
2077                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2078                     var li = unloadListeners[i];
2079                     if (li &&
2080                         li[0] == el &&
2081                         li[1] == eventName &&
2082                         li[2] == fn) {
2083                         unloadListeners.splice(i, 1);
2084                         return true;
2085                     }
2086                 }
2087
2088                 return false;
2089             }
2090
2091             var cacheItem = null;
2092
2093
2094             var index = arguments[3];
2095
2096             if ("undefined" == typeof index) {
2097                 index = this._getCacheIndex(el, eventName, fn);
2098             }
2099
2100             if (index >= 0) {
2101                 cacheItem = listeners[index];
2102             }
2103
2104             if (!el || !cacheItem) {
2105                 return false;
2106             }
2107
2108             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2109
2110             delete listeners[index][this.WFN];
2111             delete listeners[index][this.FN];
2112             listeners.splice(index, 1);
2113
2114             return true;
2115
2116         },
2117
2118
2119         getTarget: function(ev, resolveTextNode) {
2120             ev = ev.browserEvent || ev;
2121             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2122             var t = ev.target || ev.srcElement;
2123             return this.resolveTextNode(t);
2124         },
2125
2126
2127         resolveTextNode: function(node) {
2128             if (Roo.isSafari && node && 3 == node.nodeType) {
2129                 return node.parentNode;
2130             } else {
2131                 return node;
2132             }
2133         },
2134
2135
2136         getPageX: function(ev) {
2137             ev = ev.browserEvent || ev;
2138             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2139             var x = ev.pageX;
2140             if (!x && 0 !== x) {
2141                 x = ev.clientX || 0;
2142
2143                 if (Roo.isIE) {
2144                     x += this.getScroll()[1];
2145                 }
2146             }
2147
2148             return x;
2149         },
2150
2151
2152         getPageY: function(ev) {
2153             ev = ev.browserEvent || ev;
2154             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2155             var y = ev.pageY;
2156             if (!y && 0 !== y) {
2157                 y = ev.clientY || 0;
2158
2159                 if (Roo.isIE) {
2160                     y += this.getScroll()[0];
2161                 }
2162             }
2163
2164
2165             return y;
2166         },
2167
2168
2169         getXY: function(ev) {
2170             ev = ev.browserEvent || ev;
2171             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2172             return [this.getPageX(ev), this.getPageY(ev)];
2173         },
2174
2175
2176         getRelatedTarget: function(ev) {
2177             ev = ev.browserEvent || ev;
2178             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2179             var t = ev.relatedTarget;
2180             if (!t) {
2181                 if (ev.type == "mouseout") {
2182                     t = ev.toElement;
2183                 } else if (ev.type == "mouseover") {
2184                     t = ev.fromElement;
2185                 }
2186             }
2187
2188             return this.resolveTextNode(t);
2189         },
2190
2191
2192         getTime: function(ev) {
2193             ev = ev.browserEvent || ev;
2194             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2195             if (!ev.time) {
2196                 var t = new Date().getTime();
2197                 try {
2198                     ev.time = t;
2199                 } catch(ex) {
2200                     this.lastError = ex;
2201                     return t;
2202                 }
2203             }
2204
2205             return ev.time;
2206         },
2207
2208
2209         stopEvent: function(ev) {
2210             this.stopPropagation(ev);
2211             this.preventDefault(ev);
2212         },
2213
2214
2215         stopPropagation: function(ev) {
2216             ev = ev.browserEvent || ev;
2217             if (ev.stopPropagation) {
2218                 ev.stopPropagation();
2219             } else {
2220                 ev.cancelBubble = true;
2221             }
2222         },
2223
2224
2225         preventDefault: function(ev) {
2226             ev = ev.browserEvent || ev;
2227             if(ev.preventDefault) {
2228                 ev.preventDefault();
2229             } else {
2230                 ev.returnValue = false;
2231             }
2232         },
2233
2234
2235         getEvent: function(e) {
2236             var ev = e || window.event;
2237             if (!ev) {
2238                 var c = this.getEvent.caller;
2239                 while (c) {
2240                     ev = c.arguments[0];
2241                     if (ev && Event == ev.constructor) {
2242                         break;
2243                     }
2244                     c = c.caller;
2245                 }
2246             }
2247             return ev;
2248         },
2249
2250
2251         getCharCode: function(ev) {
2252             ev = ev.browserEvent || ev;
2253             return ev.charCode || ev.keyCode || 0;
2254         },
2255
2256
2257         _getCacheIndex: function(el, eventName, fn) {
2258             for (var i = 0,len = listeners.length; i < len; ++i) {
2259                 var li = listeners[i];
2260                 if (li &&
2261                     li[this.FN] == fn &&
2262                     li[this.EL] == el &&
2263                     li[this.TYPE] == eventName) {
2264                     return i;
2265                 }
2266             }
2267
2268             return -1;
2269         },
2270
2271
2272         elCache: {},
2273
2274
2275         getEl: function(id) {
2276             return document.getElementById(id);
2277         },
2278
2279
2280         clearCache: function() {
2281         },
2282
2283
2284         _load: function(e) {
2285             loadComplete = true;
2286             var EU = Roo.lib.Event;
2287
2288
2289             if (Roo.isIE) {
2290                 EU.doRemove(window, "load", EU._load);
2291             }
2292         },
2293
2294
2295         _tryPreloadAttach: function() {
2296
2297             if (this.locked) {
2298                 return false;
2299             }
2300
2301             this.locked = true;
2302
2303
2304             var tryAgain = !loadComplete;
2305             if (!tryAgain) {
2306                 tryAgain = (retryCount > 0);
2307             }
2308
2309
2310             var notAvail = [];
2311             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2312                 var item = onAvailStack[i];
2313                 if (item) {
2314                     var el = this.getEl(item.id);
2315
2316                     if (el) {
2317                         if (!item.checkReady ||
2318                             loadComplete ||
2319                             el.nextSibling ||
2320                             (document && document.body)) {
2321
2322                             var scope = el;
2323                             if (item.override) {
2324                                 if (item.override === true) {
2325                                     scope = item.obj;
2326                                 } else {
2327                                     scope = item.override;
2328                                 }
2329                             }
2330                             item.fn.call(scope, item.obj);
2331                             onAvailStack[i] = null;
2332                         }
2333                     } else {
2334                         notAvail.push(item);
2335                     }
2336                 }
2337             }
2338
2339             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2340
2341             if (tryAgain) {
2342
2343                 this.startInterval();
2344             } else {
2345                 clearInterval(this._interval);
2346                 this._interval = null;
2347             }
2348
2349             this.locked = false;
2350
2351             return true;
2352
2353         },
2354
2355
2356         purgeElement: function(el, recurse, eventName) {
2357             var elListeners = this.getListeners(el, eventName);
2358             if (elListeners) {
2359                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2360                     var l = elListeners[i];
2361                     this.removeListener(el, l.type, l.fn);
2362                 }
2363             }
2364
2365             if (recurse && el && el.childNodes) {
2366                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2367                     this.purgeElement(el.childNodes[i], recurse, eventName);
2368                 }
2369             }
2370         },
2371
2372
2373         getListeners: function(el, eventName) {
2374             var results = [], searchLists;
2375             if (!eventName) {
2376                 searchLists = [listeners, unloadListeners];
2377             } else if (eventName == "unload") {
2378                 searchLists = [unloadListeners];
2379             } else {
2380                 searchLists = [listeners];
2381             }
2382
2383             for (var j = 0; j < searchLists.length; ++j) {
2384                 var searchList = searchLists[j];
2385                 if (searchList && searchList.length > 0) {
2386                     for (var i = 0,len = searchList.length; i < len; ++i) {
2387                         var l = searchList[i];
2388                         if (l && l[this.EL] === el &&
2389                             (!eventName || eventName === l[this.TYPE])) {
2390                             results.push({
2391                                 type:   l[this.TYPE],
2392                                 fn:     l[this.FN],
2393                                 obj:    l[this.OBJ],
2394                                 adjust: l[this.ADJ_SCOPE],
2395                                 index:  i
2396                             });
2397                         }
2398                     }
2399                 }
2400             }
2401
2402             return (results.length) ? results : null;
2403         },
2404
2405
2406         _unload: function(e) {
2407
2408             var EU = Roo.lib.Event, i, j, l, len, index;
2409
2410             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2411                 l = unloadListeners[i];
2412                 if (l) {
2413                     var scope = window;
2414                     if (l[EU.ADJ_SCOPE]) {
2415                         if (l[EU.ADJ_SCOPE] === true) {
2416                             scope = l[EU.OBJ];
2417                         } else {
2418                             scope = l[EU.ADJ_SCOPE];
2419                         }
2420                     }
2421                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2422                     unloadListeners[i] = null;
2423                     l = null;
2424                     scope = null;
2425                 }
2426             }
2427
2428             unloadListeners = null;
2429
2430             if (listeners && listeners.length > 0) {
2431                 j = listeners.length;
2432                 while (j) {
2433                     index = j - 1;
2434                     l = listeners[index];
2435                     if (l) {
2436                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2437                                 l[EU.FN], index);
2438                     }
2439                     j = j - 1;
2440                 }
2441                 l = null;
2442
2443                 EU.clearCache();
2444             }
2445
2446             EU.doRemove(window, "unload", EU._unload);
2447
2448         },
2449
2450
2451         getScroll: function() {
2452             var dd = document.documentElement, db = document.body;
2453             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2454                 return [dd.scrollTop, dd.scrollLeft];
2455             } else if (db) {
2456                 return [db.scrollTop, db.scrollLeft];
2457             } else {
2458                 return [0, 0];
2459             }
2460         },
2461
2462
2463         doAdd: function () {
2464             if (window.addEventListener) {
2465                 return function(el, eventName, fn, capture) {
2466                     el.addEventListener(eventName, fn, (capture));
2467                 };
2468             } else if (window.attachEvent) {
2469                 return function(el, eventName, fn, capture) {
2470                     el.attachEvent("on" + eventName, fn);
2471                 };
2472             } else {
2473                 return function() {
2474                 };
2475             }
2476         }(),
2477
2478
2479         doRemove: function() {
2480             if (window.removeEventListener) {
2481                 return function (el, eventName, fn, capture) {
2482                     el.removeEventListener(eventName, fn, (capture));
2483                 };
2484             } else if (window.detachEvent) {
2485                 return function (el, eventName, fn) {
2486                     el.detachEvent("on" + eventName, fn);
2487                 };
2488             } else {
2489                 return function() {
2490                 };
2491             }
2492         }()
2493     };
2494     
2495 }();
2496 (function() {     
2497    
2498     var E = Roo.lib.Event;
2499     E.on = E.addListener;
2500     E.un = E.removeListener;
2501
2502     if (document && document.body) {
2503         E._load();
2504     } else {
2505         E.doAdd(window, "load", E._load);
2506     }
2507     E.doAdd(window, "unload", E._unload);
2508     E._tryPreloadAttach();
2509 })();
2510
2511 /*
2512  * Portions of this file are based on pieces of Yahoo User Interface Library
2513  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2514  * YUI licensed under the BSD License:
2515  * http://developer.yahoo.net/yui/license.txt
2516  * <script type="text/javascript">
2517  *
2518  */
2519
2520 (function() {
2521     /**
2522      * @class Roo.lib.Ajax
2523      *
2524      */
2525     Roo.lib.Ajax = {
2526         /**
2527          * @static 
2528          */
2529         request : function(method, uri, cb, data, options) {
2530             if(options){
2531                 var hs = options.headers;
2532                 if(hs){
2533                     for(var h in hs){
2534                         if(hs.hasOwnProperty(h)){
2535                             this.initHeader(h, hs[h], false);
2536                         }
2537                     }
2538                 }
2539                 if(options.xmlData){
2540                     this.initHeader('Content-Type', 'text/xml', false);
2541                     method = 'POST';
2542                     data = options.xmlData;
2543                 }
2544             }
2545
2546             return this.asyncRequest(method, uri, cb, data);
2547         },
2548
2549         serializeForm : function(form) {
2550             if(typeof form == 'string') {
2551                 form = (document.getElementById(form) || document.forms[form]);
2552             }
2553
2554             var el, name, val, disabled, data = '', hasSubmit = false;
2555             for (var i = 0; i < form.elements.length; i++) {
2556                 el = form.elements[i];
2557                 disabled = form.elements[i].disabled;
2558                 name = form.elements[i].name;
2559                 val = form.elements[i].value;
2560
2561                 if (!disabled && name){
2562                     switch (el.type)
2563                             {
2564                         case 'select-one':
2565                         case 'select-multiple':
2566                             for (var j = 0; j < el.options.length; j++) {
2567                                 if (el.options[j].selected) {
2568                                     if (Roo.isIE) {
2569                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2570                                     }
2571                                     else {
2572                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2573                                     }
2574                                 }
2575                             }
2576                             break;
2577                         case 'radio':
2578                         case 'checkbox':
2579                             if (el.checked) {
2580                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2581                             }
2582                             break;
2583                         case 'file':
2584
2585                         case undefined:
2586
2587                         case 'reset':
2588
2589                         case 'button':
2590
2591                             break;
2592                         case 'submit':
2593                             if(hasSubmit == false) {
2594                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2595                                 hasSubmit = true;
2596                             }
2597                             break;
2598                         default:
2599                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2600                             break;
2601                     }
2602                 }
2603             }
2604             data = data.substr(0, data.length - 1);
2605             return data;
2606         },
2607
2608         headers:{},
2609
2610         hasHeaders:false,
2611
2612         useDefaultHeader:true,
2613
2614         defaultPostHeader:'application/x-www-form-urlencoded',
2615
2616         useDefaultXhrHeader:true,
2617
2618         defaultXhrHeader:'XMLHttpRequest',
2619
2620         hasDefaultHeaders:true,
2621
2622         defaultHeaders:{},
2623
2624         poll:{},
2625
2626         timeout:{},
2627
2628         pollInterval:50,
2629
2630         transactionId:0,
2631
2632         setProgId:function(id)
2633         {
2634             this.activeX.unshift(id);
2635         },
2636
2637         setDefaultPostHeader:function(b)
2638         {
2639             this.useDefaultHeader = b;
2640         },
2641
2642         setDefaultXhrHeader:function(b)
2643         {
2644             this.useDefaultXhrHeader = b;
2645         },
2646
2647         setPollingInterval:function(i)
2648         {
2649             if (typeof i == 'number' && isFinite(i)) {
2650                 this.pollInterval = i;
2651             }
2652         },
2653
2654         createXhrObject:function(transactionId)
2655         {
2656             var obj,http;
2657             try
2658             {
2659
2660                 http = new XMLHttpRequest();
2661
2662                 obj = { conn:http, tId:transactionId };
2663             }
2664             catch(e)
2665             {
2666                 for (var i = 0; i < this.activeX.length; ++i) {
2667                     try
2668                     {
2669
2670                         http = new ActiveXObject(this.activeX[i]);
2671
2672                         obj = { conn:http, tId:transactionId };
2673                         break;
2674                     }
2675                     catch(e) {
2676                     }
2677                 }
2678             }
2679             finally
2680             {
2681                 return obj;
2682             }
2683         },
2684
2685         getConnectionObject:function()
2686         {
2687             var o;
2688             var tId = this.transactionId;
2689
2690             try
2691             {
2692                 o = this.createXhrObject(tId);
2693                 if (o) {
2694                     this.transactionId++;
2695                 }
2696             }
2697             catch(e) {
2698             }
2699             finally
2700             {
2701                 return o;
2702             }
2703         },
2704
2705         asyncRequest:function(method, uri, callback, postData)
2706         {
2707             var o = this.getConnectionObject();
2708
2709             if (!o) {
2710                 return null;
2711             }
2712             else {
2713                 o.conn.open(method, uri, true);
2714
2715                 if (this.useDefaultXhrHeader) {
2716                     if (!this.defaultHeaders['X-Requested-With']) {
2717                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2718                     }
2719                 }
2720
2721                 if(postData && this.useDefaultHeader){
2722                     this.initHeader('Content-Type', this.defaultPostHeader);
2723                 }
2724
2725                  if (this.hasDefaultHeaders || this.hasHeaders) {
2726                     this.setHeader(o);
2727                 }
2728
2729                 this.handleReadyState(o, callback);
2730                 o.conn.send(postData || null);
2731
2732                 return o;
2733             }
2734         },
2735
2736         handleReadyState:function(o, callback)
2737         {
2738             var oConn = this;
2739
2740             if (callback && callback.timeout) {
2741                 
2742                 this.timeout[o.tId] = window.setTimeout(function() {
2743                     oConn.abort(o, callback, true);
2744                 }, callback.timeout);
2745             }
2746
2747             this.poll[o.tId] = window.setInterval(
2748                     function() {
2749                         if (o.conn && o.conn.readyState == 4) {
2750                             window.clearInterval(oConn.poll[o.tId]);
2751                             delete oConn.poll[o.tId];
2752
2753                             if(callback && callback.timeout) {
2754                                 window.clearTimeout(oConn.timeout[o.tId]);
2755                                 delete oConn.timeout[o.tId];
2756                             }
2757
2758                             oConn.handleTransactionResponse(o, callback);
2759                         }
2760                     }
2761                     , this.pollInterval);
2762         },
2763
2764         handleTransactionResponse:function(o, callback, isAbort)
2765         {
2766
2767             if (!callback) {
2768                 this.releaseObject(o);
2769                 return;
2770             }
2771
2772             var httpStatus, responseObject;
2773
2774             try
2775             {
2776                 if (o.conn.status !== undefined && o.conn.status != 0) {
2777                     httpStatus = o.conn.status;
2778                 }
2779                 else {
2780                     httpStatus = 13030;
2781                 }
2782             }
2783             catch(e) {
2784
2785
2786                 httpStatus = 13030;
2787             }
2788
2789             if (httpStatus >= 200 && httpStatus < 300) {
2790                 responseObject = this.createResponseObject(o, callback.argument);
2791                 if (callback.success) {
2792                     if (!callback.scope) {
2793                         callback.success(responseObject);
2794                     }
2795                     else {
2796
2797
2798                         callback.success.apply(callback.scope, [responseObject]);
2799                     }
2800                 }
2801             }
2802             else {
2803                 switch (httpStatus) {
2804
2805                     case 12002:
2806                     case 12029:
2807                     case 12030:
2808                     case 12031:
2809                     case 12152:
2810                     case 13030:
2811                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2812                         if (callback.failure) {
2813                             if (!callback.scope) {
2814                                 callback.failure(responseObject);
2815                             }
2816                             else {
2817                                 callback.failure.apply(callback.scope, [responseObject]);
2818                             }
2819                         }
2820                         break;
2821                     default:
2822                         responseObject = this.createResponseObject(o, callback.argument);
2823                         if (callback.failure) {
2824                             if (!callback.scope) {
2825                                 callback.failure(responseObject);
2826                             }
2827                             else {
2828                                 callback.failure.apply(callback.scope, [responseObject]);
2829                             }
2830                         }
2831                 }
2832             }
2833
2834             this.releaseObject(o);
2835             responseObject = null;
2836         },
2837
2838         createResponseObject:function(o, callbackArg)
2839         {
2840             var obj = {};
2841             var headerObj = {};
2842
2843             try
2844             {
2845                 var headerStr = o.conn.getAllResponseHeaders();
2846                 var header = headerStr.split('\n');
2847                 for (var i = 0; i < header.length; i++) {
2848                     var delimitPos = header[i].indexOf(':');
2849                     if (delimitPos != -1) {
2850                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2851                     }
2852                 }
2853             }
2854             catch(e) {
2855             }
2856
2857             obj.tId = o.tId;
2858             obj.status = o.conn.status;
2859             obj.statusText = o.conn.statusText;
2860             obj.getResponseHeader = headerObj;
2861             obj.getAllResponseHeaders = headerStr;
2862             obj.responseText = o.conn.responseText;
2863             obj.responseXML = o.conn.responseXML;
2864
2865             if (typeof callbackArg !== undefined) {
2866                 obj.argument = callbackArg;
2867             }
2868
2869             return obj;
2870         },
2871
2872         createExceptionObject:function(tId, callbackArg, isAbort)
2873         {
2874             var COMM_CODE = 0;
2875             var COMM_ERROR = 'communication failure';
2876             var ABORT_CODE = -1;
2877             var ABORT_ERROR = 'transaction aborted';
2878
2879             var obj = {};
2880
2881             obj.tId = tId;
2882             if (isAbort) {
2883                 obj.status = ABORT_CODE;
2884                 obj.statusText = ABORT_ERROR;
2885             }
2886             else {
2887                 obj.status = COMM_CODE;
2888                 obj.statusText = COMM_ERROR;
2889             }
2890
2891             if (callbackArg) {
2892                 obj.argument = callbackArg;
2893             }
2894
2895             return obj;
2896         },
2897
2898         initHeader:function(label, value, isDefault)
2899         {
2900             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2901
2902             if (headerObj[label] === undefined) {
2903                 headerObj[label] = value;
2904             }
2905             else {
2906
2907
2908                 headerObj[label] = value + "," + headerObj[label];
2909             }
2910
2911             if (isDefault) {
2912                 this.hasDefaultHeaders = true;
2913             }
2914             else {
2915                 this.hasHeaders = true;
2916             }
2917         },
2918
2919
2920         setHeader:function(o)
2921         {
2922             if (this.hasDefaultHeaders) {
2923                 for (var prop in this.defaultHeaders) {
2924                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2925                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2926                     }
2927                 }
2928             }
2929
2930             if (this.hasHeaders) {
2931                 for (var prop in this.headers) {
2932                     if (this.headers.hasOwnProperty(prop)) {
2933                         o.conn.setRequestHeader(prop, this.headers[prop]);
2934                     }
2935                 }
2936                 this.headers = {};
2937                 this.hasHeaders = false;
2938             }
2939         },
2940
2941         resetDefaultHeaders:function() {
2942             delete this.defaultHeaders;
2943             this.defaultHeaders = {};
2944             this.hasDefaultHeaders = false;
2945         },
2946
2947         abort:function(o, callback, isTimeout)
2948         {
2949             if(this.isCallInProgress(o)) {
2950                 o.conn.abort();
2951                 window.clearInterval(this.poll[o.tId]);
2952                 delete this.poll[o.tId];
2953                 if (isTimeout) {
2954                     delete this.timeout[o.tId];
2955                 }
2956
2957                 this.handleTransactionResponse(o, callback, true);
2958
2959                 return true;
2960             }
2961             else {
2962                 return false;
2963             }
2964         },
2965
2966
2967         isCallInProgress:function(o)
2968         {
2969             if (o && o.conn) {
2970                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2971             }
2972             else {
2973
2974                 return false;
2975             }
2976         },
2977
2978
2979         releaseObject:function(o)
2980         {
2981
2982             o.conn = null;
2983
2984             o = null;
2985         },
2986
2987         activeX:[
2988         'MSXML2.XMLHTTP.3.0',
2989         'MSXML2.XMLHTTP',
2990         'Microsoft.XMLHTTP'
2991         ]
2992
2993
2994     };
2995 })();/*
2996  * Portions of this file are based on pieces of Yahoo User Interface Library
2997  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2998  * YUI licensed under the BSD License:
2999  * http://developer.yahoo.net/yui/license.txt
3000  * <script type="text/javascript">
3001  *
3002  */
3003
3004 Roo.lib.Region = function(t, r, b, l) {
3005     this.top = t;
3006     this[1] = t;
3007     this.right = r;
3008     this.bottom = b;
3009     this.left = l;
3010     this[0] = l;
3011 };
3012
3013
3014 Roo.lib.Region.prototype = {
3015     contains : function(region) {
3016         return ( region.left >= this.left &&
3017                  region.right <= this.right &&
3018                  region.top >= this.top &&
3019                  region.bottom <= this.bottom    );
3020
3021     },
3022
3023     getArea : function() {
3024         return ( (this.bottom - this.top) * (this.right - this.left) );
3025     },
3026
3027     intersect : function(region) {
3028         var t = Math.max(this.top, region.top);
3029         var r = Math.min(this.right, region.right);
3030         var b = Math.min(this.bottom, region.bottom);
3031         var l = Math.max(this.left, region.left);
3032
3033         if (b >= t && r >= l) {
3034             return new Roo.lib.Region(t, r, b, l);
3035         } else {
3036             return null;
3037         }
3038     },
3039     union : function(region) {
3040         var t = Math.min(this.top, region.top);
3041         var r = Math.max(this.right, region.right);
3042         var b = Math.max(this.bottom, region.bottom);
3043         var l = Math.min(this.left, region.left);
3044
3045         return new Roo.lib.Region(t, r, b, l);
3046     },
3047
3048     adjust : function(t, l, b, r) {
3049         this.top += t;
3050         this.left += l;
3051         this.right += r;
3052         this.bottom += b;
3053         return this;
3054     }
3055 };
3056
3057 Roo.lib.Region.getRegion = function(el) {
3058     var p = Roo.lib.Dom.getXY(el);
3059
3060     var t = p[1];
3061     var r = p[0] + el.offsetWidth;
3062     var b = p[1] + el.offsetHeight;
3063     var l = p[0];
3064
3065     return new Roo.lib.Region(t, r, b, l);
3066 };
3067 /*
3068  * Portions of this file are based on pieces of Yahoo User Interface Library
3069  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3070  * YUI licensed under the BSD License:
3071  * http://developer.yahoo.net/yui/license.txt
3072  * <script type="text/javascript">
3073  *
3074  */
3075 //@@dep Roo.lib.Region
3076
3077
3078 Roo.lib.Point = function(x, y) {
3079     if (x instanceof Array) {
3080         y = x[1];
3081         x = x[0];
3082     }
3083     this.x = this.right = this.left = this[0] = x;
3084     this.y = this.top = this.bottom = this[1] = y;
3085 };
3086
3087 Roo.lib.Point.prototype = new Roo.lib.Region();
3088 /*
3089  * Portions of this file are based on pieces of Yahoo User Interface Library
3090  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3091  * YUI licensed under the BSD License:
3092  * http://developer.yahoo.net/yui/license.txt
3093  * <script type="text/javascript">
3094  *
3095  */
3096  
3097 (function() {   
3098
3099     Roo.lib.Anim = {
3100         scroll : function(el, args, duration, easing, cb, scope) {
3101             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3102         },
3103
3104         motion : function(el, args, duration, easing, cb, scope) {
3105             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3106         },
3107
3108         color : function(el, args, duration, easing, cb, scope) {
3109             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3110         },
3111
3112         run : function(el, args, duration, easing, cb, scope, type) {
3113             type = type || Roo.lib.AnimBase;
3114             if (typeof easing == "string") {
3115                 easing = Roo.lib.Easing[easing];
3116             }
3117             var anim = new type(el, args, duration, easing);
3118             anim.animateX(function() {
3119                 Roo.callback(cb, scope);
3120             });
3121             return anim;
3122         }
3123     };
3124 })();/*
3125  * Portions of this file are based on pieces of Yahoo User Interface Library
3126  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3127  * YUI licensed under the BSD License:
3128  * http://developer.yahoo.net/yui/license.txt
3129  * <script type="text/javascript">
3130  *
3131  */
3132
3133 (function() {    
3134     var libFlyweight;
3135     
3136     function fly(el) {
3137         if (!libFlyweight) {
3138             libFlyweight = new Roo.Element.Flyweight();
3139         }
3140         libFlyweight.dom = el;
3141         return libFlyweight;
3142     }
3143
3144     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3145     
3146    
3147     
3148     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3149         if (el) {
3150             this.init(el, attributes, duration, method);
3151         }
3152     };
3153
3154     Roo.lib.AnimBase.fly = fly;
3155     
3156     
3157     
3158     Roo.lib.AnimBase.prototype = {
3159
3160         toString: function() {
3161             var el = this.getEl();
3162             var id = el.id || el.tagName;
3163             return ("Anim " + id);
3164         },
3165
3166         patterns: {
3167             noNegatives:        /width|height|opacity|padding/i,
3168             offsetAttribute:  /^((width|height)|(top|left))$/,
3169             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3170             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3171         },
3172
3173
3174         doMethod: function(attr, start, end) {
3175             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3176         },
3177
3178
3179         setAttribute: function(attr, val, unit) {
3180             if (this.patterns.noNegatives.test(attr)) {
3181                 val = (val > 0) ? val : 0;
3182             }
3183
3184             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3185         },
3186
3187
3188         getAttribute: function(attr) {
3189             var el = this.getEl();
3190             var val = fly(el).getStyle(attr);
3191
3192             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3193                 return parseFloat(val);
3194             }
3195
3196             var a = this.patterns.offsetAttribute.exec(attr) || [];
3197             var pos = !!( a[3] );
3198             var box = !!( a[2] );
3199
3200
3201             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3202                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3203             } else {
3204                 val = 0;
3205             }
3206
3207             return val;
3208         },
3209
3210
3211         getDefaultUnit: function(attr) {
3212             if (this.patterns.defaultUnit.test(attr)) {
3213                 return 'px';
3214             }
3215
3216             return '';
3217         },
3218
3219         animateX : function(callback, scope) {
3220             var f = function() {
3221                 this.onComplete.removeListener(f);
3222                 if (typeof callback == "function") {
3223                     callback.call(scope || this, this);
3224                 }
3225             };
3226             this.onComplete.addListener(f, this);
3227             this.animate();
3228         },
3229
3230
3231         setRuntimeAttribute: function(attr) {
3232             var start;
3233             var end;
3234             var attributes = this.attributes;
3235
3236             this.runtimeAttributes[attr] = {};
3237
3238             var isset = function(prop) {
3239                 return (typeof prop !== 'undefined');
3240             };
3241
3242             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3243                 return false;
3244             }
3245
3246             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3247
3248
3249             if (isset(attributes[attr]['to'])) {
3250                 end = attributes[attr]['to'];
3251             } else if (isset(attributes[attr]['by'])) {
3252                 if (start.constructor == Array) {
3253                     end = [];
3254                     for (var i = 0, len = start.length; i < len; ++i) {
3255                         end[i] = start[i] + attributes[attr]['by'][i];
3256                     }
3257                 } else {
3258                     end = start + attributes[attr]['by'];
3259                 }
3260             }
3261
3262             this.runtimeAttributes[attr].start = start;
3263             this.runtimeAttributes[attr].end = end;
3264
3265
3266             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3267         },
3268
3269
3270         init: function(el, attributes, duration, method) {
3271
3272             var isAnimated = false;
3273
3274
3275             var startTime = null;
3276
3277
3278             var actualFrames = 0;
3279
3280
3281             el = Roo.getDom(el);
3282
3283
3284             this.attributes = attributes || {};
3285
3286
3287             this.duration = duration || 1;
3288
3289
3290             this.method = method || Roo.lib.Easing.easeNone;
3291
3292
3293             this.useSeconds = true;
3294
3295
3296             this.currentFrame = 0;
3297
3298
3299             this.totalFrames = Roo.lib.AnimMgr.fps;
3300
3301
3302             this.getEl = function() {
3303                 return el;
3304             };
3305
3306
3307             this.isAnimated = function() {
3308                 return isAnimated;
3309             };
3310
3311
3312             this.getStartTime = function() {
3313                 return startTime;
3314             };
3315
3316             this.runtimeAttributes = {};
3317
3318
3319             this.animate = function() {
3320                 if (this.isAnimated()) {
3321                     return false;
3322                 }
3323
3324                 this.currentFrame = 0;
3325
3326                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3327
3328                 Roo.lib.AnimMgr.registerElement(this);
3329             };
3330
3331
3332             this.stop = function(finish) {
3333                 if (finish) {
3334                     this.currentFrame = this.totalFrames;
3335                     this._onTween.fire();
3336                 }
3337                 Roo.lib.AnimMgr.stop(this);
3338             };
3339
3340             var onStart = function() {
3341                 this.onStart.fire();
3342
3343                 this.runtimeAttributes = {};
3344                 for (var attr in this.attributes) {
3345                     this.setRuntimeAttribute(attr);
3346                 }
3347
3348                 isAnimated = true;
3349                 actualFrames = 0;
3350                 startTime = new Date();
3351             };
3352
3353
3354             var onTween = function() {
3355                 var data = {
3356                     duration: new Date() - this.getStartTime(),
3357                     currentFrame: this.currentFrame
3358                 };
3359
3360                 data.toString = function() {
3361                     return (
3362                             'duration: ' + data.duration +
3363                             ', currentFrame: ' + data.currentFrame
3364                             );
3365                 };
3366
3367                 this.onTween.fire(data);
3368
3369                 var runtimeAttributes = this.runtimeAttributes;
3370
3371                 for (var attr in runtimeAttributes) {
3372                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3373                 }
3374
3375                 actualFrames += 1;
3376             };
3377
3378             var onComplete = function() {
3379                 var actual_duration = (new Date() - startTime) / 1000 ;
3380
3381                 var data = {
3382                     duration: actual_duration,
3383                     frames: actualFrames,
3384                     fps: actualFrames / actual_duration
3385                 };
3386
3387                 data.toString = function() {
3388                     return (
3389                             'duration: ' + data.duration +
3390                             ', frames: ' + data.frames +
3391                             ', fps: ' + data.fps
3392                             );
3393                 };
3394
3395                 isAnimated = false;
3396                 actualFrames = 0;
3397                 this.onComplete.fire(data);
3398             };
3399
3400
3401             this._onStart = new Roo.util.Event(this);
3402             this.onStart = new Roo.util.Event(this);
3403             this.onTween = new Roo.util.Event(this);
3404             this._onTween = new Roo.util.Event(this);
3405             this.onComplete = new Roo.util.Event(this);
3406             this._onComplete = new Roo.util.Event(this);
3407             this._onStart.addListener(onStart);
3408             this._onTween.addListener(onTween);
3409             this._onComplete.addListener(onComplete);
3410         }
3411     };
3412 })();
3413 /*
3414  * Portions of this file are based on pieces of Yahoo User Interface Library
3415  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3416  * YUI licensed under the BSD License:
3417  * http://developer.yahoo.net/yui/license.txt
3418  * <script type="text/javascript">
3419  *
3420  */
3421
3422 Roo.lib.AnimMgr = new function() {
3423
3424     var thread = null;
3425
3426
3427     var queue = [];
3428
3429
3430     var tweenCount = 0;
3431
3432
3433     this.fps = 1000;
3434
3435
3436     this.delay = 1;
3437
3438
3439     this.registerElement = function(tween) {
3440         queue[queue.length] = tween;
3441         tweenCount += 1;
3442         tween._onStart.fire();
3443         this.start();
3444     };
3445
3446
3447     this.unRegister = function(tween, index) {
3448         tween._onComplete.fire();
3449         index = index || getIndex(tween);
3450         if (index != -1) {
3451             queue.splice(index, 1);
3452         }
3453
3454         tweenCount -= 1;
3455         if (tweenCount <= 0) {
3456             this.stop();
3457         }
3458     };
3459
3460
3461     this.start = function() {
3462         if (thread === null) {
3463             thread = setInterval(this.run, this.delay);
3464         }
3465     };
3466
3467
3468     this.stop = function(tween) {
3469         if (!tween) {
3470             clearInterval(thread);
3471
3472             for (var i = 0, len = queue.length; i < len; ++i) {
3473                 if (queue[0].isAnimated()) {
3474                     this.unRegister(queue[0], 0);
3475                 }
3476             }
3477
3478             queue = [];
3479             thread = null;
3480             tweenCount = 0;
3481         }
3482         else {
3483             this.unRegister(tween);
3484         }
3485     };
3486
3487
3488     this.run = function() {
3489         for (var i = 0, len = queue.length; i < len; ++i) {
3490             var tween = queue[i];
3491             if (!tween || !tween.isAnimated()) {
3492                 continue;
3493             }
3494
3495             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3496             {
3497                 tween.currentFrame += 1;
3498
3499                 if (tween.useSeconds) {
3500                     correctFrame(tween);
3501                 }
3502                 tween._onTween.fire();
3503             }
3504             else {
3505                 Roo.lib.AnimMgr.stop(tween, i);
3506             }
3507         }
3508     };
3509
3510     var getIndex = function(anim) {
3511         for (var i = 0, len = queue.length; i < len; ++i) {
3512             if (queue[i] == anim) {
3513                 return i;
3514             }
3515         }
3516         return -1;
3517     };
3518
3519
3520     var correctFrame = function(tween) {
3521         var frames = tween.totalFrames;
3522         var frame = tween.currentFrame;
3523         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3524         var elapsed = (new Date() - tween.getStartTime());
3525         var tweak = 0;
3526
3527         if (elapsed < tween.duration * 1000) {
3528             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3529         } else {
3530             tweak = frames - (frame + 1);
3531         }
3532         if (tweak > 0 && isFinite(tweak)) {
3533             if (tween.currentFrame + tweak >= frames) {
3534                 tweak = frames - (frame + 1);
3535             }
3536
3537             tween.currentFrame += tweak;
3538         }
3539     };
3540 };
3541
3542     /*
3543  * Portions of this file are based on pieces of Yahoo User Interface Library
3544  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3545  * YUI licensed under the BSD License:
3546  * http://developer.yahoo.net/yui/license.txt
3547  * <script type="text/javascript">
3548  *
3549  */
3550 Roo.lib.Bezier = new function() {
3551
3552         this.getPosition = function(points, t) {
3553             var n = points.length;
3554             var tmp = [];
3555
3556             for (var i = 0; i < n; ++i) {
3557                 tmp[i] = [points[i][0], points[i][1]];
3558             }
3559
3560             for (var j = 1; j < n; ++j) {
3561                 for (i = 0; i < n - j; ++i) {
3562                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3563                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3564                 }
3565             }
3566
3567             return [ tmp[0][0], tmp[0][1] ];
3568
3569         };
3570     };/*
3571  * Portions of this file are based on pieces of Yahoo User Interface Library
3572  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3573  * YUI licensed under the BSD License:
3574  * http://developer.yahoo.net/yui/license.txt
3575  * <script type="text/javascript">
3576  *
3577  */
3578 (function() {
3579
3580     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3581         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3582     };
3583
3584     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3585
3586     var fly = Roo.lib.AnimBase.fly;
3587     var Y = Roo.lib;
3588     var superclass = Y.ColorAnim.superclass;
3589     var proto = Y.ColorAnim.prototype;
3590
3591     proto.toString = function() {
3592         var el = this.getEl();
3593         var id = el.id || el.tagName;
3594         return ("ColorAnim " + id);
3595     };
3596
3597     proto.patterns.color = /color$/i;
3598     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3599     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3600     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3601     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3602
3603
3604     proto.parseColor = function(s) {
3605         if (s.length == 3) {
3606             return s;
3607         }
3608
3609         var c = this.patterns.hex.exec(s);
3610         if (c && c.length == 4) {
3611             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3612         }
3613
3614         c = this.patterns.rgb.exec(s);
3615         if (c && c.length == 4) {
3616             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3617         }
3618
3619         c = this.patterns.hex3.exec(s);
3620         if (c && c.length == 4) {
3621             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3622         }
3623
3624         return null;
3625     };
3626     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3627     proto.getAttribute = function(attr) {
3628         var el = this.getEl();
3629         if (this.patterns.color.test(attr)) {
3630             var val = fly(el).getStyle(attr);
3631
3632             if (this.patterns.transparent.test(val)) {
3633                 var parent = el.parentNode;
3634                 val = fly(parent).getStyle(attr);
3635
3636                 while (parent && this.patterns.transparent.test(val)) {
3637                     parent = parent.parentNode;
3638                     val = fly(parent).getStyle(attr);
3639                     if (parent.tagName.toUpperCase() == 'HTML') {
3640                         val = '#fff';
3641                     }
3642                 }
3643             }
3644         } else {
3645             val = superclass.getAttribute.call(this, attr);
3646         }
3647
3648         return val;
3649     };
3650     proto.getAttribute = function(attr) {
3651         var el = this.getEl();
3652         if (this.patterns.color.test(attr)) {
3653             var val = fly(el).getStyle(attr);
3654
3655             if (this.patterns.transparent.test(val)) {
3656                 var parent = el.parentNode;
3657                 val = fly(parent).getStyle(attr);
3658
3659                 while (parent && this.patterns.transparent.test(val)) {
3660                     parent = parent.parentNode;
3661                     val = fly(parent).getStyle(attr);
3662                     if (parent.tagName.toUpperCase() == 'HTML') {
3663                         val = '#fff';
3664                     }
3665                 }
3666             }
3667         } else {
3668             val = superclass.getAttribute.call(this, attr);
3669         }
3670
3671         return val;
3672     };
3673
3674     proto.doMethod = function(attr, start, end) {
3675         var val;
3676
3677         if (this.patterns.color.test(attr)) {
3678             val = [];
3679             for (var i = 0, len = start.length; i < len; ++i) {
3680                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3681             }
3682
3683             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3684         }
3685         else {
3686             val = superclass.doMethod.call(this, attr, start, end);
3687         }
3688
3689         return val;
3690     };
3691
3692     proto.setRuntimeAttribute = function(attr) {
3693         superclass.setRuntimeAttribute.call(this, attr);
3694
3695         if (this.patterns.color.test(attr)) {
3696             var attributes = this.attributes;
3697             var start = this.parseColor(this.runtimeAttributes[attr].start);
3698             var end = this.parseColor(this.runtimeAttributes[attr].end);
3699
3700             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3701                 end = this.parseColor(attributes[attr].by);
3702
3703                 for (var i = 0, len = start.length; i < len; ++i) {
3704                     end[i] = start[i] + end[i];
3705                 }
3706             }
3707
3708             this.runtimeAttributes[attr].start = start;
3709             this.runtimeAttributes[attr].end = end;
3710         }
3711     };
3712 })();
3713
3714 /*
3715  * Portions of this file are based on pieces of Yahoo User Interface Library
3716  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3717  * YUI licensed under the BSD License:
3718  * http://developer.yahoo.net/yui/license.txt
3719  * <script type="text/javascript">
3720  *
3721  */
3722 Roo.lib.Easing = {
3723
3724
3725     easeNone: function (t, b, c, d) {
3726         return c * t / d + b;
3727     },
3728
3729
3730     easeIn: function (t, b, c, d) {
3731         return c * (t /= d) * t + b;
3732     },
3733
3734
3735     easeOut: function (t, b, c, d) {
3736         return -c * (t /= d) * (t - 2) + b;
3737     },
3738
3739
3740     easeBoth: function (t, b, c, d) {
3741         if ((t /= d / 2) < 1) {
3742             return c / 2 * t * t + b;
3743         }
3744
3745         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3746     },
3747
3748
3749     easeInStrong: function (t, b, c, d) {
3750         return c * (t /= d) * t * t * t + b;
3751     },
3752
3753
3754     easeOutStrong: function (t, b, c, d) {
3755         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3756     },
3757
3758
3759     easeBothStrong: function (t, b, c, d) {
3760         if ((t /= d / 2) < 1) {
3761             return c / 2 * t * t * t * t + b;
3762         }
3763
3764         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3765     },
3766
3767
3768
3769     elasticIn: function (t, b, c, d, a, p) {
3770         if (t == 0) {
3771             return b;
3772         }
3773         if ((t /= d) == 1) {
3774             return b + c;
3775         }
3776         if (!p) {
3777             p = d * .3;
3778         }
3779
3780         if (!a || a < Math.abs(c)) {
3781             a = c;
3782             var s = p / 4;
3783         }
3784         else {
3785             var s = p / (2 * Math.PI) * Math.asin(c / a);
3786         }
3787
3788         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3789     },
3790
3791
3792     elasticOut: function (t, b, c, d, a, p) {
3793         if (t == 0) {
3794             return b;
3795         }
3796         if ((t /= d) == 1) {
3797             return b + c;
3798         }
3799         if (!p) {
3800             p = d * .3;
3801         }
3802
3803         if (!a || a < Math.abs(c)) {
3804             a = c;
3805             var s = p / 4;
3806         }
3807         else {
3808             var s = p / (2 * Math.PI) * Math.asin(c / a);
3809         }
3810
3811         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3812     },
3813
3814
3815     elasticBoth: function (t, b, c, d, a, p) {
3816         if (t == 0) {
3817             return b;
3818         }
3819
3820         if ((t /= d / 2) == 2) {
3821             return b + c;
3822         }
3823
3824         if (!p) {
3825             p = d * (.3 * 1.5);
3826         }
3827
3828         if (!a || a < Math.abs(c)) {
3829             a = c;
3830             var s = p / 4;
3831         }
3832         else {
3833             var s = p / (2 * Math.PI) * Math.asin(c / a);
3834         }
3835
3836         if (t < 1) {
3837             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3838                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3839         }
3840         return a * Math.pow(2, -10 * (t -= 1)) *
3841                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3842     },
3843
3844
3845
3846     backIn: function (t, b, c, d, s) {
3847         if (typeof s == 'undefined') {
3848             s = 1.70158;
3849         }
3850         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3851     },
3852
3853
3854     backOut: function (t, b, c, d, s) {
3855         if (typeof s == 'undefined') {
3856             s = 1.70158;
3857         }
3858         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3859     },
3860
3861
3862     backBoth: function (t, b, c, d, s) {
3863         if (typeof s == 'undefined') {
3864             s = 1.70158;
3865         }
3866
3867         if ((t /= d / 2 ) < 1) {
3868             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3869         }
3870         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3871     },
3872
3873
3874     bounceIn: function (t, b, c, d) {
3875         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3876     },
3877
3878
3879     bounceOut: function (t, b, c, d) {
3880         if ((t /= d) < (1 / 2.75)) {
3881             return c * (7.5625 * t * t) + b;
3882         } else if (t < (2 / 2.75)) {
3883             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3884         } else if (t < (2.5 / 2.75)) {
3885             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3886         }
3887         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3888     },
3889
3890
3891     bounceBoth: function (t, b, c, d) {
3892         if (t < d / 2) {
3893             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3894         }
3895         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3896     }
3897 };/*
3898  * Portions of this file are based on pieces of Yahoo User Interface Library
3899  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3900  * YUI licensed under the BSD License:
3901  * http://developer.yahoo.net/yui/license.txt
3902  * <script type="text/javascript">
3903  *
3904  */
3905     (function() {
3906         Roo.lib.Motion = function(el, attributes, duration, method) {
3907             if (el) {
3908                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3909             }
3910         };
3911
3912         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3913
3914
3915         var Y = Roo.lib;
3916         var superclass = Y.Motion.superclass;
3917         var proto = Y.Motion.prototype;
3918
3919         proto.toString = function() {
3920             var el = this.getEl();
3921             var id = el.id || el.tagName;
3922             return ("Motion " + id);
3923         };
3924
3925         proto.patterns.points = /^points$/i;
3926
3927         proto.setAttribute = function(attr, val, unit) {
3928             if (this.patterns.points.test(attr)) {
3929                 unit = unit || 'px';
3930                 superclass.setAttribute.call(this, 'left', val[0], unit);
3931                 superclass.setAttribute.call(this, 'top', val[1], unit);
3932             } else {
3933                 superclass.setAttribute.call(this, attr, val, unit);
3934             }
3935         };
3936
3937         proto.getAttribute = function(attr) {
3938             if (this.patterns.points.test(attr)) {
3939                 var val = [
3940                         superclass.getAttribute.call(this, 'left'),
3941                         superclass.getAttribute.call(this, 'top')
3942                         ];
3943             } else {
3944                 val = superclass.getAttribute.call(this, attr);
3945             }
3946
3947             return val;
3948         };
3949
3950         proto.doMethod = function(attr, start, end) {
3951             var val = null;
3952
3953             if (this.patterns.points.test(attr)) {
3954                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3955                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3956             } else {
3957                 val = superclass.doMethod.call(this, attr, start, end);
3958             }
3959             return val;
3960         };
3961
3962         proto.setRuntimeAttribute = function(attr) {
3963             if (this.patterns.points.test(attr)) {
3964                 var el = this.getEl();
3965                 var attributes = this.attributes;
3966                 var start;
3967                 var control = attributes['points']['control'] || [];
3968                 var end;
3969                 var i, len;
3970
3971                 if (control.length > 0 && !(control[0] instanceof Array)) {
3972                     control = [control];
3973                 } else {
3974                     var tmp = [];
3975                     for (i = 0,len = control.length; i < len; ++i) {
3976                         tmp[i] = control[i];
3977                     }
3978                     control = tmp;
3979                 }
3980
3981                 Roo.fly(el).position();
3982
3983                 if (isset(attributes['points']['from'])) {
3984                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3985                 }
3986                 else {
3987                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3988                 }
3989
3990                 start = this.getAttribute('points');
3991
3992
3993                 if (isset(attributes['points']['to'])) {
3994                     end = translateValues.call(this, attributes['points']['to'], start);
3995
3996                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3997                     for (i = 0,len = control.length; i < len; ++i) {
3998                         control[i] = translateValues.call(this, control[i], start);
3999                     }
4000
4001
4002                 } else if (isset(attributes['points']['by'])) {
4003                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4004
4005                     for (i = 0,len = control.length; i < len; ++i) {
4006                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4007                     }
4008                 }
4009
4010                 this.runtimeAttributes[attr] = [start];
4011
4012                 if (control.length > 0) {
4013                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4014                 }
4015
4016                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4017             }
4018             else {
4019                 superclass.setRuntimeAttribute.call(this, attr);
4020             }
4021         };
4022
4023         var translateValues = function(val, start) {
4024             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4025             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4026
4027             return val;
4028         };
4029
4030         var isset = function(prop) {
4031             return (typeof prop !== 'undefined');
4032         };
4033     })();
4034 /*
4035  * Portions of this file are based on pieces of Yahoo User Interface Library
4036  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4037  * YUI licensed under the BSD License:
4038  * http://developer.yahoo.net/yui/license.txt
4039  * <script type="text/javascript">
4040  *
4041  */
4042     (function() {
4043         Roo.lib.Scroll = function(el, attributes, duration, method) {
4044             if (el) {
4045                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4046             }
4047         };
4048
4049         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4050
4051
4052         var Y = Roo.lib;
4053         var superclass = Y.Scroll.superclass;
4054         var proto = Y.Scroll.prototype;
4055
4056         proto.toString = function() {
4057             var el = this.getEl();
4058             var id = el.id || el.tagName;
4059             return ("Scroll " + id);
4060         };
4061
4062         proto.doMethod = function(attr, start, end) {
4063             var val = null;
4064
4065             if (attr == 'scroll') {
4066                 val = [
4067                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4068                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4069                         ];
4070
4071             } else {
4072                 val = superclass.doMethod.call(this, attr, start, end);
4073             }
4074             return val;
4075         };
4076
4077         proto.getAttribute = function(attr) {
4078             var val = null;
4079             var el = this.getEl();
4080
4081             if (attr == 'scroll') {
4082                 val = [ el.scrollLeft, el.scrollTop ];
4083             } else {
4084                 val = superclass.getAttribute.call(this, attr);
4085             }
4086
4087             return val;
4088         };
4089
4090         proto.setAttribute = function(attr, val, unit) {
4091             var el = this.getEl();
4092
4093             if (attr == 'scroll') {
4094                 el.scrollLeft = val[0];
4095                 el.scrollTop = val[1];
4096             } else {
4097                 superclass.setAttribute.call(this, attr, val, unit);
4098             }
4099         };
4100     })();
4101 /*
4102  * Based on:
4103  * Ext JS Library 1.1.1
4104  * Copyright(c) 2006-2007, Ext JS, LLC.
4105  *
4106  * Originally Released Under LGPL - original licence link has changed is not relivant.
4107  *
4108  * Fork - LGPL
4109  * <script type="text/javascript">
4110  */
4111
4112
4113 // nasty IE9 hack - what a pile of crap that is..
4114
4115  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4116     Range.prototype.createContextualFragment = function (html) {
4117         var doc = window.document;
4118         var container = doc.createElement("div");
4119         container.innerHTML = html;
4120         var frag = doc.createDocumentFragment(), n;
4121         while ((n = container.firstChild)) {
4122             frag.appendChild(n);
4123         }
4124         return frag;
4125     };
4126 }
4127
4128 /**
4129  * @class Roo.DomHelper
4130  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4131  * 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>.
4132  * @singleton
4133  */
4134 Roo.DomHelper = function(){
4135     var tempTableEl = null;
4136     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4137     var tableRe = /^table|tbody|tr|td$/i;
4138     var xmlns = {};
4139     // build as innerHTML where available
4140     /** @ignore */
4141     var createHtml = function(o){
4142         if(typeof o == 'string'){
4143             return o;
4144         }
4145         var b = "";
4146         if(!o.tag){
4147             o.tag = "div";
4148         }
4149         b += "<" + o.tag;
4150         for(var attr in o){
4151             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4152             if(attr == "style"){
4153                 var s = o["style"];
4154                 if(typeof s == "function"){
4155                     s = s.call();
4156                 }
4157                 if(typeof s == "string"){
4158                     b += ' style="' + s + '"';
4159                 }else if(typeof s == "object"){
4160                     b += ' style="';
4161                     for(var key in s){
4162                         if(typeof s[key] != "function"){
4163                             b += key + ":" + s[key] + ";";
4164                         }
4165                     }
4166                     b += '"';
4167                 }
4168             }else{
4169                 if(attr == "cls"){
4170                     b += ' class="' + o["cls"] + '"';
4171                 }else if(attr == "htmlFor"){
4172                     b += ' for="' + o["htmlFor"] + '"';
4173                 }else{
4174                     b += " " + attr + '="' + o[attr] + '"';
4175                 }
4176             }
4177         }
4178         if(emptyTags.test(o.tag)){
4179             b += "/>";
4180         }else{
4181             b += ">";
4182             var cn = o.children || o.cn;
4183             if(cn){
4184                 //http://bugs.kde.org/show_bug.cgi?id=71506
4185                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4186                     for(var i = 0, len = cn.length; i < len; i++) {
4187                         b += createHtml(cn[i], b);
4188                     }
4189                 }else{
4190                     b += createHtml(cn, b);
4191                 }
4192             }
4193             if(o.html){
4194                 b += o.html;
4195             }
4196             b += "</" + o.tag + ">";
4197         }
4198         return b;
4199     };
4200
4201     // build as dom
4202     /** @ignore */
4203     var createDom = function(o, parentNode){
4204          
4205         // defininition craeted..
4206         var ns = false;
4207         if (o.ns && o.ns != 'html') {
4208                
4209             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4210                 xmlns[o.ns] = o.xmlns;
4211                 ns = o.xmlns;
4212             }
4213             if (typeof(xmlns[o.ns]) == 'undefined') {
4214                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4215             }
4216             ns = xmlns[o.ns];
4217         }
4218         
4219         
4220         if (typeof(o) == 'string') {
4221             return parentNode.appendChild(document.createTextNode(o));
4222         }
4223         o.tag = o.tag || div;
4224         if (o.ns && Roo.isIE) {
4225             ns = false;
4226             o.tag = o.ns + ':' + o.tag;
4227             
4228         }
4229         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4230         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4231         for(var attr in o){
4232             
4233             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4234                     attr == "style" || typeof o[attr] == "function") continue;
4235                     
4236             if(attr=="cls" && Roo.isIE){
4237                 el.className = o["cls"];
4238             }else{
4239                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4240                 else el[attr] = o[attr];
4241             }
4242         }
4243         Roo.DomHelper.applyStyles(el, o.style);
4244         var cn = o.children || o.cn;
4245         if(cn){
4246             //http://bugs.kde.org/show_bug.cgi?id=71506
4247              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4248                 for(var i = 0, len = cn.length; i < len; i++) {
4249                     createDom(cn[i], el);
4250                 }
4251             }else{
4252                 createDom(cn, el);
4253             }
4254         }
4255         if(o.html){
4256             el.innerHTML = o.html;
4257         }
4258         if(parentNode){
4259            parentNode.appendChild(el);
4260         }
4261         return el;
4262     };
4263
4264     var ieTable = function(depth, s, h, e){
4265         tempTableEl.innerHTML = [s, h, e].join('');
4266         var i = -1, el = tempTableEl;
4267         while(++i < depth){
4268             el = el.firstChild;
4269         }
4270         return el;
4271     };
4272
4273     // kill repeat to save bytes
4274     var ts = '<table>',
4275         te = '</table>',
4276         tbs = ts+'<tbody>',
4277         tbe = '</tbody>'+te,
4278         trs = tbs + '<tr>',
4279         tre = '</tr>'+tbe;
4280
4281     /**
4282      * @ignore
4283      * Nasty code for IE's broken table implementation
4284      */
4285     var insertIntoTable = function(tag, where, el, html){
4286         if(!tempTableEl){
4287             tempTableEl = document.createElement('div');
4288         }
4289         var node;
4290         var before = null;
4291         if(tag == 'td'){
4292             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4293                 return;
4294             }
4295             if(where == 'beforebegin'){
4296                 before = el;
4297                 el = el.parentNode;
4298             } else{
4299                 before = el.nextSibling;
4300                 el = el.parentNode;
4301             }
4302             node = ieTable(4, trs, html, tre);
4303         }
4304         else if(tag == 'tr'){
4305             if(where == 'beforebegin'){
4306                 before = el;
4307                 el = el.parentNode;
4308                 node = ieTable(3, tbs, html, tbe);
4309             } else if(where == 'afterend'){
4310                 before = el.nextSibling;
4311                 el = el.parentNode;
4312                 node = ieTable(3, tbs, html, tbe);
4313             } else{ // INTO a TR
4314                 if(where == 'afterbegin'){
4315                     before = el.firstChild;
4316                 }
4317                 node = ieTable(4, trs, html, tre);
4318             }
4319         } else if(tag == 'tbody'){
4320             if(where == 'beforebegin'){
4321                 before = el;
4322                 el = el.parentNode;
4323                 node = ieTable(2, ts, html, te);
4324             } else if(where == 'afterend'){
4325                 before = el.nextSibling;
4326                 el = el.parentNode;
4327                 node = ieTable(2, ts, html, te);
4328             } else{
4329                 if(where == 'afterbegin'){
4330                     before = el.firstChild;
4331                 }
4332                 node = ieTable(3, tbs, html, tbe);
4333             }
4334         } else{ // TABLE
4335             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4336                 return;
4337             }
4338             if(where == 'afterbegin'){
4339                 before = el.firstChild;
4340             }
4341             node = ieTable(2, ts, html, te);
4342         }
4343         el.insertBefore(node, before);
4344         return node;
4345     };
4346
4347     return {
4348     /** True to force the use of DOM instead of html fragments @type Boolean */
4349     useDom : false,
4350
4351     /**
4352      * Returns the markup for the passed Element(s) config
4353      * @param {Object} o The Dom object spec (and children)
4354      * @return {String}
4355      */
4356     markup : function(o){
4357         return createHtml(o);
4358     },
4359
4360     /**
4361      * Applies a style specification to an element
4362      * @param {String/HTMLElement} el The element to apply styles to
4363      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4364      * a function which returns such a specification.
4365      */
4366     applyStyles : function(el, styles){
4367         if(styles){
4368            el = Roo.fly(el);
4369            if(typeof styles == "string"){
4370                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4371                var matches;
4372                while ((matches = re.exec(styles)) != null){
4373                    el.setStyle(matches[1], matches[2]);
4374                }
4375            }else if (typeof styles == "object"){
4376                for (var style in styles){
4377                   el.setStyle(style, styles[style]);
4378                }
4379            }else if (typeof styles == "function"){
4380                 Roo.DomHelper.applyStyles(el, styles.call());
4381            }
4382         }
4383     },
4384
4385     /**
4386      * Inserts an HTML fragment into the Dom
4387      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4388      * @param {HTMLElement} el The context element
4389      * @param {String} html The HTML fragmenet
4390      * @return {HTMLElement} The new node
4391      */
4392     insertHtml : function(where, el, html){
4393         where = where.toLowerCase();
4394         if(el.insertAdjacentHTML){
4395             if(tableRe.test(el.tagName)){
4396                 var rs;
4397                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4398                     return rs;
4399                 }
4400             }
4401             switch(where){
4402                 case "beforebegin":
4403                     el.insertAdjacentHTML('BeforeBegin', html);
4404                     return el.previousSibling;
4405                 case "afterbegin":
4406                     el.insertAdjacentHTML('AfterBegin', html);
4407                     return el.firstChild;
4408                 case "beforeend":
4409                     el.insertAdjacentHTML('BeforeEnd', html);
4410                     return el.lastChild;
4411                 case "afterend":
4412                     el.insertAdjacentHTML('AfterEnd', html);
4413                     return el.nextSibling;
4414             }
4415             throw 'Illegal insertion point -> "' + where + '"';
4416         }
4417         var range = el.ownerDocument.createRange();
4418         var frag;
4419         switch(where){
4420              case "beforebegin":
4421                 range.setStartBefore(el);
4422                 frag = range.createContextualFragment(html);
4423                 el.parentNode.insertBefore(frag, el);
4424                 return el.previousSibling;
4425              case "afterbegin":
4426                 if(el.firstChild){
4427                     range.setStartBefore(el.firstChild);
4428                     frag = range.createContextualFragment(html);
4429                     el.insertBefore(frag, el.firstChild);
4430                     return el.firstChild;
4431                 }else{
4432                     el.innerHTML = html;
4433                     return el.firstChild;
4434                 }
4435             case "beforeend":
4436                 if(el.lastChild){
4437                     range.setStartAfter(el.lastChild);
4438                     frag = range.createContextualFragment(html);
4439                     el.appendChild(frag);
4440                     return el.lastChild;
4441                 }else{
4442                     el.innerHTML = html;
4443                     return el.lastChild;
4444                 }
4445             case "afterend":
4446                 range.setStartAfter(el);
4447                 frag = range.createContextualFragment(html);
4448                 el.parentNode.insertBefore(frag, el.nextSibling);
4449                 return el.nextSibling;
4450             }
4451             throw 'Illegal insertion point -> "' + where + '"';
4452     },
4453
4454     /**
4455      * Creates new Dom element(s) and inserts them before el
4456      * @param {String/HTMLElement/Element} el The context element
4457      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4458      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4459      * @return {HTMLElement/Roo.Element} The new node
4460      */
4461     insertBefore : function(el, o, returnElement){
4462         return this.doInsert(el, o, returnElement, "beforeBegin");
4463     },
4464
4465     /**
4466      * Creates new Dom element(s) and inserts them after el
4467      * @param {String/HTMLElement/Element} el The context element
4468      * @param {Object} o The Dom object spec (and children)
4469      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4470      * @return {HTMLElement/Roo.Element} The new node
4471      */
4472     insertAfter : function(el, o, returnElement){
4473         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4474     },
4475
4476     /**
4477      * Creates new Dom element(s) and inserts them as the first child of el
4478      * @param {String/HTMLElement/Element} el The context element
4479      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4480      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4481      * @return {HTMLElement/Roo.Element} The new node
4482      */
4483     insertFirst : function(el, o, returnElement){
4484         return this.doInsert(el, o, returnElement, "afterBegin");
4485     },
4486
4487     // private
4488     doInsert : function(el, o, returnElement, pos, sibling){
4489         el = Roo.getDom(el);
4490         var newNode;
4491         if(this.useDom || o.ns){
4492             newNode = createDom(o, null);
4493             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4494         }else{
4495             var html = createHtml(o);
4496             newNode = this.insertHtml(pos, el, html);
4497         }
4498         return returnElement ? Roo.get(newNode, true) : newNode;
4499     },
4500
4501     /**
4502      * Creates new Dom element(s) and appends them to el
4503      * @param {String/HTMLElement/Element} el The context element
4504      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506      * @return {HTMLElement/Roo.Element} The new node
4507      */
4508     append : function(el, o, returnElement){
4509         el = Roo.getDom(el);
4510         var newNode;
4511         if(this.useDom || o.ns){
4512             newNode = createDom(o, null);
4513             el.appendChild(newNode);
4514         }else{
4515             var html = createHtml(o);
4516             newNode = this.insertHtml("beforeEnd", el, html);
4517         }
4518         return returnElement ? Roo.get(newNode, true) : newNode;
4519     },
4520
4521     /**
4522      * Creates new Dom element(s) and overwrites the contents of el with them
4523      * @param {String/HTMLElement/Element} el The context element
4524      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4525      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4526      * @return {HTMLElement/Roo.Element} The new node
4527      */
4528     overwrite : function(el, o, returnElement){
4529         el = Roo.getDom(el);
4530         if (o.ns) {
4531           
4532             while (el.childNodes.length) {
4533                 el.removeChild(el.firstChild);
4534             }
4535             createDom(o, el);
4536         } else {
4537             el.innerHTML = createHtml(o);   
4538         }
4539         
4540         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4541     },
4542
4543     /**
4544      * Creates a new Roo.DomHelper.Template from the Dom object spec
4545      * @param {Object} o The Dom object spec (and children)
4546      * @return {Roo.DomHelper.Template} The new template
4547      */
4548     createTemplate : function(o){
4549         var html = createHtml(o);
4550         return new Roo.Template(html);
4551     }
4552     };
4553 }();
4554 /*
4555  * Based on:
4556  * Ext JS Library 1.1.1
4557  * Copyright(c) 2006-2007, Ext JS, LLC.
4558  *
4559  * Originally Released Under LGPL - original licence link has changed is not relivant.
4560  *
4561  * Fork - LGPL
4562  * <script type="text/javascript">
4563  */
4564  
4565 /**
4566 * @class Roo.Template
4567 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4568 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4569 * Usage:
4570 <pre><code>
4571 var t = new Roo.Template({
4572     html :  '&lt;div name="{id}"&gt;' + 
4573         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4574         '&lt;/div&gt;',
4575     myformat: function (value, allValues) {
4576         return 'XX' + value;
4577     }
4578 });
4579 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4580 </code></pre>
4581 * For more information see this blog post with examples:
4582 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4583      - Create Elements using DOM, HTML fragments and Templates</a>. 
4584 * @constructor
4585 * @param {Object} cfg - Configuration object.
4586 */
4587 Roo.Template = function(cfg){
4588     // BC!
4589     if(cfg instanceof Array){
4590         cfg = cfg.join("");
4591     }else if(arguments.length > 1){
4592         cfg = Array.prototype.join.call(arguments, "");
4593     }
4594     
4595     
4596     if (typeof(cfg) == 'object') {
4597         Roo.apply(this,cfg)
4598     } else {
4599         // bc
4600         this.html = cfg;
4601     }
4602     if (this.url) {
4603         this.load();
4604     }
4605     
4606 };
4607 Roo.Template.prototype = {
4608     
4609     /**
4610      * @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..
4611      *                    it should be fixed so that template is observable...
4612      */
4613     url : false,
4614     /**
4615      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4616      */
4617     html : '',
4618     /**
4619      * Returns an HTML fragment of this template with the specified values applied.
4620      * @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'})
4621      * @return {String} The HTML fragment
4622      */
4623     applyTemplate : function(values){
4624         try {
4625            
4626             if(this.compiled){
4627                 return this.compiled(values);
4628             }
4629             var useF = this.disableFormats !== true;
4630             var fm = Roo.util.Format, tpl = this;
4631             var fn = function(m, name, format, args){
4632                 if(format && useF){
4633                     if(format.substr(0, 5) == "this."){
4634                         return tpl.call(format.substr(5), values[name], values);
4635                     }else{
4636                         if(args){
4637                             // quoted values are required for strings in compiled templates, 
4638                             // but for non compiled we need to strip them
4639                             // quoted reversed for jsmin
4640                             var re = /^\s*['"](.*)["']\s*$/;
4641                             args = args.split(',');
4642                             for(var i = 0, len = args.length; i < len; i++){
4643                                 args[i] = args[i].replace(re, "$1");
4644                             }
4645                             args = [values[name]].concat(args);
4646                         }else{
4647                             args = [values[name]];
4648                         }
4649                         return fm[format].apply(fm, args);
4650                     }
4651                 }else{
4652                     return values[name] !== undefined ? values[name] : "";
4653                 }
4654             };
4655             return this.html.replace(this.re, fn);
4656         } catch (e) {
4657             Roo.log(e);
4658             throw e;
4659         }
4660          
4661     },
4662     
4663     loading : false,
4664       
4665     load : function ()
4666     {
4667          
4668         if (this.loading) {
4669             return;
4670         }
4671         var _t = this;
4672         
4673         this.loading = true;
4674         this.compiled = false;
4675         
4676         var cx = new Roo.data.Connection();
4677         cx.request({
4678             url : this.url,
4679             method : 'GET',
4680             success : function (response) {
4681                 _t.loading = false;
4682                 _t.html = response.responseText;
4683                 _t.url = false;
4684                 _t.compile();
4685              },
4686             failure : function(response) {
4687                 Roo.log("Template failed to load from " + _t.url);
4688                 _t.loading = false;
4689             }
4690         });
4691     },
4692
4693     /**
4694      * Sets the HTML used as the template and optionally compiles it.
4695      * @param {String} html
4696      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4697      * @return {Roo.Template} this
4698      */
4699     set : function(html, compile){
4700         this.html = html;
4701         this.compiled = null;
4702         if(compile){
4703             this.compile();
4704         }
4705         return this;
4706     },
4707     
4708     /**
4709      * True to disable format functions (defaults to false)
4710      * @type Boolean
4711      */
4712     disableFormats : false,
4713     
4714     /**
4715     * The regular expression used to match template variables 
4716     * @type RegExp
4717     * @property 
4718     */
4719     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4720     
4721     /**
4722      * Compiles the template into an internal function, eliminating the RegEx overhead.
4723      * @return {Roo.Template} this
4724      */
4725     compile : function(){
4726         var fm = Roo.util.Format;
4727         var useF = this.disableFormats !== true;
4728         var sep = Roo.isGecko ? "+" : ",";
4729         var fn = function(m, name, format, args){
4730             if(format && useF){
4731                 args = args ? ',' + args : "";
4732                 if(format.substr(0, 5) != "this."){
4733                     format = "fm." + format + '(';
4734                 }else{
4735                     format = 'this.call("'+ format.substr(5) + '", ';
4736                     args = ", values";
4737                 }
4738             }else{
4739                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4740             }
4741             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4742         };
4743         var body;
4744         // branched to use + in gecko and [].join() in others
4745         if(Roo.isGecko){
4746             body = "this.compiled = function(values){ return '" +
4747                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4748                     "';};";
4749         }else{
4750             body = ["this.compiled = function(values){ return ['"];
4751             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4752             body.push("'].join('');};");
4753             body = body.join('');
4754         }
4755         /**
4756          * eval:var:values
4757          * eval:var:fm
4758          */
4759         eval(body);
4760         return this;
4761     },
4762     
4763     // private function used to call members
4764     call : function(fnName, value, allValues){
4765         return this[fnName](value, allValues);
4766     },
4767     
4768     /**
4769      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4770      * @param {String/HTMLElement/Roo.Element} el The context element
4771      * @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'})
4772      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4773      * @return {HTMLElement/Roo.Element} The new node or Element
4774      */
4775     insertFirst: function(el, values, returnElement){
4776         return this.doInsert('afterBegin', el, values, returnElement);
4777     },
4778
4779     /**
4780      * Applies the supplied values to the template and inserts the new node(s) before el.
4781      * @param {String/HTMLElement/Roo.Element} el The context element
4782      * @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'})
4783      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4784      * @return {HTMLElement/Roo.Element} The new node or Element
4785      */
4786     insertBefore: function(el, values, returnElement){
4787         return this.doInsert('beforeBegin', el, values, returnElement);
4788     },
4789
4790     /**
4791      * Applies the supplied values to the template and inserts the new node(s) after el.
4792      * @param {String/HTMLElement/Roo.Element} el The context element
4793      * @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'})
4794      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4795      * @return {HTMLElement/Roo.Element} The new node or Element
4796      */
4797     insertAfter : function(el, values, returnElement){
4798         return this.doInsert('afterEnd', el, values, returnElement);
4799     },
4800     
4801     /**
4802      * Applies the supplied values to the template and appends the new node(s) to el.
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     append : function(el, values, returnElement){
4809         return this.doInsert('beforeEnd', el, values, returnElement);
4810     },
4811
4812     doInsert : function(where, el, values, returnEl){
4813         el = Roo.getDom(el);
4814         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4815         return returnEl ? Roo.get(newNode, true) : newNode;
4816     },
4817
4818     /**
4819      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4820      * @param {String/HTMLElement/Roo.Element} el The context element
4821      * @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'})
4822      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4823      * @return {HTMLElement/Roo.Element} The new node or Element
4824      */
4825     overwrite : function(el, values, returnElement){
4826         el = Roo.getDom(el);
4827         el.innerHTML = this.applyTemplate(values);
4828         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4829     }
4830 };
4831 /**
4832  * Alias for {@link #applyTemplate}
4833  * @method
4834  */
4835 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4836
4837 // backwards compat
4838 Roo.DomHelper.Template = Roo.Template;
4839
4840 /**
4841  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4842  * @param {String/HTMLElement} el A DOM element or its id
4843  * @returns {Roo.Template} The created template
4844  * @static
4845  */
4846 Roo.Template.from = function(el){
4847     el = Roo.getDom(el);
4848     return new Roo.Template(el.value || el.innerHTML);
4849 };/*
4850  * Based on:
4851  * Ext JS Library 1.1.1
4852  * Copyright(c) 2006-2007, Ext JS, LLC.
4853  *
4854  * Originally Released Under LGPL - original licence link has changed is not relivant.
4855  *
4856  * Fork - LGPL
4857  * <script type="text/javascript">
4858  */
4859  
4860
4861 /*
4862  * This is code is also distributed under MIT license for use
4863  * with jQuery and prototype JavaScript libraries.
4864  */
4865 /**
4866  * @class Roo.DomQuery
4867 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).
4868 <p>
4869 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>
4870
4871 <p>
4872 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.
4873 </p>
4874 <h4>Element Selectors:</h4>
4875 <ul class="list">
4876     <li> <b>*</b> any element</li>
4877     <li> <b>E</b> an element with the tag E</li>
4878     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4879     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4880     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4881     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4882 </ul>
4883 <h4>Attribute Selectors:</h4>
4884 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4885 <ul class="list">
4886     <li> <b>E[foo]</b> has an attribute "foo"</li>
4887     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4888     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4889     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4890     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4891     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4892     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4893 </ul>
4894 <h4>Pseudo Classes:</h4>
4895 <ul class="list">
4896     <li> <b>E:first-child</b> E is the first child of its parent</li>
4897     <li> <b>E:last-child</b> E is the last child of its parent</li>
4898     <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>
4899     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4900     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4901     <li> <b>E:only-child</b> E is the only child of its parent</li>
4902     <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>
4903     <li> <b>E:first</b> the first E in the resultset</li>
4904     <li> <b>E:last</b> the last E in the resultset</li>
4905     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4906     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4907     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4908     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4909     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4910     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4911     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4912     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4913     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4914 </ul>
4915 <h4>CSS Value Selectors:</h4>
4916 <ul class="list">
4917     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4918     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4919     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4920     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4921     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4922     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4923 </ul>
4924  * @singleton
4925  */
4926 Roo.DomQuery = function(){
4927     var cache = {}, simpleCache = {}, valueCache = {};
4928     var nonSpace = /\S/;
4929     var trimRe = /^\s+|\s+$/g;
4930     var tplRe = /\{(\d+)\}/g;
4931     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4932     var tagTokenRe = /^(#)?([\w-\*]+)/;
4933     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4934
4935     function child(p, index){
4936         var i = 0;
4937         var n = p.firstChild;
4938         while(n){
4939             if(n.nodeType == 1){
4940                if(++i == index){
4941                    return n;
4942                }
4943             }
4944             n = n.nextSibling;
4945         }
4946         return null;
4947     };
4948
4949     function next(n){
4950         while((n = n.nextSibling) && n.nodeType != 1);
4951         return n;
4952     };
4953
4954     function prev(n){
4955         while((n = n.previousSibling) && n.nodeType != 1);
4956         return n;
4957     };
4958
4959     function children(d){
4960         var n = d.firstChild, ni = -1;
4961             while(n){
4962                 var nx = n.nextSibling;
4963                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4964                     d.removeChild(n);
4965                 }else{
4966                     n.nodeIndex = ++ni;
4967                 }
4968                 n = nx;
4969             }
4970             return this;
4971         };
4972
4973     function byClassName(c, a, v){
4974         if(!v){
4975             return c;
4976         }
4977         var r = [], ri = -1, cn;
4978         for(var i = 0, ci; ci = c[i]; i++){
4979             if((' '+ci.className+' ').indexOf(v) != -1){
4980                 r[++ri] = ci;
4981             }
4982         }
4983         return r;
4984     };
4985
4986     function attrValue(n, attr){
4987         if(!n.tagName && typeof n.length != "undefined"){
4988             n = n[0];
4989         }
4990         if(!n){
4991             return null;
4992         }
4993         if(attr == "for"){
4994             return n.htmlFor;
4995         }
4996         if(attr == "class" || attr == "className"){
4997             return n.className;
4998         }
4999         return n.getAttribute(attr) || n[attr];
5000
5001     };
5002
5003     function getNodes(ns, mode, tagName){
5004         var result = [], ri = -1, cs;
5005         if(!ns){
5006             return result;
5007         }
5008         tagName = tagName || "*";
5009         if(typeof ns.getElementsByTagName != "undefined"){
5010             ns = [ns];
5011         }
5012         if(!mode){
5013             for(var i = 0, ni; ni = ns[i]; i++){
5014                 cs = ni.getElementsByTagName(tagName);
5015                 for(var j = 0, ci; ci = cs[j]; j++){
5016                     result[++ri] = ci;
5017                 }
5018             }
5019         }else if(mode == "/" || mode == ">"){
5020             var utag = tagName.toUpperCase();
5021             for(var i = 0, ni, cn; ni = ns[i]; i++){
5022                 cn = ni.children || ni.childNodes;
5023                 for(var j = 0, cj; cj = cn[j]; j++){
5024                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5025                         result[++ri] = cj;
5026                     }
5027                 }
5028             }
5029         }else if(mode == "+"){
5030             var utag = tagName.toUpperCase();
5031             for(var i = 0, n; n = ns[i]; i++){
5032                 while((n = n.nextSibling) && n.nodeType != 1);
5033                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5034                     result[++ri] = n;
5035                 }
5036             }
5037         }else if(mode == "~"){
5038             for(var i = 0, n; n = ns[i]; i++){
5039                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5040                 if(n){
5041                     result[++ri] = n;
5042                 }
5043             }
5044         }
5045         return result;
5046     };
5047
5048     function concat(a, b){
5049         if(b.slice){
5050             return a.concat(b);
5051         }
5052         for(var i = 0, l = b.length; i < l; i++){
5053             a[a.length] = b[i];
5054         }
5055         return a;
5056     }
5057
5058     function byTag(cs, tagName){
5059         if(cs.tagName || cs == document){
5060             cs = [cs];
5061         }
5062         if(!tagName){
5063             return cs;
5064         }
5065         var r = [], ri = -1;
5066         tagName = tagName.toLowerCase();
5067         for(var i = 0, ci; ci = cs[i]; i++){
5068             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5069                 r[++ri] = ci;
5070             }
5071         }
5072         return r;
5073     };
5074
5075     function byId(cs, attr, id){
5076         if(cs.tagName || cs == document){
5077             cs = [cs];
5078         }
5079         if(!id){
5080             return cs;
5081         }
5082         var r = [], ri = -1;
5083         for(var i = 0,ci; ci = cs[i]; i++){
5084             if(ci && ci.id == id){
5085                 r[++ri] = ci;
5086                 return r;
5087             }
5088         }
5089         return r;
5090     };
5091
5092     function byAttribute(cs, attr, value, op, custom){
5093         var r = [], ri = -1, st = custom=="{";
5094         var f = Roo.DomQuery.operators[op];
5095         for(var i = 0, ci; ci = cs[i]; i++){
5096             var a;
5097             if(st){
5098                 a = Roo.DomQuery.getStyle(ci, attr);
5099             }
5100             else if(attr == "class" || attr == "className"){
5101                 a = ci.className;
5102             }else if(attr == "for"){
5103                 a = ci.htmlFor;
5104             }else if(attr == "href"){
5105                 a = ci.getAttribute("href", 2);
5106             }else{
5107                 a = ci.getAttribute(attr);
5108             }
5109             if((f && f(a, value)) || (!f && a)){
5110                 r[++ri] = ci;
5111             }
5112         }
5113         return r;
5114     };
5115
5116     function byPseudo(cs, name, value){
5117         return Roo.DomQuery.pseudos[name](cs, value);
5118     };
5119
5120     // This is for IE MSXML which does not support expandos.
5121     // IE runs the same speed using setAttribute, however FF slows way down
5122     // and Safari completely fails so they need to continue to use expandos.
5123     var isIE = window.ActiveXObject ? true : false;
5124
5125     // this eval is stop the compressor from
5126     // renaming the variable to something shorter
5127     
5128     /** eval:var:batch */
5129     var batch = 30803; 
5130
5131     var key = 30803;
5132
5133     function nodupIEXml(cs){
5134         var d = ++key;
5135         cs[0].setAttribute("_nodup", d);
5136         var r = [cs[0]];
5137         for(var i = 1, len = cs.length; i < len; i++){
5138             var c = cs[i];
5139             if(!c.getAttribute("_nodup") != d){
5140                 c.setAttribute("_nodup", d);
5141                 r[r.length] = c;
5142             }
5143         }
5144         for(var i = 0, len = cs.length; i < len; i++){
5145             cs[i].removeAttribute("_nodup");
5146         }
5147         return r;
5148     }
5149
5150     function nodup(cs){
5151         if(!cs){
5152             return [];
5153         }
5154         var len = cs.length, c, i, r = cs, cj, ri = -1;
5155         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5156             return cs;
5157         }
5158         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5159             return nodupIEXml(cs);
5160         }
5161         var d = ++key;
5162         cs[0]._nodup = d;
5163         for(i = 1; c = cs[i]; i++){
5164             if(c._nodup != d){
5165                 c._nodup = d;
5166             }else{
5167                 r = [];
5168                 for(var j = 0; j < i; j++){
5169                     r[++ri] = cs[j];
5170                 }
5171                 for(j = i+1; cj = cs[j]; j++){
5172                     if(cj._nodup != d){
5173                         cj._nodup = d;
5174                         r[++ri] = cj;
5175                     }
5176                 }
5177                 return r;
5178             }
5179         }
5180         return r;
5181     }
5182
5183     function quickDiffIEXml(c1, c2){
5184         var d = ++key;
5185         for(var i = 0, len = c1.length; i < len; i++){
5186             c1[i].setAttribute("_qdiff", d);
5187         }
5188         var r = [];
5189         for(var i = 0, len = c2.length; i < len; i++){
5190             if(c2[i].getAttribute("_qdiff") != d){
5191                 r[r.length] = c2[i];
5192             }
5193         }
5194         for(var i = 0, len = c1.length; i < len; i++){
5195            c1[i].removeAttribute("_qdiff");
5196         }
5197         return r;
5198     }
5199
5200     function quickDiff(c1, c2){
5201         var len1 = c1.length;
5202         if(!len1){
5203             return c2;
5204         }
5205         if(isIE && c1[0].selectSingleNode){
5206             return quickDiffIEXml(c1, c2);
5207         }
5208         var d = ++key;
5209         for(var i = 0; i < len1; i++){
5210             c1[i]._qdiff = d;
5211         }
5212         var r = [];
5213         for(var i = 0, len = c2.length; i < len; i++){
5214             if(c2[i]._qdiff != d){
5215                 r[r.length] = c2[i];
5216             }
5217         }
5218         return r;
5219     }
5220
5221     function quickId(ns, mode, root, id){
5222         if(ns == root){
5223            var d = root.ownerDocument || root;
5224            return d.getElementById(id);
5225         }
5226         ns = getNodes(ns, mode, "*");
5227         return byId(ns, null, id);
5228     }
5229
5230     return {
5231         getStyle : function(el, name){
5232             return Roo.fly(el).getStyle(name);
5233         },
5234         /**
5235          * Compiles a selector/xpath query into a reusable function. The returned function
5236          * takes one parameter "root" (optional), which is the context node from where the query should start.
5237          * @param {String} selector The selector/xpath query
5238          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5239          * @return {Function}
5240          */
5241         compile : function(path, type){
5242             type = type || "select";
5243             
5244             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5245             var q = path, mode, lq;
5246             var tk = Roo.DomQuery.matchers;
5247             var tklen = tk.length;
5248             var mm;
5249
5250             // accept leading mode switch
5251             var lmode = q.match(modeRe);
5252             if(lmode && lmode[1]){
5253                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5254                 q = q.replace(lmode[1], "");
5255             }
5256             // strip leading slashes
5257             while(path.substr(0, 1)=="/"){
5258                 path = path.substr(1);
5259             }
5260
5261             while(q && lq != q){
5262                 lq = q;
5263                 var tm = q.match(tagTokenRe);
5264                 if(type == "select"){
5265                     if(tm){
5266                         if(tm[1] == "#"){
5267                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5268                         }else{
5269                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5270                         }
5271                         q = q.replace(tm[0], "");
5272                     }else if(q.substr(0, 1) != '@'){
5273                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5274                     }
5275                 }else{
5276                     if(tm){
5277                         if(tm[1] == "#"){
5278                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5279                         }else{
5280                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5281                         }
5282                         q = q.replace(tm[0], "");
5283                     }
5284                 }
5285                 while(!(mm = q.match(modeRe))){
5286                     var matched = false;
5287                     for(var j = 0; j < tklen; j++){
5288                         var t = tk[j];
5289                         var m = q.match(t.re);
5290                         if(m){
5291                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5292                                                     return m[i];
5293                                                 });
5294                             q = q.replace(m[0], "");
5295                             matched = true;
5296                             break;
5297                         }
5298                     }
5299                     // prevent infinite loop on bad selector
5300                     if(!matched){
5301                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5302                     }
5303                 }
5304                 if(mm[1]){
5305                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5306                     q = q.replace(mm[1], "");
5307                 }
5308             }
5309             fn[fn.length] = "return nodup(n);\n}";
5310             
5311              /** 
5312               * list of variables that need from compression as they are used by eval.
5313              *  eval:var:batch 
5314              *  eval:var:nodup
5315              *  eval:var:byTag
5316              *  eval:var:ById
5317              *  eval:var:getNodes
5318              *  eval:var:quickId
5319              *  eval:var:mode
5320              *  eval:var:root
5321              *  eval:var:n
5322              *  eval:var:byClassName
5323              *  eval:var:byPseudo
5324              *  eval:var:byAttribute
5325              *  eval:var:attrValue
5326              * 
5327              **/ 
5328             eval(fn.join(""));
5329             return f;
5330         },
5331
5332         /**
5333          * Selects a group of elements.
5334          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5335          * @param {Node} root (optional) The start of the query (defaults to document).
5336          * @return {Array}
5337          */
5338         select : function(path, root, type){
5339             if(!root || root == document){
5340                 root = document;
5341             }
5342             if(typeof root == "string"){
5343                 root = document.getElementById(root);
5344             }
5345             var paths = path.split(",");
5346             var results = [];
5347             for(var i = 0, len = paths.length; i < len; i++){
5348                 var p = paths[i].replace(trimRe, "");
5349                 if(!cache[p]){
5350                     cache[p] = Roo.DomQuery.compile(p);
5351                     if(!cache[p]){
5352                         throw p + " is not a valid selector";
5353                     }
5354                 }
5355                 var result = cache[p](root);
5356                 if(result && result != document){
5357                     results = results.concat(result);
5358                 }
5359             }
5360             if(paths.length > 1){
5361                 return nodup(results);
5362             }
5363             return results;
5364         },
5365
5366         /**
5367          * Selects a single element.
5368          * @param {String} selector The selector/xpath query
5369          * @param {Node} root (optional) The start of the query (defaults to document).
5370          * @return {Element}
5371          */
5372         selectNode : function(path, root){
5373             return Roo.DomQuery.select(path, root)[0];
5374         },
5375
5376         /**
5377          * Selects the value of a node, optionally replacing null with the defaultValue.
5378          * @param {String} selector The selector/xpath query
5379          * @param {Node} root (optional) The start of the query (defaults to document).
5380          * @param {String} defaultValue
5381          */
5382         selectValue : function(path, root, defaultValue){
5383             path = path.replace(trimRe, "");
5384             if(!valueCache[path]){
5385                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5386             }
5387             var n = valueCache[path](root);
5388             n = n[0] ? n[0] : n;
5389             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5390             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5391         },
5392
5393         /**
5394          * Selects the value of a node, parsing integers and floats.
5395          * @param {String} selector The selector/xpath query
5396          * @param {Node} root (optional) The start of the query (defaults to document).
5397          * @param {Number} defaultValue
5398          * @return {Number}
5399          */
5400         selectNumber : function(path, root, defaultValue){
5401             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5402             return parseFloat(v);
5403         },
5404
5405         /**
5406          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5407          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5408          * @param {String} selector The simple selector to test
5409          * @return {Boolean}
5410          */
5411         is : function(el, ss){
5412             if(typeof el == "string"){
5413                 el = document.getElementById(el);
5414             }
5415             var isArray = (el instanceof Array);
5416             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5417             return isArray ? (result.length == el.length) : (result.length > 0);
5418         },
5419
5420         /**
5421          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5422          * @param {Array} el An array of elements to filter
5423          * @param {String} selector The simple selector to test
5424          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5425          * the selector instead of the ones that match
5426          * @return {Array}
5427          */
5428         filter : function(els, ss, nonMatches){
5429             ss = ss.replace(trimRe, "");
5430             if(!simpleCache[ss]){
5431                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5432             }
5433             var result = simpleCache[ss](els);
5434             return nonMatches ? quickDiff(result, els) : result;
5435         },
5436
5437         /**
5438          * Collection of matching regular expressions and code snippets.
5439          */
5440         matchers : [{
5441                 re: /^\.([\w-]+)/,
5442                 select: 'n = byClassName(n, null, " {1} ");'
5443             }, {
5444                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5445                 select: 'n = byPseudo(n, "{1}", "{2}");'
5446             },{
5447                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5448                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5449             }, {
5450                 re: /^#([\w-]+)/,
5451                 select: 'n = byId(n, null, "{1}");'
5452             },{
5453                 re: /^@([\w-]+)/,
5454                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5455             }
5456         ],
5457
5458         /**
5459          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5460          * 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;.
5461          */
5462         operators : {
5463             "=" : function(a, v){
5464                 return a == v;
5465             },
5466             "!=" : function(a, v){
5467                 return a != v;
5468             },
5469             "^=" : function(a, v){
5470                 return a && a.substr(0, v.length) == v;
5471             },
5472             "$=" : function(a, v){
5473                 return a && a.substr(a.length-v.length) == v;
5474             },
5475             "*=" : function(a, v){
5476                 return a && a.indexOf(v) !== -1;
5477             },
5478             "%=" : function(a, v){
5479                 return (a % v) == 0;
5480             },
5481             "|=" : function(a, v){
5482                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5483             },
5484             "~=" : function(a, v){
5485                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5486             }
5487         },
5488
5489         /**
5490          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5491          * and the argument (if any) supplied in the selector.
5492          */
5493         pseudos : {
5494             "first-child" : function(c){
5495                 var r = [], ri = -1, n;
5496                 for(var i = 0, ci; ci = n = c[i]; i++){
5497                     while((n = n.previousSibling) && n.nodeType != 1);
5498                     if(!n){
5499                         r[++ri] = ci;
5500                     }
5501                 }
5502                 return r;
5503             },
5504
5505             "last-child" : function(c){
5506                 var r = [], ri = -1, n;
5507                 for(var i = 0, ci; ci = n = c[i]; i++){
5508                     while((n = n.nextSibling) && n.nodeType != 1);
5509                     if(!n){
5510                         r[++ri] = ci;
5511                     }
5512                 }
5513                 return r;
5514             },
5515
5516             "nth-child" : function(c, a) {
5517                 var r = [], ri = -1;
5518                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5519                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5520                 for(var i = 0, n; n = c[i]; i++){
5521                     var pn = n.parentNode;
5522                     if (batch != pn._batch) {
5523                         var j = 0;
5524                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5525                             if(cn.nodeType == 1){
5526                                cn.nodeIndex = ++j;
5527                             }
5528                         }
5529                         pn._batch = batch;
5530                     }
5531                     if (f == 1) {
5532                         if (l == 0 || n.nodeIndex == l){
5533                             r[++ri] = n;
5534                         }
5535                     } else if ((n.nodeIndex + l) % f == 0){
5536                         r[++ri] = n;
5537                     }
5538                 }
5539
5540                 return r;
5541             },
5542
5543             "only-child" : function(c){
5544                 var r = [], ri = -1;;
5545                 for(var i = 0, ci; ci = c[i]; i++){
5546                     if(!prev(ci) && !next(ci)){
5547                         r[++ri] = ci;
5548                     }
5549                 }
5550                 return r;
5551             },
5552
5553             "empty" : function(c){
5554                 var r = [], ri = -1;
5555                 for(var i = 0, ci; ci = c[i]; i++){
5556                     var cns = ci.childNodes, j = 0, cn, empty = true;
5557                     while(cn = cns[j]){
5558                         ++j;
5559                         if(cn.nodeType == 1 || cn.nodeType == 3){
5560                             empty = false;
5561                             break;
5562                         }
5563                     }
5564                     if(empty){
5565                         r[++ri] = ci;
5566                     }
5567                 }
5568                 return r;
5569             },
5570
5571             "contains" : function(c, v){
5572                 var r = [], ri = -1;
5573                 for(var i = 0, ci; ci = c[i]; i++){
5574                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5575                         r[++ri] = ci;
5576                     }
5577                 }
5578                 return r;
5579             },
5580
5581             "nodeValue" : function(c, v){
5582                 var r = [], ri = -1;
5583                 for(var i = 0, ci; ci = c[i]; i++){
5584                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5585                         r[++ri] = ci;
5586                     }
5587                 }
5588                 return r;
5589             },
5590
5591             "checked" : function(c){
5592                 var r = [], ri = -1;
5593                 for(var i = 0, ci; ci = c[i]; i++){
5594                     if(ci.checked == true){
5595                         r[++ri] = ci;
5596                     }
5597                 }
5598                 return r;
5599             },
5600
5601             "not" : function(c, ss){
5602                 return Roo.DomQuery.filter(c, ss, true);
5603             },
5604
5605             "odd" : function(c){
5606                 return this["nth-child"](c, "odd");
5607             },
5608
5609             "even" : function(c){
5610                 return this["nth-child"](c, "even");
5611             },
5612
5613             "nth" : function(c, a){
5614                 return c[a-1] || [];
5615             },
5616
5617             "first" : function(c){
5618                 return c[0] || [];
5619             },
5620
5621             "last" : function(c){
5622                 return c[c.length-1] || [];
5623             },
5624
5625             "has" : function(c, ss){
5626                 var s = Roo.DomQuery.select;
5627                 var r = [], ri = -1;
5628                 for(var i = 0, ci; ci = c[i]; i++){
5629                     if(s(ss, ci).length > 0){
5630                         r[++ri] = ci;
5631                     }
5632                 }
5633                 return r;
5634             },
5635
5636             "next" : function(c, ss){
5637                 var is = Roo.DomQuery.is;
5638                 var r = [], ri = -1;
5639                 for(var i = 0, ci; ci = c[i]; i++){
5640                     var n = next(ci);
5641                     if(n && is(n, ss)){
5642                         r[++ri] = ci;
5643                     }
5644                 }
5645                 return r;
5646             },
5647
5648             "prev" : function(c, ss){
5649                 var is = Roo.DomQuery.is;
5650                 var r = [], ri = -1;
5651                 for(var i = 0, ci; ci = c[i]; i++){
5652                     var n = prev(ci);
5653                     if(n && is(n, ss)){
5654                         r[++ri] = ci;
5655                     }
5656                 }
5657                 return r;
5658             }
5659         }
5660     };
5661 }();
5662
5663 /**
5664  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5665  * @param {String} path The selector/xpath query
5666  * @param {Node} root (optional) The start of the query (defaults to document).
5667  * @return {Array}
5668  * @member Roo
5669  * @method query
5670  */
5671 Roo.query = Roo.DomQuery.select;
5672 /*
5673  * Based on:
5674  * Ext JS Library 1.1.1
5675  * Copyright(c) 2006-2007, Ext JS, LLC.
5676  *
5677  * Originally Released Under LGPL - original licence link has changed is not relivant.
5678  *
5679  * Fork - LGPL
5680  * <script type="text/javascript">
5681  */
5682
5683 /**
5684  * @class Roo.util.Observable
5685  * Base class that provides a common interface for publishing events. Subclasses are expected to
5686  * to have a property "events" with all the events defined.<br>
5687  * For example:
5688  * <pre><code>
5689  Employee = function(name){
5690     this.name = name;
5691     this.addEvents({
5692         "fired" : true,
5693         "quit" : true
5694     });
5695  }
5696  Roo.extend(Employee, Roo.util.Observable);
5697 </code></pre>
5698  * @param {Object} config properties to use (incuding events / listeners)
5699  */
5700
5701 Roo.util.Observable = function(cfg){
5702     
5703     cfg = cfg|| {};
5704     this.addEvents(cfg.events || {});
5705     if (cfg.events) {
5706         delete cfg.events; // make sure
5707     }
5708      
5709     Roo.apply(this, cfg);
5710     
5711     if(this.listeners){
5712         this.on(this.listeners);
5713         delete this.listeners;
5714     }
5715 };
5716 Roo.util.Observable.prototype = {
5717     /** 
5718  * @cfg {Object} listeners  list of events and functions to call for this object, 
5719  * For example :
5720  * <pre><code>
5721     listeners :  { 
5722        'click' : function(e) {
5723            ..... 
5724         } ,
5725         .... 
5726     } 
5727   </code></pre>
5728  */
5729     
5730     
5731     /**
5732      * Fires the specified event with the passed parameters (minus the event name).
5733      * @param {String} eventName
5734      * @param {Object...} args Variable number of parameters are passed to handlers
5735      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5736      */
5737     fireEvent : function(){
5738         var ce = this.events[arguments[0].toLowerCase()];
5739         if(typeof ce == "object"){
5740             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5741         }else{
5742             return true;
5743         }
5744     },
5745
5746     // private
5747     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5748
5749     /**
5750      * Appends an event handler to this component
5751      * @param {String}   eventName The type of event to listen for
5752      * @param {Function} handler The method the event invokes
5753      * @param {Object}   scope (optional) The scope in which to execute the handler
5754      * function. The handler function's "this" context.
5755      * @param {Object}   options (optional) An object containing handler configuration
5756      * properties. This may contain any of the following properties:<ul>
5757      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5758      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5759      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5760      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5761      * by the specified number of milliseconds. If the event fires again within that time, the original
5762      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5763      * </ul><br>
5764      * <p>
5765      * <b>Combining Options</b><br>
5766      * Using the options argument, it is possible to combine different types of listeners:<br>
5767      * <br>
5768      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5769                 <pre><code>
5770                 el.on('click', this.onClick, this, {
5771                         single: true,
5772                 delay: 100,
5773                 forumId: 4
5774                 });
5775                 </code></pre>
5776      * <p>
5777      * <b>Attaching multiple handlers in 1 call</b><br>
5778      * The method also allows for a single argument to be passed which is a config object containing properties
5779      * which specify multiple handlers.
5780      * <pre><code>
5781                 el.on({
5782                         'click': {
5783                         fn: this.onClick,
5784                         scope: this,
5785                         delay: 100
5786                 }, 
5787                 'mouseover': {
5788                         fn: this.onMouseOver,
5789                         scope: this
5790                 },
5791                 'mouseout': {
5792                         fn: this.onMouseOut,
5793                         scope: this
5794                 }
5795                 });
5796                 </code></pre>
5797      * <p>
5798      * Or a shorthand syntax which passes the same scope object to all handlers:
5799         <pre><code>
5800                 el.on({
5801                         'click': this.onClick,
5802                 'mouseover': this.onMouseOver,
5803                 'mouseout': this.onMouseOut,
5804                 scope: this
5805                 });
5806                 </code></pre>
5807      */
5808     addListener : function(eventName, fn, scope, o){
5809         if(typeof eventName == "object"){
5810             o = eventName;
5811             for(var e in o){
5812                 if(this.filterOptRe.test(e)){
5813                     continue;
5814                 }
5815                 if(typeof o[e] == "function"){
5816                     // shared options
5817                     this.addListener(e, o[e], o.scope,  o);
5818                 }else{
5819                     // individual options
5820                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5821                 }
5822             }
5823             return;
5824         }
5825         o = (!o || typeof o == "boolean") ? {} : o;
5826         eventName = eventName.toLowerCase();
5827         var ce = this.events[eventName] || true;
5828         if(typeof ce == "boolean"){
5829             ce = new Roo.util.Event(this, eventName);
5830             this.events[eventName] = ce;
5831         }
5832         ce.addListener(fn, scope, o);
5833     },
5834
5835     /**
5836      * Removes a listener
5837      * @param {String}   eventName     The type of event to listen for
5838      * @param {Function} handler        The handler to remove
5839      * @param {Object}   scope  (optional) The scope (this object) for the handler
5840      */
5841     removeListener : function(eventName, fn, scope){
5842         var ce = this.events[eventName.toLowerCase()];
5843         if(typeof ce == "object"){
5844             ce.removeListener(fn, scope);
5845         }
5846     },
5847
5848     /**
5849      * Removes all listeners for this object
5850      */
5851     purgeListeners : function(){
5852         for(var evt in this.events){
5853             if(typeof this.events[evt] == "object"){
5854                  this.events[evt].clearListeners();
5855             }
5856         }
5857     },
5858
5859     relayEvents : function(o, events){
5860         var createHandler = function(ename){
5861             return function(){
5862                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5863             };
5864         };
5865         for(var i = 0, len = events.length; i < len; i++){
5866             var ename = events[i];
5867             if(!this.events[ename]){ this.events[ename] = true; };
5868             o.on(ename, createHandler(ename), this);
5869         }
5870     },
5871
5872     /**
5873      * Used to define events on this Observable
5874      * @param {Object} object The object with the events defined
5875      */
5876     addEvents : function(o){
5877         if(!this.events){
5878             this.events = {};
5879         }
5880         Roo.applyIf(this.events, o);
5881     },
5882
5883     /**
5884      * Checks to see if this object has any listeners for a specified event
5885      * @param {String} eventName The name of the event to check for
5886      * @return {Boolean} True if the event is being listened for, else false
5887      */
5888     hasListener : function(eventName){
5889         var e = this.events[eventName];
5890         return typeof e == "object" && e.listeners.length > 0;
5891     }
5892 };
5893 /**
5894  * Appends an event handler to this element (shorthand for addListener)
5895  * @param {String}   eventName     The type of event to listen for
5896  * @param {Function} handler        The method the event invokes
5897  * @param {Object}   scope (optional) The scope in which to execute the handler
5898  * function. The handler function's "this" context.
5899  * @param {Object}   options  (optional)
5900  * @method
5901  */
5902 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5903 /**
5904  * Removes a listener (shorthand for removeListener)
5905  * @param {String}   eventName     The type of event to listen for
5906  * @param {Function} handler        The handler to remove
5907  * @param {Object}   scope  (optional) The scope (this object) for the handler
5908  * @method
5909  */
5910 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5911
5912 /**
5913  * Starts capture on the specified Observable. All events will be passed
5914  * to the supplied function with the event name + standard signature of the event
5915  * <b>before</b> the event is fired. If the supplied function returns false,
5916  * the event will not fire.
5917  * @param {Observable} o The Observable to capture
5918  * @param {Function} fn The function to call
5919  * @param {Object} scope (optional) The scope (this object) for the fn
5920  * @static
5921  */
5922 Roo.util.Observable.capture = function(o, fn, scope){
5923     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5924 };
5925
5926 /**
5927  * Removes <b>all</b> added captures from the Observable.
5928  * @param {Observable} o The Observable to release
5929  * @static
5930  */
5931 Roo.util.Observable.releaseCapture = function(o){
5932     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5933 };
5934
5935 (function(){
5936
5937     var createBuffered = function(h, o, scope){
5938         var task = new Roo.util.DelayedTask();
5939         return function(){
5940             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5941         };
5942     };
5943
5944     var createSingle = function(h, e, fn, scope){
5945         return function(){
5946             e.removeListener(fn, scope);
5947             return h.apply(scope, arguments);
5948         };
5949     };
5950
5951     var createDelayed = function(h, o, scope){
5952         return function(){
5953             var args = Array.prototype.slice.call(arguments, 0);
5954             setTimeout(function(){
5955                 h.apply(scope, args);
5956             }, o.delay || 10);
5957         };
5958     };
5959
5960     Roo.util.Event = function(obj, name){
5961         this.name = name;
5962         this.obj = obj;
5963         this.listeners = [];
5964     };
5965
5966     Roo.util.Event.prototype = {
5967         addListener : function(fn, scope, options){
5968             var o = options || {};
5969             scope = scope || this.obj;
5970             if(!this.isListening(fn, scope)){
5971                 var l = {fn: fn, scope: scope, options: o};
5972                 var h = fn;
5973                 if(o.delay){
5974                     h = createDelayed(h, o, scope);
5975                 }
5976                 if(o.single){
5977                     h = createSingle(h, this, fn, scope);
5978                 }
5979                 if(o.buffer){
5980                     h = createBuffered(h, o, scope);
5981                 }
5982                 l.fireFn = h;
5983                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5984                     this.listeners.push(l);
5985                 }else{
5986                     this.listeners = this.listeners.slice(0);
5987                     this.listeners.push(l);
5988                 }
5989             }
5990         },
5991
5992         findListener : function(fn, scope){
5993             scope = scope || this.obj;
5994             var ls = this.listeners;
5995             for(var i = 0, len = ls.length; i < len; i++){
5996                 var l = ls[i];
5997                 if(l.fn == fn && l.scope == scope){
5998                     return i;
5999                 }
6000             }
6001             return -1;
6002         },
6003
6004         isListening : function(fn, scope){
6005             return this.findListener(fn, scope) != -1;
6006         },
6007
6008         removeListener : function(fn, scope){
6009             var index;
6010             if((index = this.findListener(fn, scope)) != -1){
6011                 if(!this.firing){
6012                     this.listeners.splice(index, 1);
6013                 }else{
6014                     this.listeners = this.listeners.slice(0);
6015                     this.listeners.splice(index, 1);
6016                 }
6017                 return true;
6018             }
6019             return false;
6020         },
6021
6022         clearListeners : function(){
6023             this.listeners = [];
6024         },
6025
6026         fire : function(){
6027             var ls = this.listeners, scope, len = ls.length;
6028             if(len > 0){
6029                 this.firing = true;
6030                 var args = Array.prototype.slice.call(arguments, 0);
6031                 for(var i = 0; i < len; i++){
6032                     var l = ls[i];
6033                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6034                         this.firing = false;
6035                         return false;
6036                     }
6037                 }
6038                 this.firing = false;
6039             }
6040             return true;
6041         }
6042     };
6043 })();/*
6044  * Based on:
6045  * Ext JS Library 1.1.1
6046  * Copyright(c) 2006-2007, Ext JS, LLC.
6047  *
6048  * Originally Released Under LGPL - original licence link has changed is not relivant.
6049  *
6050  * Fork - LGPL
6051  * <script type="text/javascript">
6052  */
6053
6054 /**
6055  * @class Roo.EventManager
6056  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6057  * several useful events directly.
6058  * See {@link Roo.EventObject} for more details on normalized event objects.
6059  * @singleton
6060  */
6061 Roo.EventManager = function(){
6062     var docReadyEvent, docReadyProcId, docReadyState = false;
6063     var resizeEvent, resizeTask, textEvent, textSize;
6064     var E = Roo.lib.Event;
6065     var D = Roo.lib.Dom;
6066
6067     
6068     
6069
6070     var fireDocReady = function(){
6071         if(!docReadyState){
6072             docReadyState = true;
6073             Roo.isReady = true;
6074             if(docReadyProcId){
6075                 clearInterval(docReadyProcId);
6076             }
6077             if(Roo.isGecko || Roo.isOpera) {
6078                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6079             }
6080             if(Roo.isIE){
6081                 var defer = document.getElementById("ie-deferred-loader");
6082                 if(defer){
6083                     defer.onreadystatechange = null;
6084                     defer.parentNode.removeChild(defer);
6085                 }
6086             }
6087             if(docReadyEvent){
6088                 docReadyEvent.fire();
6089                 docReadyEvent.clearListeners();
6090             }
6091         }
6092     };
6093     
6094     var initDocReady = function(){
6095         docReadyEvent = new Roo.util.Event();
6096         if(Roo.isGecko || Roo.isOpera) {
6097             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6098         }else if(Roo.isIE){
6099             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6100             var defer = document.getElementById("ie-deferred-loader");
6101             defer.onreadystatechange = function(){
6102                 if(this.readyState == "complete"){
6103                     fireDocReady();
6104                 }
6105             };
6106         }else if(Roo.isSafari){ 
6107             docReadyProcId = setInterval(function(){
6108                 var rs = document.readyState;
6109                 if(rs == "complete") {
6110                     fireDocReady();     
6111                  }
6112             }, 10);
6113         }
6114         // no matter what, make sure it fires on load
6115         E.on(window, "load", fireDocReady);
6116     };
6117
6118     var createBuffered = function(h, o){
6119         var task = new Roo.util.DelayedTask(h);
6120         return function(e){
6121             // create new event object impl so new events don't wipe out properties
6122             e = new Roo.EventObjectImpl(e);
6123             task.delay(o.buffer, h, null, [e]);
6124         };
6125     };
6126
6127     var createSingle = function(h, el, ename, fn){
6128         return function(e){
6129             Roo.EventManager.removeListener(el, ename, fn);
6130             h(e);
6131         };
6132     };
6133
6134     var createDelayed = function(h, o){
6135         return function(e){
6136             // create new event object impl so new events don't wipe out properties
6137             e = new Roo.EventObjectImpl(e);
6138             setTimeout(function(){
6139                 h(e);
6140             }, o.delay || 10);
6141         };
6142     };
6143     var transitionEndVal = false;
6144     
6145     var transitionEnd = function()
6146     {
6147         if (transitionEndVal) {
6148             return transitionEndVal;
6149         }
6150         var el = document.createElement('div');
6151
6152         var transEndEventNames = {
6153             WebkitTransition : 'webkitTransitionEnd',
6154             MozTransition    : 'transitionend',
6155             OTransition      : 'oTransitionEnd otransitionend',
6156             transition       : 'transitionend'
6157         };
6158     
6159         for (var name in transEndEventNames) {
6160             if (el.style[name] !== undefined) {
6161                 transitionEndVal = transEndEventNames[name];
6162                 return  transitionEndVal ;
6163             }
6164         }
6165     }
6166     
6167
6168     var listen = function(element, ename, opt, fn, scope){
6169         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6170         fn = fn || o.fn; scope = scope || o.scope;
6171         var el = Roo.getDom(element);
6172         
6173         
6174         if(!el){
6175             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6176         }
6177         
6178         if (ename == 'transitionend') {
6179             ename = transitionEnd();
6180         }
6181         var h = function(e){
6182             e = Roo.EventObject.setEvent(e);
6183             var t;
6184             if(o.delegate){
6185                 t = e.getTarget(o.delegate, el);
6186                 if(!t){
6187                     return;
6188                 }
6189             }else{
6190                 t = e.target;
6191             }
6192             if(o.stopEvent === true){
6193                 e.stopEvent();
6194             }
6195             if(o.preventDefault === true){
6196                e.preventDefault();
6197             }
6198             if(o.stopPropagation === true){
6199                 e.stopPropagation();
6200             }
6201
6202             if(o.normalized === false){
6203                 e = e.browserEvent;
6204             }
6205
6206             fn.call(scope || el, e, t, o);
6207         };
6208         if(o.delay){
6209             h = createDelayed(h, o);
6210         }
6211         if(o.single){
6212             h = createSingle(h, el, ename, fn);
6213         }
6214         if(o.buffer){
6215             h = createBuffered(h, o);
6216         }
6217         fn._handlers = fn._handlers || [];
6218         
6219         
6220         fn._handlers.push([Roo.id(el), ename, h]);
6221         
6222         
6223          
6224         E.on(el, ename, h);
6225         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6226             el.addEventListener("DOMMouseScroll", h, false);
6227             E.on(window, 'unload', function(){
6228                 el.removeEventListener("DOMMouseScroll", h, false);
6229             });
6230         }
6231         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6232             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6233         }
6234         return h;
6235     };
6236
6237     var stopListening = function(el, ename, fn){
6238         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6239         if(hds){
6240             for(var i = 0, len = hds.length; i < len; i++){
6241                 var h = hds[i];
6242                 if(h[0] == id && h[1] == ename){
6243                     hd = h[2];
6244                     hds.splice(i, 1);
6245                     break;
6246                 }
6247             }
6248         }
6249         E.un(el, ename, hd);
6250         el = Roo.getDom(el);
6251         if(ename == "mousewheel" && el.addEventListener){
6252             el.removeEventListener("DOMMouseScroll", hd, false);
6253         }
6254         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6255             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6256         }
6257     };
6258
6259     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6260     
6261     var pub = {
6262         
6263         
6264         /** 
6265          * Fix for doc tools
6266          * @scope Roo.EventManager
6267          */
6268         
6269         
6270         /** 
6271          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6272          * object with a Roo.EventObject
6273          * @param {Function} fn        The method the event invokes
6274          * @param {Object}   scope    An object that becomes the scope of the handler
6275          * @param {boolean}  override If true, the obj passed in becomes
6276          *                             the execution scope of the listener
6277          * @return {Function} The wrapped function
6278          * @deprecated
6279          */
6280         wrap : function(fn, scope, override){
6281             return function(e){
6282                 Roo.EventObject.setEvent(e);
6283                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6284             };
6285         },
6286         
6287         /**
6288      * Appends an event handler to an element (shorthand for addListener)
6289      * @param {String/HTMLElement}   element        The html element or id to assign the
6290      * @param {String}   eventName The type of event to listen for
6291      * @param {Function} handler The method the event invokes
6292      * @param {Object}   scope (optional) The scope in which to execute the handler
6293      * function. The handler function's "this" context.
6294      * @param {Object}   options (optional) An object containing handler configuration
6295      * properties. This may contain any of the following properties:<ul>
6296      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6297      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6298      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6299      * <li>preventDefault {Boolean} True to prevent the default action</li>
6300      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6301      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6302      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6303      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6304      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6305      * by the specified number of milliseconds. If the event fires again within that time, the original
6306      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6307      * </ul><br>
6308      * <p>
6309      * <b>Combining Options</b><br>
6310      * Using the options argument, it is possible to combine different types of listeners:<br>
6311      * <br>
6312      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6313      * Code:<pre><code>
6314 el.on('click', this.onClick, this, {
6315     single: true,
6316     delay: 100,
6317     stopEvent : true,
6318     forumId: 4
6319 });</code></pre>
6320      * <p>
6321      * <b>Attaching multiple handlers in 1 call</b><br>
6322       * The method also allows for a single argument to be passed which is a config object containing properties
6323      * which specify multiple handlers.
6324      * <p>
6325      * Code:<pre><code>
6326 el.on({
6327     'click' : {
6328         fn: this.onClick
6329         scope: this,
6330         delay: 100
6331     },
6332     'mouseover' : {
6333         fn: this.onMouseOver
6334         scope: this
6335     },
6336     'mouseout' : {
6337         fn: this.onMouseOut
6338         scope: this
6339     }
6340 });</code></pre>
6341      * <p>
6342      * Or a shorthand syntax:<br>
6343      * Code:<pre><code>
6344 el.on({
6345     'click' : this.onClick,
6346     'mouseover' : this.onMouseOver,
6347     'mouseout' : this.onMouseOut
6348     scope: this
6349 });</code></pre>
6350      */
6351         addListener : function(element, eventName, fn, scope, options){
6352             if(typeof eventName == "object"){
6353                 var o = eventName;
6354                 for(var e in o){
6355                     if(propRe.test(e)){
6356                         continue;
6357                     }
6358                     if(typeof o[e] == "function"){
6359                         // shared options
6360                         listen(element, e, o, o[e], o.scope);
6361                     }else{
6362                         // individual options
6363                         listen(element, e, o[e]);
6364                     }
6365                 }
6366                 return;
6367             }
6368             return listen(element, eventName, options, fn, scope);
6369         },
6370         
6371         /**
6372          * Removes an event handler
6373          *
6374          * @param {String/HTMLElement}   element        The id or html element to remove the 
6375          *                             event from
6376          * @param {String}   eventName     The type of event
6377          * @param {Function} fn
6378          * @return {Boolean} True if a listener was actually removed
6379          */
6380         removeListener : function(element, eventName, fn){
6381             return stopListening(element, eventName, fn);
6382         },
6383         
6384         /**
6385          * Fires when the document is ready (before onload and before images are loaded). Can be 
6386          * accessed shorthanded Roo.onReady().
6387          * @param {Function} fn        The method the event invokes
6388          * @param {Object}   scope    An  object that becomes the scope of the handler
6389          * @param {boolean}  options
6390          */
6391         onDocumentReady : function(fn, scope, options){
6392             if(docReadyState){ // if it already fired
6393                 docReadyEvent.addListener(fn, scope, options);
6394                 docReadyEvent.fire();
6395                 docReadyEvent.clearListeners();
6396                 return;
6397             }
6398             if(!docReadyEvent){
6399                 initDocReady();
6400             }
6401             docReadyEvent.addListener(fn, scope, options);
6402         },
6403         
6404         /**
6405          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
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         onWindowResize : function(fn, scope, options){
6411             if(!resizeEvent){
6412                 resizeEvent = new Roo.util.Event();
6413                 resizeTask = new Roo.util.DelayedTask(function(){
6414                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6415                 });
6416                 E.on(window, "resize", function(){
6417                     if(Roo.isIE){
6418                         resizeTask.delay(50);
6419                     }else{
6420                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6421                     }
6422                 });
6423             }
6424             resizeEvent.addListener(fn, scope, options);
6425         },
6426
6427         /**
6428          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6429          * @param {Function} fn        The method the event invokes
6430          * @param {Object}   scope    An object that becomes the scope of the handler
6431          * @param {boolean}  options
6432          */
6433         onTextResize : function(fn, scope, options){
6434             if(!textEvent){
6435                 textEvent = new Roo.util.Event();
6436                 var textEl = new Roo.Element(document.createElement('div'));
6437                 textEl.dom.className = 'x-text-resize';
6438                 textEl.dom.innerHTML = 'X';
6439                 textEl.appendTo(document.body);
6440                 textSize = textEl.dom.offsetHeight;
6441                 setInterval(function(){
6442                     if(textEl.dom.offsetHeight != textSize){
6443                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6444                     }
6445                 }, this.textResizeInterval);
6446             }
6447             textEvent.addListener(fn, scope, options);
6448         },
6449
6450         /**
6451          * Removes the passed window resize listener.
6452          * @param {Function} fn        The method the event invokes
6453          * @param {Object}   scope    The scope of handler
6454          */
6455         removeResizeListener : function(fn, scope){
6456             if(resizeEvent){
6457                 resizeEvent.removeListener(fn, scope);
6458             }
6459         },
6460
6461         // private
6462         fireResize : function(){
6463             if(resizeEvent){
6464                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6465             }   
6466         },
6467         /**
6468          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6469          */
6470         ieDeferSrc : false,
6471         /**
6472          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6473          */
6474         textResizeInterval : 50
6475     };
6476     
6477     /**
6478      * Fix for doc tools
6479      * @scopeAlias pub=Roo.EventManager
6480      */
6481     
6482      /**
6483      * Appends an event handler to an element (shorthand for addListener)
6484      * @param {String/HTMLElement}   element        The html element or id to assign the
6485      * @param {String}   eventName The type of event to listen for
6486      * @param {Function} handler The method the event invokes
6487      * @param {Object}   scope (optional) The scope in which to execute the handler
6488      * function. The handler function's "this" context.
6489      * @param {Object}   options (optional) An object containing handler configuration
6490      * properties. This may contain any of the following properties:<ul>
6491      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6492      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6493      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6494      * <li>preventDefault {Boolean} True to prevent the default action</li>
6495      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6496      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6497      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6498      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6499      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6500      * by the specified number of milliseconds. If the event fires again within that time, the original
6501      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6502      * </ul><br>
6503      * <p>
6504      * <b>Combining Options</b><br>
6505      * Using the options argument, it is possible to combine different types of listeners:<br>
6506      * <br>
6507      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6508      * Code:<pre><code>
6509 el.on('click', this.onClick, this, {
6510     single: true,
6511     delay: 100,
6512     stopEvent : true,
6513     forumId: 4
6514 });</code></pre>
6515      * <p>
6516      * <b>Attaching multiple handlers in 1 call</b><br>
6517       * The method also allows for a single argument to be passed which is a config object containing properties
6518      * which specify multiple handlers.
6519      * <p>
6520      * Code:<pre><code>
6521 el.on({
6522     'click' : {
6523         fn: this.onClick
6524         scope: this,
6525         delay: 100
6526     },
6527     'mouseover' : {
6528         fn: this.onMouseOver
6529         scope: this
6530     },
6531     'mouseout' : {
6532         fn: this.onMouseOut
6533         scope: this
6534     }
6535 });</code></pre>
6536      * <p>
6537      * Or a shorthand syntax:<br>
6538      * Code:<pre><code>
6539 el.on({
6540     'click' : this.onClick,
6541     'mouseover' : this.onMouseOver,
6542     'mouseout' : this.onMouseOut
6543     scope: this
6544 });</code></pre>
6545      */
6546     pub.on = pub.addListener;
6547     pub.un = pub.removeListener;
6548
6549     pub.stoppedMouseDownEvent = new Roo.util.Event();
6550     return pub;
6551 }();
6552 /**
6553   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6554   * @param {Function} fn        The method the event invokes
6555   * @param {Object}   scope    An  object that becomes the scope of the handler
6556   * @param {boolean}  override If true, the obj passed in becomes
6557   *                             the execution scope of the listener
6558   * @member Roo
6559   * @method onReady
6560  */
6561 Roo.onReady = Roo.EventManager.onDocumentReady;
6562
6563 Roo.onReady(function(){
6564     var bd = Roo.get(document.body);
6565     if(!bd){ return; }
6566
6567     var cls = [
6568             Roo.isIE ? "roo-ie"
6569             : Roo.isGecko ? "roo-gecko"
6570             : Roo.isOpera ? "roo-opera"
6571             : Roo.isSafari ? "roo-safari" : ""];
6572
6573     if(Roo.isMac){
6574         cls.push("roo-mac");
6575     }
6576     if(Roo.isLinux){
6577         cls.push("roo-linux");
6578     }
6579     if(Roo.isBorderBox){
6580         cls.push('roo-border-box');
6581     }
6582     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6583         var p = bd.dom.parentNode;
6584         if(p){
6585             p.className += ' roo-strict';
6586         }
6587     }
6588     bd.addClass(cls.join(' '));
6589 });
6590
6591 /**
6592  * @class Roo.EventObject
6593  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6594  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6595  * Example:
6596  * <pre><code>
6597  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6598     e.preventDefault();
6599     var target = e.getTarget();
6600     ...
6601  }
6602  var myDiv = Roo.get("myDiv");
6603  myDiv.on("click", handleClick);
6604  //or
6605  Roo.EventManager.on("myDiv", 'click', handleClick);
6606  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6607  </code></pre>
6608  * @singleton
6609  */
6610 Roo.EventObject = function(){
6611     
6612     var E = Roo.lib.Event;
6613     
6614     // safari keypress events for special keys return bad keycodes
6615     var safariKeys = {
6616         63234 : 37, // left
6617         63235 : 39, // right
6618         63232 : 38, // up
6619         63233 : 40, // down
6620         63276 : 33, // page up
6621         63277 : 34, // page down
6622         63272 : 46, // delete
6623         63273 : 36, // home
6624         63275 : 35  // end
6625     };
6626
6627     // normalize button clicks
6628     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6629                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6630
6631     Roo.EventObjectImpl = function(e){
6632         if(e){
6633             this.setEvent(e.browserEvent || e);
6634         }
6635     };
6636     Roo.EventObjectImpl.prototype = {
6637         /**
6638          * Used to fix doc tools.
6639          * @scope Roo.EventObject.prototype
6640          */
6641             
6642
6643         
6644         
6645         /** The normal browser event */
6646         browserEvent : null,
6647         /** The button pressed in a mouse event */
6648         button : -1,
6649         /** True if the shift key was down during the event */
6650         shiftKey : false,
6651         /** True if the control key was down during the event */
6652         ctrlKey : false,
6653         /** True if the alt key was down during the event */
6654         altKey : false,
6655
6656         /** Key constant 
6657         * @type Number */
6658         BACKSPACE : 8,
6659         /** Key constant 
6660         * @type Number */
6661         TAB : 9,
6662         /** Key constant 
6663         * @type Number */
6664         RETURN : 13,
6665         /** Key constant 
6666         * @type Number */
6667         ENTER : 13,
6668         /** Key constant 
6669         * @type Number */
6670         SHIFT : 16,
6671         /** Key constant 
6672         * @type Number */
6673         CONTROL : 17,
6674         /** Key constant 
6675         * @type Number */
6676         ESC : 27,
6677         /** Key constant 
6678         * @type Number */
6679         SPACE : 32,
6680         /** Key constant 
6681         * @type Number */
6682         PAGEUP : 33,
6683         /** Key constant 
6684         * @type Number */
6685         PAGEDOWN : 34,
6686         /** Key constant 
6687         * @type Number */
6688         END : 35,
6689         /** Key constant 
6690         * @type Number */
6691         HOME : 36,
6692         /** Key constant 
6693         * @type Number */
6694         LEFT : 37,
6695         /** Key constant 
6696         * @type Number */
6697         UP : 38,
6698         /** Key constant 
6699         * @type Number */
6700         RIGHT : 39,
6701         /** Key constant 
6702         * @type Number */
6703         DOWN : 40,
6704         /** Key constant 
6705         * @type Number */
6706         DELETE : 46,
6707         /** Key constant 
6708         * @type Number */
6709         F5 : 116,
6710
6711            /** @private */
6712         setEvent : function(e){
6713             if(e == this || (e && e.browserEvent)){ // already wrapped
6714                 return e;
6715             }
6716             this.browserEvent = e;
6717             if(e){
6718                 // normalize buttons
6719                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6720                 if(e.type == 'click' && this.button == -1){
6721                     this.button = 0;
6722                 }
6723                 this.type = e.type;
6724                 this.shiftKey = e.shiftKey;
6725                 // mac metaKey behaves like ctrlKey
6726                 this.ctrlKey = e.ctrlKey || e.metaKey;
6727                 this.altKey = e.altKey;
6728                 // in getKey these will be normalized for the mac
6729                 this.keyCode = e.keyCode;
6730                 // keyup warnings on firefox.
6731                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6732                 // cache the target for the delayed and or buffered events
6733                 this.target = E.getTarget(e);
6734                 // same for XY
6735                 this.xy = E.getXY(e);
6736             }else{
6737                 this.button = -1;
6738                 this.shiftKey = false;
6739                 this.ctrlKey = false;
6740                 this.altKey = false;
6741                 this.keyCode = 0;
6742                 this.charCode =0;
6743                 this.target = null;
6744                 this.xy = [0, 0];
6745             }
6746             return this;
6747         },
6748
6749         /**
6750          * Stop the event (preventDefault and stopPropagation)
6751          */
6752         stopEvent : function(){
6753             if(this.browserEvent){
6754                 if(this.browserEvent.type == 'mousedown'){
6755                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6756                 }
6757                 E.stopEvent(this.browserEvent);
6758             }
6759         },
6760
6761         /**
6762          * Prevents the browsers default handling of the event.
6763          */
6764         preventDefault : function(){
6765             if(this.browserEvent){
6766                 E.preventDefault(this.browserEvent);
6767             }
6768         },
6769
6770         /** @private */
6771         isNavKeyPress : function(){
6772             var k = this.keyCode;
6773             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6774             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6775         },
6776
6777         isSpecialKey : function(){
6778             var k = this.keyCode;
6779             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6780             (k == 16) || (k == 17) ||
6781             (k >= 18 && k <= 20) ||
6782             (k >= 33 && k <= 35) ||
6783             (k >= 36 && k <= 39) ||
6784             (k >= 44 && k <= 45);
6785         },
6786         /**
6787          * Cancels bubbling of the event.
6788          */
6789         stopPropagation : function(){
6790             if(this.browserEvent){
6791                 if(this.type == 'mousedown'){
6792                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6793                 }
6794                 E.stopPropagation(this.browserEvent);
6795             }
6796         },
6797
6798         /**
6799          * Gets the key code for the event.
6800          * @return {Number}
6801          */
6802         getCharCode : function(){
6803             return this.charCode || this.keyCode;
6804         },
6805
6806         /**
6807          * Returns a normalized keyCode for the event.
6808          * @return {Number} The key code
6809          */
6810         getKey : function(){
6811             var k = this.keyCode || this.charCode;
6812             return Roo.isSafari ? (safariKeys[k] || k) : k;
6813         },
6814
6815         /**
6816          * Gets the x coordinate of the event.
6817          * @return {Number}
6818          */
6819         getPageX : function(){
6820             return this.xy[0];
6821         },
6822
6823         /**
6824          * Gets the y coordinate of the event.
6825          * @return {Number}
6826          */
6827         getPageY : function(){
6828             return this.xy[1];
6829         },
6830
6831         /**
6832          * Gets the time of the event.
6833          * @return {Number}
6834          */
6835         getTime : function(){
6836             if(this.browserEvent){
6837                 return E.getTime(this.browserEvent);
6838             }
6839             return null;
6840         },
6841
6842         /**
6843          * Gets the page coordinates of the event.
6844          * @return {Array} The xy values like [x, y]
6845          */
6846         getXY : function(){
6847             return this.xy;
6848         },
6849
6850         /**
6851          * Gets the target for the event.
6852          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6853          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6854                 search as a number or element (defaults to 10 || document.body)
6855          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6856          * @return {HTMLelement}
6857          */
6858         getTarget : function(selector, maxDepth, returnEl){
6859             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6860         },
6861         /**
6862          * Gets the related target.
6863          * @return {HTMLElement}
6864          */
6865         getRelatedTarget : function(){
6866             if(this.browserEvent){
6867                 return E.getRelatedTarget(this.browserEvent);
6868             }
6869             return null;
6870         },
6871
6872         /**
6873          * Normalizes mouse wheel delta across browsers
6874          * @return {Number} The delta
6875          */
6876         getWheelDelta : function(){
6877             var e = this.browserEvent;
6878             var delta = 0;
6879             if(e.wheelDelta){ /* IE/Opera. */
6880                 delta = e.wheelDelta/120;
6881             }else if(e.detail){ /* Mozilla case. */
6882                 delta = -e.detail/3;
6883             }
6884             return delta;
6885         },
6886
6887         /**
6888          * Returns true if the control, meta, shift or alt key was pressed during this event.
6889          * @return {Boolean}
6890          */
6891         hasModifier : function(){
6892             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6893         },
6894
6895         /**
6896          * Returns true if the target of this event equals el or is a child of el
6897          * @param {String/HTMLElement/Element} el
6898          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6899          * @return {Boolean}
6900          */
6901         within : function(el, related){
6902             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6903             return t && Roo.fly(el).contains(t);
6904         },
6905
6906         getPoint : function(){
6907             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6908         }
6909     };
6910
6911     return new Roo.EventObjectImpl();
6912 }();
6913             
6914     /*
6915  * Based on:
6916  * Ext JS Library 1.1.1
6917  * Copyright(c) 2006-2007, Ext JS, LLC.
6918  *
6919  * Originally Released Under LGPL - original licence link has changed is not relivant.
6920  *
6921  * Fork - LGPL
6922  * <script type="text/javascript">
6923  */
6924
6925  
6926 // was in Composite Element!??!?!
6927  
6928 (function(){
6929     var D = Roo.lib.Dom;
6930     var E = Roo.lib.Event;
6931     var A = Roo.lib.Anim;
6932
6933     // local style camelizing for speed
6934     var propCache = {};
6935     var camelRe = /(-[a-z])/gi;
6936     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6937     var view = document.defaultView;
6938
6939 /**
6940  * @class Roo.Element
6941  * Represents an Element in the DOM.<br><br>
6942  * Usage:<br>
6943 <pre><code>
6944 var el = Roo.get("my-div");
6945
6946 // or with getEl
6947 var el = getEl("my-div");
6948
6949 // or with a DOM element
6950 var el = Roo.get(myDivElement);
6951 </code></pre>
6952  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6953  * each call instead of constructing a new one.<br><br>
6954  * <b>Animations</b><br />
6955  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6956  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6957 <pre>
6958 Option    Default   Description
6959 --------- --------  ---------------------------------------------
6960 duration  .35       The duration of the animation in seconds
6961 easing    easeOut   The YUI easing method
6962 callback  none      A function to execute when the anim completes
6963 scope     this      The scope (this) of the callback function
6964 </pre>
6965 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6966 * manipulate the animation. Here's an example:
6967 <pre><code>
6968 var el = Roo.get("my-div");
6969
6970 // no animation
6971 el.setWidth(100);
6972
6973 // default animation
6974 el.setWidth(100, true);
6975
6976 // animation with some options set
6977 el.setWidth(100, {
6978     duration: 1,
6979     callback: this.foo,
6980     scope: this
6981 });
6982
6983 // using the "anim" property to get the Anim object
6984 var opt = {
6985     duration: 1,
6986     callback: this.foo,
6987     scope: this
6988 };
6989 el.setWidth(100, opt);
6990 ...
6991 if(opt.anim.isAnimated()){
6992     opt.anim.stop();
6993 }
6994 </code></pre>
6995 * <b> Composite (Collections of) Elements</b><br />
6996  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6997  * @constructor Create a new Element directly.
6998  * @param {String/HTMLElement} element
6999  * @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).
7000  */
7001     Roo.Element = function(element, forceNew){
7002         var dom = typeof element == "string" ?
7003                 document.getElementById(element) : element;
7004         if(!dom){ // invalid id/element
7005             return null;
7006         }
7007         var id = dom.id;
7008         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7009             return Roo.Element.cache[id];
7010         }
7011
7012         /**
7013          * The DOM element
7014          * @type HTMLElement
7015          */
7016         this.dom = dom;
7017
7018         /**
7019          * The DOM element ID
7020          * @type String
7021          */
7022         this.id = id || Roo.id(dom);
7023     };
7024
7025     var El = Roo.Element;
7026
7027     El.prototype = {
7028         /**
7029          * The element's default display mode  (defaults to "")
7030          * @type String
7031          */
7032         originalDisplay : "",
7033
7034         visibilityMode : 1,
7035         /**
7036          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7037          * @type String
7038          */
7039         defaultUnit : "px",
7040         /**
7041          * Sets the element's visibility mode. When setVisible() is called it
7042          * will use this to determine whether to set the visibility or the display property.
7043          * @param visMode Element.VISIBILITY or Element.DISPLAY
7044          * @return {Roo.Element} this
7045          */
7046         setVisibilityMode : function(visMode){
7047             this.visibilityMode = visMode;
7048             return this;
7049         },
7050         /**
7051          * Convenience method for setVisibilityMode(Element.DISPLAY)
7052          * @param {String} display (optional) What to set display to when visible
7053          * @return {Roo.Element} this
7054          */
7055         enableDisplayMode : function(display){
7056             this.setVisibilityMode(El.DISPLAY);
7057             if(typeof display != "undefined") this.originalDisplay = display;
7058             return this;
7059         },
7060
7061         /**
7062          * 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)
7063          * @param {String} selector The simple selector to test
7064          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7065                 search as a number or element (defaults to 10 || document.body)
7066          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7067          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7068          */
7069         findParent : function(simpleSelector, maxDepth, returnEl){
7070             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7071             maxDepth = maxDepth || 50;
7072             if(typeof maxDepth != "number"){
7073                 stopEl = Roo.getDom(maxDepth);
7074                 maxDepth = 10;
7075             }
7076             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7077                 if(dq.is(p, simpleSelector)){
7078                     return returnEl ? Roo.get(p) : p;
7079                 }
7080                 depth++;
7081                 p = p.parentNode;
7082             }
7083             return null;
7084         },
7085
7086
7087         /**
7088          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7089          * @param {String} selector The simple selector to test
7090          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7091                 search as a number or element (defaults to 10 || document.body)
7092          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7093          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7094          */
7095         findParentNode : function(simpleSelector, maxDepth, returnEl){
7096             var p = Roo.fly(this.dom.parentNode, '_internal');
7097             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7098         },
7099
7100         /**
7101          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7102          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7103          * @param {String} selector The simple selector to test
7104          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7105                 search as a number or element (defaults to 10 || document.body)
7106          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7107          */
7108         up : function(simpleSelector, maxDepth){
7109             return this.findParentNode(simpleSelector, maxDepth, true);
7110         },
7111
7112
7113
7114         /**
7115          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7116          * @param {String} selector The simple selector to test
7117          * @return {Boolean} True if this element matches the selector, else false
7118          */
7119         is : function(simpleSelector){
7120             return Roo.DomQuery.is(this.dom, simpleSelector);
7121         },
7122
7123         /**
7124          * Perform animation on this element.
7125          * @param {Object} args The YUI animation control args
7126          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7127          * @param {Function} onComplete (optional) Function to call when animation completes
7128          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7129          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7130          * @return {Roo.Element} this
7131          */
7132         animate : function(args, duration, onComplete, easing, animType){
7133             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7134             return this;
7135         },
7136
7137         /*
7138          * @private Internal animation call
7139          */
7140         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7141             animType = animType || 'run';
7142             opt = opt || {};
7143             var anim = Roo.lib.Anim[animType](
7144                 this.dom, args,
7145                 (opt.duration || defaultDur) || .35,
7146                 (opt.easing || defaultEase) || 'easeOut',
7147                 function(){
7148                     Roo.callback(cb, this);
7149                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7150                 },
7151                 this
7152             );
7153             opt.anim = anim;
7154             return anim;
7155         },
7156
7157         // private legacy anim prep
7158         preanim : function(a, i){
7159             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7160         },
7161
7162         /**
7163          * Removes worthless text nodes
7164          * @param {Boolean} forceReclean (optional) By default the element
7165          * keeps track if it has been cleaned already so
7166          * you can call this over and over. However, if you update the element and
7167          * need to force a reclean, you can pass true.
7168          */
7169         clean : function(forceReclean){
7170             if(this.isCleaned && forceReclean !== true){
7171                 return this;
7172             }
7173             var ns = /\S/;
7174             var d = this.dom, n = d.firstChild, ni = -1;
7175             while(n){
7176                 var nx = n.nextSibling;
7177                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7178                     d.removeChild(n);
7179                 }else{
7180                     n.nodeIndex = ++ni;
7181                 }
7182                 n = nx;
7183             }
7184             this.isCleaned = true;
7185             return this;
7186         },
7187
7188         // private
7189         calcOffsetsTo : function(el){
7190             el = Roo.get(el);
7191             var d = el.dom;
7192             var restorePos = false;
7193             if(el.getStyle('position') == 'static'){
7194                 el.position('relative');
7195                 restorePos = true;
7196             }
7197             var x = 0, y =0;
7198             var op = this.dom;
7199             while(op && op != d && op.tagName != 'HTML'){
7200                 x+= op.offsetLeft;
7201                 y+= op.offsetTop;
7202                 op = op.offsetParent;
7203             }
7204             if(restorePos){
7205                 el.position('static');
7206             }
7207             return [x, y];
7208         },
7209
7210         /**
7211          * Scrolls this element into view within the passed container.
7212          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7213          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7214          * @return {Roo.Element} this
7215          */
7216         scrollIntoView : function(container, hscroll){
7217             var c = Roo.getDom(container) || document.body;
7218             var el = this.dom;
7219
7220             var o = this.calcOffsetsTo(c),
7221                 l = o[0],
7222                 t = o[1],
7223                 b = t+el.offsetHeight,
7224                 r = l+el.offsetWidth;
7225
7226             var ch = c.clientHeight;
7227             var ct = parseInt(c.scrollTop, 10);
7228             var cl = parseInt(c.scrollLeft, 10);
7229             var cb = ct + ch;
7230             var cr = cl + c.clientWidth;
7231
7232             if(t < ct){
7233                 c.scrollTop = t;
7234             }else if(b > cb){
7235                 c.scrollTop = b-ch;
7236             }
7237
7238             if(hscroll !== false){
7239                 if(l < cl){
7240                     c.scrollLeft = l;
7241                 }else if(r > cr){
7242                     c.scrollLeft = r-c.clientWidth;
7243                 }
7244             }
7245             return this;
7246         },
7247
7248         // private
7249         scrollChildIntoView : function(child, hscroll){
7250             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7251         },
7252
7253         /**
7254          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7255          * the new height may not be available immediately.
7256          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7257          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7258          * @param {Function} onComplete (optional) Function to call when animation completes
7259          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7260          * @return {Roo.Element} this
7261          */
7262         autoHeight : function(animate, duration, onComplete, easing){
7263             var oldHeight = this.getHeight();
7264             this.clip();
7265             this.setHeight(1); // force clipping
7266             setTimeout(function(){
7267                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7268                 if(!animate){
7269                     this.setHeight(height);
7270                     this.unclip();
7271                     if(typeof onComplete == "function"){
7272                         onComplete();
7273                     }
7274                 }else{
7275                     this.setHeight(oldHeight); // restore original height
7276                     this.setHeight(height, animate, duration, function(){
7277                         this.unclip();
7278                         if(typeof onComplete == "function") onComplete();
7279                     }.createDelegate(this), easing);
7280                 }
7281             }.createDelegate(this), 0);
7282             return this;
7283         },
7284
7285         /**
7286          * Returns true if this element is an ancestor of the passed element
7287          * @param {HTMLElement/String} el The element to check
7288          * @return {Boolean} True if this element is an ancestor of el, else false
7289          */
7290         contains : function(el){
7291             if(!el){return false;}
7292             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7293         },
7294
7295         /**
7296          * Checks whether the element is currently visible using both visibility and display properties.
7297          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7298          * @return {Boolean} True if the element is currently visible, else false
7299          */
7300         isVisible : function(deep) {
7301             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7302             if(deep !== true || !vis){
7303                 return vis;
7304             }
7305             var p = this.dom.parentNode;
7306             while(p && p.tagName.toLowerCase() != "body"){
7307                 if(!Roo.fly(p, '_isVisible').isVisible()){
7308                     return false;
7309                 }
7310                 p = p.parentNode;
7311             }
7312             return true;
7313         },
7314
7315         /**
7316          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7317          * @param {String} selector The CSS selector
7318          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7319          * @return {CompositeElement/CompositeElementLite} The composite element
7320          */
7321         select : function(selector, unique){
7322             return El.select(selector, unique, this.dom);
7323         },
7324
7325         /**
7326          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7327          * @param {String} selector The CSS selector
7328          * @return {Array} An array of the matched nodes
7329          */
7330         query : function(selector, unique){
7331             return Roo.DomQuery.select(selector, this.dom);
7332         },
7333
7334         /**
7335          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7336          * @param {String} selector The CSS selector
7337          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7338          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7339          */
7340         child : function(selector, returnDom){
7341             var n = Roo.DomQuery.selectNode(selector, this.dom);
7342             return returnDom ? n : Roo.get(n);
7343         },
7344
7345         /**
7346          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7347          * @param {String} selector The CSS selector
7348          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7349          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7350          */
7351         down : function(selector, returnDom){
7352             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7353             return returnDom ? n : Roo.get(n);
7354         },
7355
7356         /**
7357          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7358          * @param {String} group The group the DD object is member of
7359          * @param {Object} config The DD config object
7360          * @param {Object} overrides An object containing methods to override/implement on the DD object
7361          * @return {Roo.dd.DD} The DD object
7362          */
7363         initDD : function(group, config, overrides){
7364             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7365             return Roo.apply(dd, overrides);
7366         },
7367
7368         /**
7369          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7370          * @param {String} group The group the DDProxy object is member of
7371          * @param {Object} config The DDProxy config object
7372          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7373          * @return {Roo.dd.DDProxy} The DDProxy object
7374          */
7375         initDDProxy : function(group, config, overrides){
7376             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7377             return Roo.apply(dd, overrides);
7378         },
7379
7380         /**
7381          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7382          * @param {String} group The group the DDTarget object is member of
7383          * @param {Object} config The DDTarget config object
7384          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7385          * @return {Roo.dd.DDTarget} The DDTarget object
7386          */
7387         initDDTarget : function(group, config, overrides){
7388             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7389             return Roo.apply(dd, overrides);
7390         },
7391
7392         /**
7393          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7394          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7395          * @param {Boolean} visible Whether the element is visible
7396          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7397          * @return {Roo.Element} this
7398          */
7399          setVisible : function(visible, animate){
7400             if(!animate || !A){
7401                 if(this.visibilityMode == El.DISPLAY){
7402                     this.setDisplayed(visible);
7403                 }else{
7404                     this.fixDisplay();
7405                     this.dom.style.visibility = visible ? "visible" : "hidden";
7406                 }
7407             }else{
7408                 // closure for composites
7409                 var dom = this.dom;
7410                 var visMode = this.visibilityMode;
7411                 if(visible){
7412                     this.setOpacity(.01);
7413                     this.setVisible(true);
7414                 }
7415                 this.anim({opacity: { to: (visible?1:0) }},
7416                       this.preanim(arguments, 1),
7417                       null, .35, 'easeIn', function(){
7418                          if(!visible){
7419                              if(visMode == El.DISPLAY){
7420                                  dom.style.display = "none";
7421                              }else{
7422                                  dom.style.visibility = "hidden";
7423                              }
7424                              Roo.get(dom).setOpacity(1);
7425                          }
7426                      });
7427             }
7428             return this;
7429         },
7430
7431         /**
7432          * Returns true if display is not "none"
7433          * @return {Boolean}
7434          */
7435         isDisplayed : function() {
7436             return this.getStyle("display") != "none";
7437         },
7438
7439         /**
7440          * Toggles the element's visibility or display, depending on visibility mode.
7441          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7442          * @return {Roo.Element} this
7443          */
7444         toggle : function(animate){
7445             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7446             return this;
7447         },
7448
7449         /**
7450          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7451          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7452          * @return {Roo.Element} this
7453          */
7454         setDisplayed : function(value) {
7455             if(typeof value == "boolean"){
7456                value = value ? this.originalDisplay : "none";
7457             }
7458             this.setStyle("display", value);
7459             return this;
7460         },
7461
7462         /**
7463          * Tries to focus the element. Any exceptions are caught and ignored.
7464          * @return {Roo.Element} this
7465          */
7466         focus : function() {
7467             try{
7468                 this.dom.focus();
7469             }catch(e){}
7470             return this;
7471         },
7472
7473         /**
7474          * Tries to blur the element. Any exceptions are caught and ignored.
7475          * @return {Roo.Element} this
7476          */
7477         blur : function() {
7478             try{
7479                 this.dom.blur();
7480             }catch(e){}
7481             return this;
7482         },
7483
7484         /**
7485          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7486          * @param {String/Array} className The CSS class to add, or an array of classes
7487          * @return {Roo.Element} this
7488          */
7489         addClass : function(className){
7490             if(className instanceof Array){
7491                 for(var i = 0, len = className.length; i < len; i++) {
7492                     this.addClass(className[i]);
7493                 }
7494             }else{
7495                 if(className && !this.hasClass(className)){
7496                     this.dom.className = this.dom.className + " " + className;
7497                 }
7498             }
7499             return this;
7500         },
7501
7502         /**
7503          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7504          * @param {String/Array} className The CSS class to add, or an array of classes
7505          * @return {Roo.Element} this
7506          */
7507         radioClass : function(className){
7508             var siblings = this.dom.parentNode.childNodes;
7509             for(var i = 0; i < siblings.length; i++) {
7510                 var s = siblings[i];
7511                 if(s.nodeType == 1){
7512                     Roo.get(s).removeClass(className);
7513                 }
7514             }
7515             this.addClass(className);
7516             return this;
7517         },
7518
7519         /**
7520          * Removes one or more CSS classes from the element.
7521          * @param {String/Array} className The CSS class to remove, or an array of classes
7522          * @return {Roo.Element} this
7523          */
7524         removeClass : function(className){
7525             if(!className || !this.dom.className){
7526                 return this;
7527             }
7528             if(className instanceof Array){
7529                 for(var i = 0, len = className.length; i < len; i++) {
7530                     this.removeClass(className[i]);
7531                 }
7532             }else{
7533                 if(this.hasClass(className)){
7534                     var re = this.classReCache[className];
7535                     if (!re) {
7536                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7537                        this.classReCache[className] = re;
7538                     }
7539                     this.dom.className =
7540                         this.dom.className.replace(re, " ");
7541                 }
7542             }
7543             return this;
7544         },
7545
7546         // private
7547         classReCache: {},
7548
7549         /**
7550          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7551          * @param {String} className The CSS class to toggle
7552          * @return {Roo.Element} this
7553          */
7554         toggleClass : function(className){
7555             if(this.hasClass(className)){
7556                 this.removeClass(className);
7557             }else{
7558                 this.addClass(className);
7559             }
7560             return this;
7561         },
7562
7563         /**
7564          * Checks if the specified CSS class exists on this element's DOM node.
7565          * @param {String} className The CSS class to check for
7566          * @return {Boolean} True if the class exists, else false
7567          */
7568         hasClass : function(className){
7569             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7570         },
7571
7572         /**
7573          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7574          * @param {String} oldClassName The CSS class to replace
7575          * @param {String} newClassName The replacement CSS class
7576          * @return {Roo.Element} this
7577          */
7578         replaceClass : function(oldClassName, newClassName){
7579             this.removeClass(oldClassName);
7580             this.addClass(newClassName);
7581             return this;
7582         },
7583
7584         /**
7585          * Returns an object with properties matching the styles requested.
7586          * For example, el.getStyles('color', 'font-size', 'width') might return
7587          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7588          * @param {String} style1 A style name
7589          * @param {String} style2 A style name
7590          * @param {String} etc.
7591          * @return {Object} The style object
7592          */
7593         getStyles : function(){
7594             var a = arguments, len = a.length, r = {};
7595             for(var i = 0; i < len; i++){
7596                 r[a[i]] = this.getStyle(a[i]);
7597             }
7598             return r;
7599         },
7600
7601         /**
7602          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7603          * @param {String} property The style property whose value is returned.
7604          * @return {String} The current value of the style property for this element.
7605          */
7606         getStyle : function(){
7607             return view && view.getComputedStyle ?
7608                 function(prop){
7609                     var el = this.dom, v, cs, camel;
7610                     if(prop == 'float'){
7611                         prop = "cssFloat";
7612                     }
7613                     if(el.style && (v = el.style[prop])){
7614                         return v;
7615                     }
7616                     if(cs = view.getComputedStyle(el, "")){
7617                         if(!(camel = propCache[prop])){
7618                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7619                         }
7620                         return cs[camel];
7621                     }
7622                     return null;
7623                 } :
7624                 function(prop){
7625                     var el = this.dom, v, cs, camel;
7626                     if(prop == 'opacity'){
7627                         if(typeof el.style.filter == 'string'){
7628                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7629                             if(m){
7630                                 var fv = parseFloat(m[1]);
7631                                 if(!isNaN(fv)){
7632                                     return fv ? fv / 100 : 0;
7633                                 }
7634                             }
7635                         }
7636                         return 1;
7637                     }else if(prop == 'float'){
7638                         prop = "styleFloat";
7639                     }
7640                     if(!(camel = propCache[prop])){
7641                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7642                     }
7643                     if(v = el.style[camel]){
7644                         return v;
7645                     }
7646                     if(cs = el.currentStyle){
7647                         return cs[camel];
7648                     }
7649                     return null;
7650                 };
7651         }(),
7652
7653         /**
7654          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7655          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7656          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7657          * @return {Roo.Element} this
7658          */
7659         setStyle : function(prop, value){
7660             if(typeof prop == "string"){
7661                 
7662                 if (prop == 'float') {
7663                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7664                     return this;
7665                 }
7666                 
7667                 var camel;
7668                 if(!(camel = propCache[prop])){
7669                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7670                 }
7671                 
7672                 if(camel == 'opacity') {
7673                     this.setOpacity(value);
7674                 }else{
7675                     this.dom.style[camel] = value;
7676                 }
7677             }else{
7678                 for(var style in prop){
7679                     if(typeof prop[style] != "function"){
7680                        this.setStyle(style, prop[style]);
7681                     }
7682                 }
7683             }
7684             return this;
7685         },
7686
7687         /**
7688          * More flexible version of {@link #setStyle} for setting style properties.
7689          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7690          * a function which returns such a specification.
7691          * @return {Roo.Element} this
7692          */
7693         applyStyles : function(style){
7694             Roo.DomHelper.applyStyles(this.dom, style);
7695             return this;
7696         },
7697
7698         /**
7699           * 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).
7700           * @return {Number} The X position of the element
7701           */
7702         getX : function(){
7703             return D.getX(this.dom);
7704         },
7705
7706         /**
7707           * 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).
7708           * @return {Number} The Y position of the element
7709           */
7710         getY : function(){
7711             return D.getY(this.dom);
7712         },
7713
7714         /**
7715           * 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).
7716           * @return {Array} The XY position of the element
7717           */
7718         getXY : function(){
7719             return D.getXY(this.dom);
7720         },
7721
7722         /**
7723          * 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).
7724          * @param {Number} The X position of the element
7725          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7726          * @return {Roo.Element} this
7727          */
7728         setX : function(x, animate){
7729             if(!animate || !A){
7730                 D.setX(this.dom, x);
7731             }else{
7732                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7733             }
7734             return this;
7735         },
7736
7737         /**
7738          * 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).
7739          * @param {Number} The Y position of the element
7740          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7741          * @return {Roo.Element} this
7742          */
7743         setY : function(y, animate){
7744             if(!animate || !A){
7745                 D.setY(this.dom, y);
7746             }else{
7747                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7748             }
7749             return this;
7750         },
7751
7752         /**
7753          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7754          * @param {String} left The left CSS property value
7755          * @return {Roo.Element} this
7756          */
7757         setLeft : function(left){
7758             this.setStyle("left", this.addUnits(left));
7759             return this;
7760         },
7761
7762         /**
7763          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7764          * @param {String} top The top CSS property value
7765          * @return {Roo.Element} this
7766          */
7767         setTop : function(top){
7768             this.setStyle("top", this.addUnits(top));
7769             return this;
7770         },
7771
7772         /**
7773          * Sets the element's CSS right style.
7774          * @param {String} right The right CSS property value
7775          * @return {Roo.Element} this
7776          */
7777         setRight : function(right){
7778             this.setStyle("right", this.addUnits(right));
7779             return this;
7780         },
7781
7782         /**
7783          * Sets the element's CSS bottom style.
7784          * @param {String} bottom The bottom CSS property value
7785          * @return {Roo.Element} this
7786          */
7787         setBottom : function(bottom){
7788             this.setStyle("bottom", this.addUnits(bottom));
7789             return this;
7790         },
7791
7792         /**
7793          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7794          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7795          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7796          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7797          * @return {Roo.Element} this
7798          */
7799         setXY : function(pos, animate){
7800             if(!animate || !A){
7801                 D.setXY(this.dom, pos);
7802             }else{
7803                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7804             }
7805             return this;
7806         },
7807
7808         /**
7809          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7810          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7811          * @param {Number} x X value for new position (coordinates are page-based)
7812          * @param {Number} y Y value for new position (coordinates are page-based)
7813          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7814          * @return {Roo.Element} this
7815          */
7816         setLocation : function(x, y, animate){
7817             this.setXY([x, y], this.preanim(arguments, 2));
7818             return this;
7819         },
7820
7821         /**
7822          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7823          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7824          * @param {Number} x X value for new position (coordinates are page-based)
7825          * @param {Number} y Y value for new position (coordinates are page-based)
7826          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7827          * @return {Roo.Element} this
7828          */
7829         moveTo : function(x, y, animate){
7830             this.setXY([x, y], this.preanim(arguments, 2));
7831             return this;
7832         },
7833
7834         /**
7835          * Returns the region of the given element.
7836          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7837          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7838          */
7839         getRegion : function(){
7840             return D.getRegion(this.dom);
7841         },
7842
7843         /**
7844          * Returns the offset height of the element
7845          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7846          * @return {Number} The element's height
7847          */
7848         getHeight : function(contentHeight){
7849             var h = this.dom.offsetHeight || 0;
7850             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7851         },
7852
7853         /**
7854          * Returns the offset width of the element
7855          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7856          * @return {Number} The element's width
7857          */
7858         getWidth : function(contentWidth){
7859             var w = this.dom.offsetWidth || 0;
7860             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7861         },
7862
7863         /**
7864          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7865          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7866          * if a height has not been set using CSS.
7867          * @return {Number}
7868          */
7869         getComputedHeight : function(){
7870             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7871             if(!h){
7872                 h = parseInt(this.getStyle('height'), 10) || 0;
7873                 if(!this.isBorderBox()){
7874                     h += this.getFrameWidth('tb');
7875                 }
7876             }
7877             return h;
7878         },
7879
7880         /**
7881          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7882          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7883          * if a width has not been set using CSS.
7884          * @return {Number}
7885          */
7886         getComputedWidth : function(){
7887             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7888             if(!w){
7889                 w = parseInt(this.getStyle('width'), 10) || 0;
7890                 if(!this.isBorderBox()){
7891                     w += this.getFrameWidth('lr');
7892                 }
7893             }
7894             return w;
7895         },
7896
7897         /**
7898          * Returns the size of the element.
7899          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7900          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7901          */
7902         getSize : function(contentSize){
7903             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7904         },
7905
7906         /**
7907          * Returns the width and height of the viewport.
7908          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7909          */
7910         getViewSize : function(){
7911             var d = this.dom, doc = document, aw = 0, ah = 0;
7912             if(d == doc || d == doc.body){
7913                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7914             }else{
7915                 return {
7916                     width : d.clientWidth,
7917                     height: d.clientHeight
7918                 };
7919             }
7920         },
7921
7922         /**
7923          * Returns the value of the "value" attribute
7924          * @param {Boolean} asNumber true to parse the value as a number
7925          * @return {String/Number}
7926          */
7927         getValue : function(asNumber){
7928             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7929         },
7930
7931         // private
7932         adjustWidth : function(width){
7933             if(typeof width == "number"){
7934                 if(this.autoBoxAdjust && !this.isBorderBox()){
7935                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7936                 }
7937                 if(width < 0){
7938                     width = 0;
7939                 }
7940             }
7941             return width;
7942         },
7943
7944         // private
7945         adjustHeight : function(height){
7946             if(typeof height == "number"){
7947                if(this.autoBoxAdjust && !this.isBorderBox()){
7948                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7949                }
7950                if(height < 0){
7951                    height = 0;
7952                }
7953             }
7954             return height;
7955         },
7956
7957         /**
7958          * Set the width of the element
7959          * @param {Number} width The new width
7960          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7961          * @return {Roo.Element} this
7962          */
7963         setWidth : function(width, animate){
7964             width = this.adjustWidth(width);
7965             if(!animate || !A){
7966                 this.dom.style.width = this.addUnits(width);
7967             }else{
7968                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7969             }
7970             return this;
7971         },
7972
7973         /**
7974          * Set the height of the element
7975          * @param {Number} height The new height
7976          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7977          * @return {Roo.Element} this
7978          */
7979          setHeight : function(height, animate){
7980             height = this.adjustHeight(height);
7981             if(!animate || !A){
7982                 this.dom.style.height = this.addUnits(height);
7983             }else{
7984                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7985             }
7986             return this;
7987         },
7988
7989         /**
7990          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
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          setSize : function(width, height, animate){
7997             if(typeof width == "object"){ // in case of object from getSize()
7998                 height = width.height; width = width.width;
7999             }
8000             width = this.adjustWidth(width); height = this.adjustHeight(height);
8001             if(!animate || !A){
8002                 this.dom.style.width = this.addUnits(width);
8003                 this.dom.style.height = this.addUnits(height);
8004             }else{
8005                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8006             }
8007             return this;
8008         },
8009
8010         /**
8011          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8012          * @param {Number} x X value for new position (coordinates are page-based)
8013          * @param {Number} y Y value for new position (coordinates are page-based)
8014          * @param {Number} width The new width
8015          * @param {Number} height The new height
8016          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8017          * @return {Roo.Element} this
8018          */
8019         setBounds : function(x, y, width, height, animate){
8020             if(!animate || !A){
8021                 this.setSize(width, height);
8022                 this.setLocation(x, y);
8023             }else{
8024                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8025                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8026                               this.preanim(arguments, 4), 'motion');
8027             }
8028             return this;
8029         },
8030
8031         /**
8032          * 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.
8033          * @param {Roo.lib.Region} region The region to fill
8034          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8035          * @return {Roo.Element} this
8036          */
8037         setRegion : function(region, animate){
8038             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8039             return this;
8040         },
8041
8042         /**
8043          * Appends an event handler
8044          *
8045          * @param {String}   eventName     The type of event to append
8046          * @param {Function} fn        The method the event invokes
8047          * @param {Object} scope       (optional) The scope (this object) of the fn
8048          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8049          */
8050         addListener : function(eventName, fn, scope, options){
8051             if (this.dom) {
8052                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8053             }
8054         },
8055
8056         /**
8057          * Removes an event handler from this element
8058          * @param {String} eventName the type of event to remove
8059          * @param {Function} fn the method the event invokes
8060          * @return {Roo.Element} this
8061          */
8062         removeListener : function(eventName, fn){
8063             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8064             return this;
8065         },
8066
8067         /**
8068          * Removes all previous added listeners from this element
8069          * @return {Roo.Element} this
8070          */
8071         removeAllListeners : function(){
8072             E.purgeElement(this.dom);
8073             return this;
8074         },
8075
8076         relayEvent : function(eventName, observable){
8077             this.on(eventName, function(e){
8078                 observable.fireEvent(eventName, e);
8079             });
8080         },
8081
8082         /**
8083          * Set the opacity of the element
8084          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8085          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8086          * @return {Roo.Element} this
8087          */
8088          setOpacity : function(opacity, animate){
8089             if(!animate || !A){
8090                 var s = this.dom.style;
8091                 if(Roo.isIE){
8092                     s.zoom = 1;
8093                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8094                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8095                 }else{
8096                     s.opacity = opacity;
8097                 }
8098             }else{
8099                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8100             }
8101             return this;
8102         },
8103
8104         /**
8105          * Gets the left X coordinate
8106          * @param {Boolean} local True to get the local css position instead of page coordinate
8107          * @return {Number}
8108          */
8109         getLeft : function(local){
8110             if(!local){
8111                 return this.getX();
8112             }else{
8113                 return parseInt(this.getStyle("left"), 10) || 0;
8114             }
8115         },
8116
8117         /**
8118          * Gets the right X coordinate of the element (element X position + element width)
8119          * @param {Boolean} local True to get the local css position instead of page coordinate
8120          * @return {Number}
8121          */
8122         getRight : function(local){
8123             if(!local){
8124                 return this.getX() + this.getWidth();
8125             }else{
8126                 return (this.getLeft(true) + this.getWidth()) || 0;
8127             }
8128         },
8129
8130         /**
8131          * Gets the top Y coordinate
8132          * @param {Boolean} local True to get the local css position instead of page coordinate
8133          * @return {Number}
8134          */
8135         getTop : function(local) {
8136             if(!local){
8137                 return this.getY();
8138             }else{
8139                 return parseInt(this.getStyle("top"), 10) || 0;
8140             }
8141         },
8142
8143         /**
8144          * Gets the bottom Y coordinate of the element (element Y position + element height)
8145          * @param {Boolean} local True to get the local css position instead of page coordinate
8146          * @return {Number}
8147          */
8148         getBottom : function(local){
8149             if(!local){
8150                 return this.getY() + this.getHeight();
8151             }else{
8152                 return (this.getTop(true) + this.getHeight()) || 0;
8153             }
8154         },
8155
8156         /**
8157         * Initializes positioning on this element. If a desired position is not passed, it will make the
8158         * the element positioned relative IF it is not already positioned.
8159         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8160         * @param {Number} zIndex (optional) The zIndex to apply
8161         * @param {Number} x (optional) Set the page X position
8162         * @param {Number} y (optional) Set the page Y position
8163         */
8164         position : function(pos, zIndex, x, y){
8165             if(!pos){
8166                if(this.getStyle('position') == 'static'){
8167                    this.setStyle('position', 'relative');
8168                }
8169             }else{
8170                 this.setStyle("position", pos);
8171             }
8172             if(zIndex){
8173                 this.setStyle("z-index", zIndex);
8174             }
8175             if(x !== undefined && y !== undefined){
8176                 this.setXY([x, y]);
8177             }else if(x !== undefined){
8178                 this.setX(x);
8179             }else if(y !== undefined){
8180                 this.setY(y);
8181             }
8182         },
8183
8184         /**
8185         * Clear positioning back to the default when the document was loaded
8186         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8187         * @return {Roo.Element} this
8188          */
8189         clearPositioning : function(value){
8190             value = value ||'';
8191             this.setStyle({
8192                 "left": value,
8193                 "right": value,
8194                 "top": value,
8195                 "bottom": value,
8196                 "z-index": "",
8197                 "position" : "static"
8198             });
8199             return this;
8200         },
8201
8202         /**
8203         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8204         * snapshot before performing an update and then restoring the element.
8205         * @return {Object}
8206         */
8207         getPositioning : function(){
8208             var l = this.getStyle("left");
8209             var t = this.getStyle("top");
8210             return {
8211                 "position" : this.getStyle("position"),
8212                 "left" : l,
8213                 "right" : l ? "" : this.getStyle("right"),
8214                 "top" : t,
8215                 "bottom" : t ? "" : this.getStyle("bottom"),
8216                 "z-index" : this.getStyle("z-index")
8217             };
8218         },
8219
8220         /**
8221          * Gets the width of the border(s) for the specified side(s)
8222          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8223          * passing lr would get the border (l)eft width + the border (r)ight width.
8224          * @return {Number} The width of the sides passed added together
8225          */
8226         getBorderWidth : function(side){
8227             return this.addStyles(side, El.borders);
8228         },
8229
8230         /**
8231          * Gets the width of the padding(s) for the specified side(s)
8232          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8233          * passing lr would get the padding (l)eft + the padding (r)ight.
8234          * @return {Number} The padding of the sides passed added together
8235          */
8236         getPadding : function(side){
8237             return this.addStyles(side, El.paddings);
8238         },
8239
8240         /**
8241         * Set positioning with an object returned by getPositioning().
8242         * @param {Object} posCfg
8243         * @return {Roo.Element} this
8244          */
8245         setPositioning : function(pc){
8246             this.applyStyles(pc);
8247             if(pc.right == "auto"){
8248                 this.dom.style.right = "";
8249             }
8250             if(pc.bottom == "auto"){
8251                 this.dom.style.bottom = "";
8252             }
8253             return this;
8254         },
8255
8256         // private
8257         fixDisplay : function(){
8258             if(this.getStyle("display") == "none"){
8259                 this.setStyle("visibility", "hidden");
8260                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8261                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8262                     this.setStyle("display", "block");
8263                 }
8264             }
8265         },
8266
8267         /**
8268          * Quick set left and top adding default units
8269          * @param {String} left The left CSS property value
8270          * @param {String} top The top CSS property value
8271          * @return {Roo.Element} this
8272          */
8273          setLeftTop : function(left, top){
8274             this.dom.style.left = this.addUnits(left);
8275             this.dom.style.top = this.addUnits(top);
8276             return this;
8277         },
8278
8279         /**
8280          * Move this element relative to its current position.
8281          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8282          * @param {Number} distance How far to move the element in pixels
8283          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8284          * @return {Roo.Element} this
8285          */
8286          move : function(direction, distance, animate){
8287             var xy = this.getXY();
8288             direction = direction.toLowerCase();
8289             switch(direction){
8290                 case "l":
8291                 case "left":
8292                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8293                     break;
8294                case "r":
8295                case "right":
8296                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8297                     break;
8298                case "t":
8299                case "top":
8300                case "up":
8301                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8302                     break;
8303                case "b":
8304                case "bottom":
8305                case "down":
8306                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8307                     break;
8308             }
8309             return this;
8310         },
8311
8312         /**
8313          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8314          * @return {Roo.Element} this
8315          */
8316         clip : function(){
8317             if(!this.isClipped){
8318                this.isClipped = true;
8319                this.originalClip = {
8320                    "o": this.getStyle("overflow"),
8321                    "x": this.getStyle("overflow-x"),
8322                    "y": this.getStyle("overflow-y")
8323                };
8324                this.setStyle("overflow", "hidden");
8325                this.setStyle("overflow-x", "hidden");
8326                this.setStyle("overflow-y", "hidden");
8327             }
8328             return this;
8329         },
8330
8331         /**
8332          *  Return clipping (overflow) to original clipping before clip() was called
8333          * @return {Roo.Element} this
8334          */
8335         unclip : function(){
8336             if(this.isClipped){
8337                 this.isClipped = false;
8338                 var o = this.originalClip;
8339                 if(o.o){this.setStyle("overflow", o.o);}
8340                 if(o.x){this.setStyle("overflow-x", o.x);}
8341                 if(o.y){this.setStyle("overflow-y", o.y);}
8342             }
8343             return this;
8344         },
8345
8346
8347         /**
8348          * Gets the x,y coordinates specified by the anchor position on the element.
8349          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8350          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8351          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8352          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8353          * @return {Array} [x, y] An array containing the element's x and y coordinates
8354          */
8355         getAnchorXY : function(anchor, local, s){
8356             //Passing a different size is useful for pre-calculating anchors,
8357             //especially for anchored animations that change the el size.
8358
8359             var w, h, vp = false;
8360             if(!s){
8361                 var d = this.dom;
8362                 if(d == document.body || d == document){
8363                     vp = true;
8364                     w = D.getViewWidth(); h = D.getViewHeight();
8365                 }else{
8366                     w = this.getWidth(); h = this.getHeight();
8367                 }
8368             }else{
8369                 w = s.width;  h = s.height;
8370             }
8371             var x = 0, y = 0, r = Math.round;
8372             switch((anchor || "tl").toLowerCase()){
8373                 case "c":
8374                     x = r(w*.5);
8375                     y = r(h*.5);
8376                 break;
8377                 case "t":
8378                     x = r(w*.5);
8379                     y = 0;
8380                 break;
8381                 case "l":
8382                     x = 0;
8383                     y = r(h*.5);
8384                 break;
8385                 case "r":
8386                     x = w;
8387                     y = r(h*.5);
8388                 break;
8389                 case "b":
8390                     x = r(w*.5);
8391                     y = h;
8392                 break;
8393                 case "tl":
8394                     x = 0;
8395                     y = 0;
8396                 break;
8397                 case "bl":
8398                     x = 0;
8399                     y = h;
8400                 break;
8401                 case "br":
8402                     x = w;
8403                     y = h;
8404                 break;
8405                 case "tr":
8406                     x = w;
8407                     y = 0;
8408                 break;
8409             }
8410             if(local === true){
8411                 return [x, y];
8412             }
8413             if(vp){
8414                 var sc = this.getScroll();
8415                 return [x + sc.left, y + sc.top];
8416             }
8417             //Add the element's offset xy
8418             var o = this.getXY();
8419             return [x+o[0], y+o[1]];
8420         },
8421
8422         /**
8423          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8424          * supported position values.
8425          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8426          * @param {String} position The position to align to.
8427          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8428          * @return {Array} [x, y]
8429          */
8430         getAlignToXY : function(el, p, o){
8431             el = Roo.get(el);
8432             var d = this.dom;
8433             if(!el.dom){
8434                 throw "Element.alignTo with an element that doesn't exist";
8435             }
8436             var c = false; //constrain to viewport
8437             var p1 = "", p2 = "";
8438             o = o || [0,0];
8439
8440             if(!p){
8441                 p = "tl-bl";
8442             }else if(p == "?"){
8443                 p = "tl-bl?";
8444             }else if(p.indexOf("-") == -1){
8445                 p = "tl-" + p;
8446             }
8447             p = p.toLowerCase();
8448             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8449             if(!m){
8450                throw "Element.alignTo with an invalid alignment " + p;
8451             }
8452             p1 = m[1]; p2 = m[2]; c = !!m[3];
8453
8454             //Subtract the aligned el's internal xy from the target's offset xy
8455             //plus custom offset to get the aligned el's new offset xy
8456             var a1 = this.getAnchorXY(p1, true);
8457             var a2 = el.getAnchorXY(p2, false);
8458             var x = a2[0] - a1[0] + o[0];
8459             var y = a2[1] - a1[1] + o[1];
8460             if(c){
8461                 //constrain the aligned el to viewport if necessary
8462                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8463                 // 5px of margin for ie
8464                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8465
8466                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8467                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8468                 //otherwise swap the aligned el to the opposite border of the target.
8469                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8470                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8471                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8472                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8473
8474                var doc = document;
8475                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8476                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8477
8478                if((x+w) > dw + scrollX){
8479                     x = swapX ? r.left-w : dw+scrollX-w;
8480                 }
8481                if(x < scrollX){
8482                    x = swapX ? r.right : scrollX;
8483                }
8484                if((y+h) > dh + scrollY){
8485                     y = swapY ? r.top-h : dh+scrollY-h;
8486                 }
8487                if (y < scrollY){
8488                    y = swapY ? r.bottom : scrollY;
8489                }
8490             }
8491             return [x,y];
8492         },
8493
8494         // private
8495         getConstrainToXY : function(){
8496             var os = {top:0, left:0, bottom:0, right: 0};
8497
8498             return function(el, local, offsets, proposedXY){
8499                 el = Roo.get(el);
8500                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8501
8502                 var vw, vh, vx = 0, vy = 0;
8503                 if(el.dom == document.body || el.dom == document){
8504                     vw = Roo.lib.Dom.getViewWidth();
8505                     vh = Roo.lib.Dom.getViewHeight();
8506                 }else{
8507                     vw = el.dom.clientWidth;
8508                     vh = el.dom.clientHeight;
8509                     if(!local){
8510                         var vxy = el.getXY();
8511                         vx = vxy[0];
8512                         vy = vxy[1];
8513                     }
8514                 }
8515
8516                 var s = el.getScroll();
8517
8518                 vx += offsets.left + s.left;
8519                 vy += offsets.top + s.top;
8520
8521                 vw -= offsets.right;
8522                 vh -= offsets.bottom;
8523
8524                 var vr = vx+vw;
8525                 var vb = vy+vh;
8526
8527                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8528                 var x = xy[0], y = xy[1];
8529                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8530
8531                 // only move it if it needs it
8532                 var moved = false;
8533
8534                 // first validate right/bottom
8535                 if((x + w) > vr){
8536                     x = vr - w;
8537                     moved = true;
8538                 }
8539                 if((y + h) > vb){
8540                     y = vb - h;
8541                     moved = true;
8542                 }
8543                 // then make sure top/left isn't negative
8544                 if(x < vx){
8545                     x = vx;
8546                     moved = true;
8547                 }
8548                 if(y < vy){
8549                     y = vy;
8550                     moved = true;
8551                 }
8552                 return moved ? [x, y] : false;
8553             };
8554         }(),
8555
8556         // private
8557         adjustForConstraints : function(xy, parent, offsets){
8558             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8559         },
8560
8561         /**
8562          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8563          * document it aligns it to the viewport.
8564          * The position parameter is optional, and can be specified in any one of the following formats:
8565          * <ul>
8566          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8567          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8568          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8569          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8570          *   <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
8571          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8572          * </ul>
8573          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8574          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8575          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8576          * that specified in order to enforce the viewport constraints.
8577          * Following are all of the supported anchor positions:
8578     <pre>
8579     Value  Description
8580     -----  -----------------------------
8581     tl     The top left corner (default)
8582     t      The center of the top edge
8583     tr     The top right corner
8584     l      The center of the left edge
8585     c      In the center of the element
8586     r      The center of the right edge
8587     bl     The bottom left corner
8588     b      The center of the bottom edge
8589     br     The bottom right corner
8590     </pre>
8591     Example Usage:
8592     <pre><code>
8593     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8594     el.alignTo("other-el");
8595
8596     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8597     el.alignTo("other-el", "tr?");
8598
8599     // align the bottom right corner of el with the center left edge of other-el
8600     el.alignTo("other-el", "br-l?");
8601
8602     // align the center of el with the bottom left corner of other-el and
8603     // adjust the x position by -6 pixels (and the y position by 0)
8604     el.alignTo("other-el", "c-bl", [-6, 0]);
8605     </code></pre>
8606          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8607          * @param {String} position The position to align to.
8608          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8609          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8610          * @return {Roo.Element} this
8611          */
8612         alignTo : function(element, position, offsets, animate){
8613             var xy = this.getAlignToXY(element, position, offsets);
8614             this.setXY(xy, this.preanim(arguments, 3));
8615             return this;
8616         },
8617
8618         /**
8619          * Anchors an element to another element and realigns it when the window is resized.
8620          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8621          * @param {String} position The position to align to.
8622          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8623          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8624          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8625          * is a number, it is used as the buffer delay (defaults to 50ms).
8626          * @param {Function} callback The function to call after the animation finishes
8627          * @return {Roo.Element} this
8628          */
8629         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8630             var action = function(){
8631                 this.alignTo(el, alignment, offsets, animate);
8632                 Roo.callback(callback, this);
8633             };
8634             Roo.EventManager.onWindowResize(action, this);
8635             var tm = typeof monitorScroll;
8636             if(tm != 'undefined'){
8637                 Roo.EventManager.on(window, 'scroll', action, this,
8638                     {buffer: tm == 'number' ? monitorScroll : 50});
8639             }
8640             action.call(this); // align immediately
8641             return this;
8642         },
8643         /**
8644          * Clears any opacity settings from this element. Required in some cases for IE.
8645          * @return {Roo.Element} this
8646          */
8647         clearOpacity : function(){
8648             if (window.ActiveXObject) {
8649                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8650                     this.dom.style.filter = "";
8651                 }
8652             } else {
8653                 this.dom.style.opacity = "";
8654                 this.dom.style["-moz-opacity"] = "";
8655                 this.dom.style["-khtml-opacity"] = "";
8656             }
8657             return this;
8658         },
8659
8660         /**
8661          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8662          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8663          * @return {Roo.Element} this
8664          */
8665         hide : function(animate){
8666             this.setVisible(false, this.preanim(arguments, 0));
8667             return this;
8668         },
8669
8670         /**
8671         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8672         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8673          * @return {Roo.Element} this
8674          */
8675         show : function(animate){
8676             this.setVisible(true, this.preanim(arguments, 0));
8677             return this;
8678         },
8679
8680         /**
8681          * @private Test if size has a unit, otherwise appends the default
8682          */
8683         addUnits : function(size){
8684             return Roo.Element.addUnits(size, this.defaultUnit);
8685         },
8686
8687         /**
8688          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8689          * @return {Roo.Element} this
8690          */
8691         beginMeasure : function(){
8692             var el = this.dom;
8693             if(el.offsetWidth || el.offsetHeight){
8694                 return this; // offsets work already
8695             }
8696             var changed = [];
8697             var p = this.dom, b = document.body; // start with this element
8698             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8699                 var pe = Roo.get(p);
8700                 if(pe.getStyle('display') == 'none'){
8701                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8702                     p.style.visibility = "hidden";
8703                     p.style.display = "block";
8704                 }
8705                 p = p.parentNode;
8706             }
8707             this._measureChanged = changed;
8708             return this;
8709
8710         },
8711
8712         /**
8713          * Restores displays to before beginMeasure was called
8714          * @return {Roo.Element} this
8715          */
8716         endMeasure : function(){
8717             var changed = this._measureChanged;
8718             if(changed){
8719                 for(var i = 0, len = changed.length; i < len; i++) {
8720                     var r = changed[i];
8721                     r.el.style.visibility = r.visibility;
8722                     r.el.style.display = "none";
8723                 }
8724                 this._measureChanged = null;
8725             }
8726             return this;
8727         },
8728
8729         /**
8730         * Update the innerHTML of this element, optionally searching for and processing scripts
8731         * @param {String} html The new HTML
8732         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8733         * @param {Function} callback For async script loading you can be noticed when the update completes
8734         * @return {Roo.Element} this
8735          */
8736         update : function(html, loadScripts, callback){
8737             if(typeof html == "undefined"){
8738                 html = "";
8739             }
8740             if(loadScripts !== true){
8741                 this.dom.innerHTML = html;
8742                 if(typeof callback == "function"){
8743                     callback();
8744                 }
8745                 return this;
8746             }
8747             var id = Roo.id();
8748             var dom = this.dom;
8749
8750             html += '<span id="' + id + '"></span>';
8751
8752             E.onAvailable(id, function(){
8753                 var hd = document.getElementsByTagName("head")[0];
8754                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8755                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8756                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8757
8758                 var match;
8759                 while(match = re.exec(html)){
8760                     var attrs = match[1];
8761                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8762                     if(srcMatch && srcMatch[2]){
8763                        var s = document.createElement("script");
8764                        s.src = srcMatch[2];
8765                        var typeMatch = attrs.match(typeRe);
8766                        if(typeMatch && typeMatch[2]){
8767                            s.type = typeMatch[2];
8768                        }
8769                        hd.appendChild(s);
8770                     }else if(match[2] && match[2].length > 0){
8771                         if(window.execScript) {
8772                            window.execScript(match[2]);
8773                         } else {
8774                             /**
8775                              * eval:var:id
8776                              * eval:var:dom
8777                              * eval:var:html
8778                              * 
8779                              */
8780                            window.eval(match[2]);
8781                         }
8782                     }
8783                 }
8784                 var el = document.getElementById(id);
8785                 if(el){el.parentNode.removeChild(el);}
8786                 if(typeof callback == "function"){
8787                     callback();
8788                 }
8789             });
8790             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8791             return this;
8792         },
8793
8794         /**
8795          * Direct access to the UpdateManager update() method (takes the same parameters).
8796          * @param {String/Function} url The url for this request or a function to call to get the url
8797          * @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}
8798          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8799          * @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.
8800          * @return {Roo.Element} this
8801          */
8802         load : function(){
8803             var um = this.getUpdateManager();
8804             um.update.apply(um, arguments);
8805             return this;
8806         },
8807
8808         /**
8809         * Gets this element's UpdateManager
8810         * @return {Roo.UpdateManager} The UpdateManager
8811         */
8812         getUpdateManager : function(){
8813             if(!this.updateManager){
8814                 this.updateManager = new Roo.UpdateManager(this);
8815             }
8816             return this.updateManager;
8817         },
8818
8819         /**
8820          * Disables text selection for this element (normalized across browsers)
8821          * @return {Roo.Element} this
8822          */
8823         unselectable : function(){
8824             this.dom.unselectable = "on";
8825             this.swallowEvent("selectstart", true);
8826             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8827             this.addClass("x-unselectable");
8828             return this;
8829         },
8830
8831         /**
8832         * Calculates the x, y to center this element on the screen
8833         * @return {Array} The x, y values [x, y]
8834         */
8835         getCenterXY : function(){
8836             return this.getAlignToXY(document, 'c-c');
8837         },
8838
8839         /**
8840         * Centers the Element in either the viewport, or another Element.
8841         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8842         */
8843         center : function(centerIn){
8844             this.alignTo(centerIn || document, 'c-c');
8845             return this;
8846         },
8847
8848         /**
8849          * Tests various css rules/browsers to determine if this element uses a border box
8850          * @return {Boolean}
8851          */
8852         isBorderBox : function(){
8853             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8854         },
8855
8856         /**
8857          * Return a box {x, y, width, height} that can be used to set another elements
8858          * size/location to match this element.
8859          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8860          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8861          * @return {Object} box An object in the format {x, y, width, height}
8862          */
8863         getBox : function(contentBox, local){
8864             var xy;
8865             if(!local){
8866                 xy = this.getXY();
8867             }else{
8868                 var left = parseInt(this.getStyle("left"), 10) || 0;
8869                 var top = parseInt(this.getStyle("top"), 10) || 0;
8870                 xy = [left, top];
8871             }
8872             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8873             if(!contentBox){
8874                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8875             }else{
8876                 var l = this.getBorderWidth("l")+this.getPadding("l");
8877                 var r = this.getBorderWidth("r")+this.getPadding("r");
8878                 var t = this.getBorderWidth("t")+this.getPadding("t");
8879                 var b = this.getBorderWidth("b")+this.getPadding("b");
8880                 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)};
8881             }
8882             bx.right = bx.x + bx.width;
8883             bx.bottom = bx.y + bx.height;
8884             return bx;
8885         },
8886
8887         /**
8888          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8889          for more information about the sides.
8890          * @param {String} sides
8891          * @return {Number}
8892          */
8893         getFrameWidth : function(sides, onlyContentBox){
8894             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8895         },
8896
8897         /**
8898          * 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.
8899          * @param {Object} box The box to fill {x, y, width, height}
8900          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8901          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8902          * @return {Roo.Element} this
8903          */
8904         setBox : function(box, adjust, animate){
8905             var w = box.width, h = box.height;
8906             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8907                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8908                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8909             }
8910             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8911             return this;
8912         },
8913
8914         /**
8915          * Forces the browser to repaint this element
8916          * @return {Roo.Element} this
8917          */
8918          repaint : function(){
8919             var dom = this.dom;
8920             this.addClass("x-repaint");
8921             setTimeout(function(){
8922                 Roo.get(dom).removeClass("x-repaint");
8923             }, 1);
8924             return this;
8925         },
8926
8927         /**
8928          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8929          * then it returns the calculated width of the sides (see getPadding)
8930          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8931          * @return {Object/Number}
8932          */
8933         getMargins : function(side){
8934             if(!side){
8935                 return {
8936                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8937                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8938                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8939                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8940                 };
8941             }else{
8942                 return this.addStyles(side, El.margins);
8943              }
8944         },
8945
8946         // private
8947         addStyles : function(sides, styles){
8948             var val = 0, v, w;
8949             for(var i = 0, len = sides.length; i < len; i++){
8950                 v = this.getStyle(styles[sides.charAt(i)]);
8951                 if(v){
8952                      w = parseInt(v, 10);
8953                      if(w){ val += w; }
8954                 }
8955             }
8956             return val;
8957         },
8958
8959         /**
8960          * Creates a proxy element of this element
8961          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8962          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8963          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8964          * @return {Roo.Element} The new proxy element
8965          */
8966         createProxy : function(config, renderTo, matchBox){
8967             if(renderTo){
8968                 renderTo = Roo.getDom(renderTo);
8969             }else{
8970                 renderTo = document.body;
8971             }
8972             config = typeof config == "object" ?
8973                 config : {tag : "div", cls: config};
8974             var proxy = Roo.DomHelper.append(renderTo, config, true);
8975             if(matchBox){
8976                proxy.setBox(this.getBox());
8977             }
8978             return proxy;
8979         },
8980
8981         /**
8982          * Puts a mask over this element to disable user interaction. Requires core.css.
8983          * This method can only be applied to elements which accept child nodes.
8984          * @param {String} msg (optional) A message to display in the mask
8985          * @param {String} msgCls (optional) A css class to apply to the msg element
8986          * @return {Element} The mask  element
8987          */
8988         mask : function(msg, msgCls)
8989         {
8990             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8991                 this.setStyle("position", "relative");
8992             }
8993             if(!this._mask){
8994                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8995             }
8996             this.addClass("x-masked");
8997             this._mask.setDisplayed(true);
8998             
8999             // we wander
9000             var z = 0;
9001             var dom = this.dom
9002             while (dom && dom.style) {
9003                 if (!isNaN(parseInt(dom.style.zIndex))) {
9004                     z = Math.max(z, parseInt(dom.style.zIndex));
9005                 }
9006                 dom = dom.parentNode;
9007             }
9008             // if we are masking the body - then it hides everything..
9009             if (this.dom == document.body) {
9010                 z = 1000000;
9011                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9012                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9013             }
9014            
9015             if(typeof msg == 'string'){
9016                 if(!this._maskMsg){
9017                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9018                 }
9019                 var mm = this._maskMsg;
9020                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9021                 if (mm.dom.firstChild) { // weird IE issue?
9022                     mm.dom.firstChild.innerHTML = msg;
9023                 }
9024                 mm.setDisplayed(true);
9025                 mm.center(this);
9026                 mm.setStyle('z-index', z + 102);
9027             }
9028             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9029                 this._mask.setHeight(this.getHeight());
9030             }
9031             this._mask.setStyle('z-index', z + 100);
9032             
9033             return this._mask;
9034         },
9035
9036         /**
9037          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9038          * it is cached for reuse.
9039          */
9040         unmask : function(removeEl){
9041             if(this._mask){
9042                 if(removeEl === true){
9043                     this._mask.remove();
9044                     delete this._mask;
9045                     if(this._maskMsg){
9046                         this._maskMsg.remove();
9047                         delete this._maskMsg;
9048                     }
9049                 }else{
9050                     this._mask.setDisplayed(false);
9051                     if(this._maskMsg){
9052                         this._maskMsg.setDisplayed(false);
9053                     }
9054                 }
9055             }
9056             this.removeClass("x-masked");
9057         },
9058
9059         /**
9060          * Returns true if this element is masked
9061          * @return {Boolean}
9062          */
9063         isMasked : function(){
9064             return this._mask && this._mask.isVisible();
9065         },
9066
9067         /**
9068          * Creates an iframe shim for this element to keep selects and other windowed objects from
9069          * showing through.
9070          * @return {Roo.Element} The new shim element
9071          */
9072         createShim : function(){
9073             var el = document.createElement('iframe');
9074             el.frameBorder = 'no';
9075             el.className = 'roo-shim';
9076             if(Roo.isIE && Roo.isSecure){
9077                 el.src = Roo.SSL_SECURE_URL;
9078             }
9079             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9080             shim.autoBoxAdjust = false;
9081             return shim;
9082         },
9083
9084         /**
9085          * Removes this element from the DOM and deletes it from the cache
9086          */
9087         remove : function(){
9088             if(this.dom.parentNode){
9089                 this.dom.parentNode.removeChild(this.dom);
9090             }
9091             delete El.cache[this.dom.id];
9092         },
9093
9094         /**
9095          * Sets up event handlers to add and remove a css class when the mouse is over this element
9096          * @param {String} className
9097          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9098          * mouseout events for children elements
9099          * @return {Roo.Element} this
9100          */
9101         addClassOnOver : function(className, preventFlicker){
9102             this.on("mouseover", function(){
9103                 Roo.fly(this, '_internal').addClass(className);
9104             }, this.dom);
9105             var removeFn = function(e){
9106                 if(preventFlicker !== true || !e.within(this, true)){
9107                     Roo.fly(this, '_internal').removeClass(className);
9108                 }
9109             };
9110             this.on("mouseout", removeFn, this.dom);
9111             return this;
9112         },
9113
9114         /**
9115          * Sets up event handlers to add and remove a css class when this element has the focus
9116          * @param {String} className
9117          * @return {Roo.Element} this
9118          */
9119         addClassOnFocus : function(className){
9120             this.on("focus", function(){
9121                 Roo.fly(this, '_internal').addClass(className);
9122             }, this.dom);
9123             this.on("blur", function(){
9124                 Roo.fly(this, '_internal').removeClass(className);
9125             }, this.dom);
9126             return this;
9127         },
9128         /**
9129          * 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)
9130          * @param {String} className
9131          * @return {Roo.Element} this
9132          */
9133         addClassOnClick : function(className){
9134             var dom = this.dom;
9135             this.on("mousedown", function(){
9136                 Roo.fly(dom, '_internal').addClass(className);
9137                 var d = Roo.get(document);
9138                 var fn = function(){
9139                     Roo.fly(dom, '_internal').removeClass(className);
9140                     d.removeListener("mouseup", fn);
9141                 };
9142                 d.on("mouseup", fn);
9143             });
9144             return this;
9145         },
9146
9147         /**
9148          * Stops the specified event from bubbling and optionally prevents the default action
9149          * @param {String} eventName
9150          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9151          * @return {Roo.Element} this
9152          */
9153         swallowEvent : function(eventName, preventDefault){
9154             var fn = function(e){
9155                 e.stopPropagation();
9156                 if(preventDefault){
9157                     e.preventDefault();
9158                 }
9159             };
9160             if(eventName instanceof Array){
9161                 for(var i = 0, len = eventName.length; i < len; i++){
9162                      this.on(eventName[i], fn);
9163                 }
9164                 return this;
9165             }
9166             this.on(eventName, fn);
9167             return this;
9168         },
9169
9170         /**
9171          * @private
9172          */
9173       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9174
9175         /**
9176          * Sizes this element to its parent element's dimensions performing
9177          * neccessary box adjustments.
9178          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9179          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9180          * @return {Roo.Element} this
9181          */
9182         fitToParent : function(monitorResize, targetParent) {
9183           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9184           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9185           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9186             return;
9187           }
9188           var p = Roo.get(targetParent || this.dom.parentNode);
9189           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9190           if (monitorResize === true) {
9191             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9192             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9193           }
9194           return this;
9195         },
9196
9197         /**
9198          * Gets the next sibling, skipping text nodes
9199          * @return {HTMLElement} The next sibling or null
9200          */
9201         getNextSibling : function(){
9202             var n = this.dom.nextSibling;
9203             while(n && n.nodeType != 1){
9204                 n = n.nextSibling;
9205             }
9206             return n;
9207         },
9208
9209         /**
9210          * Gets the previous sibling, skipping text nodes
9211          * @return {HTMLElement} The previous sibling or null
9212          */
9213         getPrevSibling : function(){
9214             var n = this.dom.previousSibling;
9215             while(n && n.nodeType != 1){
9216                 n = n.previousSibling;
9217             }
9218             return n;
9219         },
9220
9221
9222         /**
9223          * Appends the passed element(s) to this element
9224          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9225          * @return {Roo.Element} this
9226          */
9227         appendChild: function(el){
9228             el = Roo.get(el);
9229             el.appendTo(this);
9230             return this;
9231         },
9232
9233         /**
9234          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9235          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9236          * automatically generated with the specified attributes.
9237          * @param {HTMLElement} insertBefore (optional) a child element of this element
9238          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9239          * @return {Roo.Element} The new child element
9240          */
9241         createChild: function(config, insertBefore, returnDom){
9242             config = config || {tag:'div'};
9243             if(insertBefore){
9244                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9245             }
9246             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9247         },
9248
9249         /**
9250          * Appends this element to the passed element
9251          * @param {String/HTMLElement/Element} el The new parent element
9252          * @return {Roo.Element} this
9253          */
9254         appendTo: function(el){
9255             el = Roo.getDom(el);
9256             el.appendChild(this.dom);
9257             return this;
9258         },
9259
9260         /**
9261          * Inserts this element before the passed element in the DOM
9262          * @param {String/HTMLElement/Element} el The element to insert before
9263          * @return {Roo.Element} this
9264          */
9265         insertBefore: function(el){
9266             el = Roo.getDom(el);
9267             el.parentNode.insertBefore(this.dom, el);
9268             return this;
9269         },
9270
9271         /**
9272          * Inserts this element after the passed element in the DOM
9273          * @param {String/HTMLElement/Element} el The element to insert after
9274          * @return {Roo.Element} this
9275          */
9276         insertAfter: function(el){
9277             el = Roo.getDom(el);
9278             el.parentNode.insertBefore(this.dom, el.nextSibling);
9279             return this;
9280         },
9281
9282         /**
9283          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9284          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9285          * @return {Roo.Element} The new child
9286          */
9287         insertFirst: function(el, returnDom){
9288             el = el || {};
9289             if(typeof el == 'object' && !el.nodeType){ // dh config
9290                 return this.createChild(el, this.dom.firstChild, returnDom);
9291             }else{
9292                 el = Roo.getDom(el);
9293                 this.dom.insertBefore(el, this.dom.firstChild);
9294                 return !returnDom ? Roo.get(el) : el;
9295             }
9296         },
9297
9298         /**
9299          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9300          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9301          * @param {String} where (optional) 'before' or 'after' defaults to before
9302          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9303          * @return {Roo.Element} the inserted Element
9304          */
9305         insertSibling: function(el, where, returnDom){
9306             where = where ? where.toLowerCase() : 'before';
9307             el = el || {};
9308             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9309
9310             if(typeof el == 'object' && !el.nodeType){ // dh config
9311                 if(where == 'after' && !this.dom.nextSibling){
9312                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9313                 }else{
9314                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9315                 }
9316
9317             }else{
9318                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9319                             where == 'before' ? this.dom : this.dom.nextSibling);
9320                 if(!returnDom){
9321                     rt = Roo.get(rt);
9322                 }
9323             }
9324             return rt;
9325         },
9326
9327         /**
9328          * Creates and wraps this element with another element
9329          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9330          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9331          * @return {HTMLElement/Element} The newly created wrapper element
9332          */
9333         wrap: function(config, returnDom){
9334             if(!config){
9335                 config = {tag: "div"};
9336             }
9337             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9338             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9339             return newEl;
9340         },
9341
9342         /**
9343          * Replaces the passed element with this element
9344          * @param {String/HTMLElement/Element} el The element to replace
9345          * @return {Roo.Element} this
9346          */
9347         replace: function(el){
9348             el = Roo.get(el);
9349             this.insertBefore(el);
9350             el.remove();
9351             return this;
9352         },
9353
9354         /**
9355          * Inserts an html fragment into this element
9356          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9357          * @param {String} html The HTML fragment
9358          * @param {Boolean} returnEl True to return an Roo.Element
9359          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9360          */
9361         insertHtml : function(where, html, returnEl){
9362             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9363             return returnEl ? Roo.get(el) : el;
9364         },
9365
9366         /**
9367          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9368          * @param {Object} o The object with the attributes
9369          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9370          * @return {Roo.Element} this
9371          */
9372         set : function(o, useSet){
9373             var el = this.dom;
9374             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9375             for(var attr in o){
9376                 if(attr == "style" || typeof o[attr] == "function") continue;
9377                 if(attr=="cls"){
9378                     el.className = o["cls"];
9379                 }else{
9380                     if(useSet) el.setAttribute(attr, o[attr]);
9381                     else el[attr] = o[attr];
9382                 }
9383             }
9384             if(o.style){
9385                 Roo.DomHelper.applyStyles(el, o.style);
9386             }
9387             return this;
9388         },
9389
9390         /**
9391          * Convenience method for constructing a KeyMap
9392          * @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:
9393          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9394          * @param {Function} fn The function to call
9395          * @param {Object} scope (optional) The scope of the function
9396          * @return {Roo.KeyMap} The KeyMap created
9397          */
9398         addKeyListener : function(key, fn, scope){
9399             var config;
9400             if(typeof key != "object" || key instanceof Array){
9401                 config = {
9402                     key: key,
9403                     fn: fn,
9404                     scope: scope
9405                 };
9406             }else{
9407                 config = {
9408                     key : key.key,
9409                     shift : key.shift,
9410                     ctrl : key.ctrl,
9411                     alt : key.alt,
9412                     fn: fn,
9413                     scope: scope
9414                 };
9415             }
9416             return new Roo.KeyMap(this, config);
9417         },
9418
9419         /**
9420          * Creates a KeyMap for this element
9421          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9422          * @return {Roo.KeyMap} The KeyMap created
9423          */
9424         addKeyMap : function(config){
9425             return new Roo.KeyMap(this, config);
9426         },
9427
9428         /**
9429          * Returns true if this element is scrollable.
9430          * @return {Boolean}
9431          */
9432          isScrollable : function(){
9433             var dom = this.dom;
9434             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9435         },
9436
9437         /**
9438          * 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().
9439          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9440          * @param {Number} value The new scroll value
9441          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9442          * @return {Element} this
9443          */
9444
9445         scrollTo : function(side, value, animate){
9446             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9447             if(!animate || !A){
9448                 this.dom[prop] = value;
9449             }else{
9450                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9451                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9452             }
9453             return this;
9454         },
9455
9456         /**
9457          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9458          * within this element's scrollable range.
9459          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9460          * @param {Number} distance How far to scroll the element in pixels
9461          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9462          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9463          * was scrolled as far as it could go.
9464          */
9465          scroll : function(direction, distance, animate){
9466              if(!this.isScrollable()){
9467                  return;
9468              }
9469              var el = this.dom;
9470              var l = el.scrollLeft, t = el.scrollTop;
9471              var w = el.scrollWidth, h = el.scrollHeight;
9472              var cw = el.clientWidth, ch = el.clientHeight;
9473              direction = direction.toLowerCase();
9474              var scrolled = false;
9475              var a = this.preanim(arguments, 2);
9476              switch(direction){
9477                  case "l":
9478                  case "left":
9479                      if(w - l > cw){
9480                          var v = Math.min(l + distance, w-cw);
9481                          this.scrollTo("left", v, a);
9482                          scrolled = true;
9483                      }
9484                      break;
9485                 case "r":
9486                 case "right":
9487                      if(l > 0){
9488                          var v = Math.max(l - distance, 0);
9489                          this.scrollTo("left", v, a);
9490                          scrolled = true;
9491                      }
9492                      break;
9493                 case "t":
9494                 case "top":
9495                 case "up":
9496                      if(t > 0){
9497                          var v = Math.max(t - distance, 0);
9498                          this.scrollTo("top", v, a);
9499                          scrolled = true;
9500                      }
9501                      break;
9502                 case "b":
9503                 case "bottom":
9504                 case "down":
9505                      if(h - t > ch){
9506                          var v = Math.min(t + distance, h-ch);
9507                          this.scrollTo("top", v, a);
9508                          scrolled = true;
9509                      }
9510                      break;
9511              }
9512              return scrolled;
9513         },
9514
9515         /**
9516          * Translates the passed page coordinates into left/top css values for this element
9517          * @param {Number/Array} x The page x or an array containing [x, y]
9518          * @param {Number} y The page y
9519          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9520          */
9521         translatePoints : function(x, y){
9522             if(typeof x == 'object' || x instanceof Array){
9523                 y = x[1]; x = x[0];
9524             }
9525             var p = this.getStyle('position');
9526             var o = this.getXY();
9527
9528             var l = parseInt(this.getStyle('left'), 10);
9529             var t = parseInt(this.getStyle('top'), 10);
9530
9531             if(isNaN(l)){
9532                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9533             }
9534             if(isNaN(t)){
9535                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9536             }
9537
9538             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9539         },
9540
9541         /**
9542          * Returns the current scroll position of the element.
9543          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9544          */
9545         getScroll : function(){
9546             var d = this.dom, doc = document;
9547             if(d == doc || d == doc.body){
9548                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9549                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9550                 return {left: l, top: t};
9551             }else{
9552                 return {left: d.scrollLeft, top: d.scrollTop};
9553             }
9554         },
9555
9556         /**
9557          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9558          * are convert to standard 6 digit hex color.
9559          * @param {String} attr The css attribute
9560          * @param {String} defaultValue The default value to use when a valid color isn't found
9561          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9562          * YUI color anims.
9563          */
9564         getColor : function(attr, defaultValue, prefix){
9565             var v = this.getStyle(attr);
9566             if(!v || v == "transparent" || v == "inherit") {
9567                 return defaultValue;
9568             }
9569             var color = typeof prefix == "undefined" ? "#" : prefix;
9570             if(v.substr(0, 4) == "rgb("){
9571                 var rvs = v.slice(4, v.length -1).split(",");
9572                 for(var i = 0; i < 3; i++){
9573                     var h = parseInt(rvs[i]).toString(16);
9574                     if(h < 16){
9575                         h = "0" + h;
9576                     }
9577                     color += h;
9578                 }
9579             } else {
9580                 if(v.substr(0, 1) == "#"){
9581                     if(v.length == 4) {
9582                         for(var i = 1; i < 4; i++){
9583                             var c = v.charAt(i);
9584                             color +=  c + c;
9585                         }
9586                     }else if(v.length == 7){
9587                         color += v.substr(1);
9588                     }
9589                 }
9590             }
9591             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9592         },
9593
9594         /**
9595          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9596          * gradient background, rounded corners and a 4-way shadow.
9597          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9598          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9599          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9600          * @return {Roo.Element} this
9601          */
9602         boxWrap : function(cls){
9603             cls = cls || 'x-box';
9604             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9605             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9606             return el;
9607         },
9608
9609         /**
9610          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9611          * @param {String} namespace The namespace in which to look for the attribute
9612          * @param {String} name The attribute name
9613          * @return {String} The attribute value
9614          */
9615         getAttributeNS : Roo.isIE ? function(ns, name){
9616             var d = this.dom;
9617             var type = typeof d[ns+":"+name];
9618             if(type != 'undefined' && type != 'unknown'){
9619                 return d[ns+":"+name];
9620             }
9621             return d[name];
9622         } : function(ns, name){
9623             var d = this.dom;
9624             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9625         },
9626         
9627         
9628         /**
9629          * Sets or Returns the value the dom attribute value
9630          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9631          * @param {String} value (optional) The value to set the attribute to
9632          * @return {String} The attribute value
9633          */
9634         attr : function(name){
9635             if (arguments.length > 1) {
9636                 this.dom.setAttribute(name, arguments[1]);
9637                 return arguments[1];
9638             }
9639             if (typeof(name) == 'object') {
9640                 for(var i in name) {
9641                     this.attr(i, name[i]);
9642                 }
9643                 return name;
9644             }
9645             
9646             
9647             if (!this.dom.hasAttribute(name)) {
9648                 return undefined;
9649             }
9650             return this.dom.getAttribute(name);
9651         }
9652         
9653         
9654         
9655     };
9656
9657     var ep = El.prototype;
9658
9659     /**
9660      * Appends an event handler (Shorthand for addListener)
9661      * @param {String}   eventName     The type of event to append
9662      * @param {Function} fn        The method the event invokes
9663      * @param {Object} scope       (optional) The scope (this object) of the fn
9664      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9665      * @method
9666      */
9667     ep.on = ep.addListener;
9668         // backwards compat
9669     ep.mon = ep.addListener;
9670
9671     /**
9672      * Removes an event handler from this element (shorthand for removeListener)
9673      * @param {String} eventName the type of event to remove
9674      * @param {Function} fn the method the event invokes
9675      * @return {Roo.Element} this
9676      * @method
9677      */
9678     ep.un = ep.removeListener;
9679
9680     /**
9681      * true to automatically adjust width and height settings for box-model issues (default to true)
9682      */
9683     ep.autoBoxAdjust = true;
9684
9685     // private
9686     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9687
9688     // private
9689     El.addUnits = function(v, defaultUnit){
9690         if(v === "" || v == "auto"){
9691             return v;
9692         }
9693         if(v === undefined){
9694             return '';
9695         }
9696         if(typeof v == "number" || !El.unitPattern.test(v)){
9697             return v + (defaultUnit || 'px');
9698         }
9699         return v;
9700     };
9701
9702     // special markup used throughout Roo when box wrapping elements
9703     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>';
9704     /**
9705      * Visibility mode constant - Use visibility to hide element
9706      * @static
9707      * @type Number
9708      */
9709     El.VISIBILITY = 1;
9710     /**
9711      * Visibility mode constant - Use display to hide element
9712      * @static
9713      * @type Number
9714      */
9715     El.DISPLAY = 2;
9716
9717     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9718     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9719     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9720
9721
9722
9723     /**
9724      * @private
9725      */
9726     El.cache = {};
9727
9728     var docEl;
9729
9730     /**
9731      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9732      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9733      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9734      * @return {Element} The Element object
9735      * @static
9736      */
9737     El.get = function(el){
9738         var ex, elm, id;
9739         if(!el){ return null; }
9740         if(typeof el == "string"){ // element id
9741             if(!(elm = document.getElementById(el))){
9742                 return null;
9743             }
9744             if(ex = El.cache[el]){
9745                 ex.dom = elm;
9746             }else{
9747                 ex = El.cache[el] = new El(elm);
9748             }
9749             return ex;
9750         }else if(el.tagName){ // dom element
9751             if(!(id = el.id)){
9752                 id = Roo.id(el);
9753             }
9754             if(ex = El.cache[id]){
9755                 ex.dom = el;
9756             }else{
9757                 ex = El.cache[id] = new El(el);
9758             }
9759             return ex;
9760         }else if(el instanceof El){
9761             if(el != docEl){
9762                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9763                                                               // catch case where it hasn't been appended
9764                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9765             }
9766             return el;
9767         }else if(el.isComposite){
9768             return el;
9769         }else if(el instanceof Array){
9770             return El.select(el);
9771         }else if(el == document){
9772             // create a bogus element object representing the document object
9773             if(!docEl){
9774                 var f = function(){};
9775                 f.prototype = El.prototype;
9776                 docEl = new f();
9777                 docEl.dom = document;
9778             }
9779             return docEl;
9780         }
9781         return null;
9782     };
9783
9784     // private
9785     El.uncache = function(el){
9786         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9787             if(a[i]){
9788                 delete El.cache[a[i].id || a[i]];
9789             }
9790         }
9791     };
9792
9793     // private
9794     // Garbage collection - uncache elements/purge listeners on orphaned elements
9795     // so we don't hold a reference and cause the browser to retain them
9796     El.garbageCollect = function(){
9797         if(!Roo.enableGarbageCollector){
9798             clearInterval(El.collectorThread);
9799             return;
9800         }
9801         for(var eid in El.cache){
9802             var el = El.cache[eid], d = el.dom;
9803             // -------------------------------------------------------
9804             // Determining what is garbage:
9805             // -------------------------------------------------------
9806             // !d
9807             // dom node is null, definitely garbage
9808             // -------------------------------------------------------
9809             // !d.parentNode
9810             // no parentNode == direct orphan, definitely garbage
9811             // -------------------------------------------------------
9812             // !d.offsetParent && !document.getElementById(eid)
9813             // display none elements have no offsetParent so we will
9814             // also try to look it up by it's id. However, check
9815             // offsetParent first so we don't do unneeded lookups.
9816             // This enables collection of elements that are not orphans
9817             // directly, but somewhere up the line they have an orphan
9818             // parent.
9819             // -------------------------------------------------------
9820             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9821                 delete El.cache[eid];
9822                 if(d && Roo.enableListenerCollection){
9823                     E.purgeElement(d);
9824                 }
9825             }
9826         }
9827     }
9828     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9829
9830
9831     // dom is optional
9832     El.Flyweight = function(dom){
9833         this.dom = dom;
9834     };
9835     El.Flyweight.prototype = El.prototype;
9836
9837     El._flyweights = {};
9838     /**
9839      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9840      * the dom node can be overwritten by other code.
9841      * @param {String/HTMLElement} el The dom node or id
9842      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9843      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9844      * @static
9845      * @return {Element} The shared Element object
9846      */
9847     El.fly = function(el, named){
9848         named = named || '_global';
9849         el = Roo.getDom(el);
9850         if(!el){
9851             return null;
9852         }
9853         if(!El._flyweights[named]){
9854             El._flyweights[named] = new El.Flyweight();
9855         }
9856         El._flyweights[named].dom = el;
9857         return El._flyweights[named];
9858     };
9859
9860     /**
9861      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9862      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9863      * Shorthand of {@link Roo.Element#get}
9864      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9865      * @return {Element} The Element object
9866      * @member Roo
9867      * @method get
9868      */
9869     Roo.get = El.get;
9870     /**
9871      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9872      * the dom node can be overwritten by other code.
9873      * Shorthand of {@link Roo.Element#fly}
9874      * @param {String/HTMLElement} el The dom node or id
9875      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9876      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9877      * @static
9878      * @return {Element} The shared Element object
9879      * @member Roo
9880      * @method fly
9881      */
9882     Roo.fly = El.fly;
9883
9884     // speedy lookup for elements never to box adjust
9885     var noBoxAdjust = Roo.isStrict ? {
9886         select:1
9887     } : {
9888         input:1, select:1, textarea:1
9889     };
9890     if(Roo.isIE || Roo.isGecko){
9891         noBoxAdjust['button'] = 1;
9892     }
9893
9894
9895     Roo.EventManager.on(window, 'unload', function(){
9896         delete El.cache;
9897         delete El._flyweights;
9898     });
9899 })();
9900
9901
9902
9903
9904 if(Roo.DomQuery){
9905     Roo.Element.selectorFunction = Roo.DomQuery.select;
9906 }
9907
9908 Roo.Element.select = function(selector, unique, root){
9909     var els;
9910     if(typeof selector == "string"){
9911         els = Roo.Element.selectorFunction(selector, root);
9912     }else if(selector.length !== undefined){
9913         els = selector;
9914     }else{
9915         throw "Invalid selector";
9916     }
9917     if(unique === true){
9918         return new Roo.CompositeElement(els);
9919     }else{
9920         return new Roo.CompositeElementLite(els);
9921     }
9922 };
9923 /**
9924  * Selects elements based on the passed CSS selector to enable working on them as 1.
9925  * @param {String/Array} selector The CSS selector or an array of elements
9926  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9927  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9928  * @return {CompositeElementLite/CompositeElement}
9929  * @member Roo
9930  * @method select
9931  */
9932 Roo.select = Roo.Element.select;
9933
9934
9935
9936
9937
9938
9939
9940
9941
9942
9943
9944
9945
9946
9947 /*
9948  * Based on:
9949  * Ext JS Library 1.1.1
9950  * Copyright(c) 2006-2007, Ext JS, LLC.
9951  *
9952  * Originally Released Under LGPL - original licence link has changed is not relivant.
9953  *
9954  * Fork - LGPL
9955  * <script type="text/javascript">
9956  */
9957
9958
9959
9960 //Notifies Element that fx methods are available
9961 Roo.enableFx = true;
9962
9963 /**
9964  * @class Roo.Fx
9965  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9966  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9967  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9968  * Element effects to work.</p><br/>
9969  *
9970  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9971  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9972  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9973  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9974  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9975  * expected results and should be done with care.</p><br/>
9976  *
9977  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9978  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9979 <pre>
9980 Value  Description
9981 -----  -----------------------------
9982 tl     The top left corner
9983 t      The center of the top edge
9984 tr     The top right corner
9985 l      The center of the left edge
9986 r      The center of the right edge
9987 bl     The bottom left corner
9988 b      The center of the bottom edge
9989 br     The bottom right corner
9990 </pre>
9991  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9992  * below are common options that can be passed to any Fx method.</b>
9993  * @cfg {Function} callback A function called when the effect is finished
9994  * @cfg {Object} scope The scope of the effect function
9995  * @cfg {String} easing A valid Easing value for the effect
9996  * @cfg {String} afterCls A css class to apply after the effect
9997  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9998  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9999  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10000  * effects that end with the element being visually hidden, ignored otherwise)
10001  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10002  * a function which returns such a specification that will be applied to the Element after the effect finishes
10003  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10004  * @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
10005  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10006  */
10007 Roo.Fx = {
10008         /**
10009          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10010          * origin for the slide effect.  This function automatically handles wrapping the element with
10011          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10012          * Usage:
10013          *<pre><code>
10014 // default: slide the element in from the top
10015 el.slideIn();
10016
10017 // custom: slide the element in from the right with a 2-second duration
10018 el.slideIn('r', { duration: 2 });
10019
10020 // common config options shown with default values
10021 el.slideIn('t', {
10022     easing: 'easeOut',
10023     duration: .5
10024 });
10025 </code></pre>
10026          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10027          * @param {Object} options (optional) Object literal with any of the Fx config options
10028          * @return {Roo.Element} The Element
10029          */
10030     slideIn : function(anchor, o){
10031         var el = this.getFxEl();
10032         o = o || {};
10033
10034         el.queueFx(o, function(){
10035
10036             anchor = anchor || "t";
10037
10038             // fix display to visibility
10039             this.fixDisplay();
10040
10041             // restore values after effect
10042             var r = this.getFxRestore();
10043             var b = this.getBox();
10044             // fixed size for slide
10045             this.setSize(b);
10046
10047             // wrap if needed
10048             var wrap = this.fxWrap(r.pos, o, "hidden");
10049
10050             var st = this.dom.style;
10051             st.visibility = "visible";
10052             st.position = "absolute";
10053
10054             // clear out temp styles after slide and unwrap
10055             var after = function(){
10056                 el.fxUnwrap(wrap, r.pos, o);
10057                 st.width = r.width;
10058                 st.height = r.height;
10059                 el.afterFx(o);
10060             };
10061             // time to calc the positions
10062             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10063
10064             switch(anchor.toLowerCase()){
10065                 case "t":
10066                     wrap.setSize(b.width, 0);
10067                     st.left = st.bottom = "0";
10068                     a = {height: bh};
10069                 break;
10070                 case "l":
10071                     wrap.setSize(0, b.height);
10072                     st.right = st.top = "0";
10073                     a = {width: bw};
10074                 break;
10075                 case "r":
10076                     wrap.setSize(0, b.height);
10077                     wrap.setX(b.right);
10078                     st.left = st.top = "0";
10079                     a = {width: bw, points: pt};
10080                 break;
10081                 case "b":
10082                     wrap.setSize(b.width, 0);
10083                     wrap.setY(b.bottom);
10084                     st.left = st.top = "0";
10085                     a = {height: bh, points: pt};
10086                 break;
10087                 case "tl":
10088                     wrap.setSize(0, 0);
10089                     st.right = st.bottom = "0";
10090                     a = {width: bw, height: bh};
10091                 break;
10092                 case "bl":
10093                     wrap.setSize(0, 0);
10094                     wrap.setY(b.y+b.height);
10095                     st.right = st.top = "0";
10096                     a = {width: bw, height: bh, points: pt};
10097                 break;
10098                 case "br":
10099                     wrap.setSize(0, 0);
10100                     wrap.setXY([b.right, b.bottom]);
10101                     st.left = st.top = "0";
10102                     a = {width: bw, height: bh, points: pt};
10103                 break;
10104                 case "tr":
10105                     wrap.setSize(0, 0);
10106                     wrap.setX(b.x+b.width);
10107                     st.left = st.bottom = "0";
10108                     a = {width: bw, height: bh, points: pt};
10109                 break;
10110             }
10111             this.dom.style.visibility = "visible";
10112             wrap.show();
10113
10114             arguments.callee.anim = wrap.fxanim(a,
10115                 o,
10116                 'motion',
10117                 .5,
10118                 'easeOut', after);
10119         });
10120         return this;
10121     },
10122     
10123         /**
10124          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10125          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10126          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10127          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10128          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10129          * Usage:
10130          *<pre><code>
10131 // default: slide the element out to the top
10132 el.slideOut();
10133
10134 // custom: slide the element out to the right with a 2-second duration
10135 el.slideOut('r', { duration: 2 });
10136
10137 // common config options shown with default values
10138 el.slideOut('t', {
10139     easing: 'easeOut',
10140     duration: .5,
10141     remove: false,
10142     useDisplay: false
10143 });
10144 </code></pre>
10145          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10146          * @param {Object} options (optional) Object literal with any of the Fx config options
10147          * @return {Roo.Element} The Element
10148          */
10149     slideOut : function(anchor, o){
10150         var el = this.getFxEl();
10151         o = o || {};
10152
10153         el.queueFx(o, function(){
10154
10155             anchor = anchor || "t";
10156
10157             // restore values after effect
10158             var r = this.getFxRestore();
10159             
10160             var b = this.getBox();
10161             // fixed size for slide
10162             this.setSize(b);
10163
10164             // wrap if needed
10165             var wrap = this.fxWrap(r.pos, o, "visible");
10166
10167             var st = this.dom.style;
10168             st.visibility = "visible";
10169             st.position = "absolute";
10170
10171             wrap.setSize(b);
10172
10173             var after = function(){
10174                 if(o.useDisplay){
10175                     el.setDisplayed(false);
10176                 }else{
10177                     el.hide();
10178                 }
10179
10180                 el.fxUnwrap(wrap, r.pos, o);
10181
10182                 st.width = r.width;
10183                 st.height = r.height;
10184
10185                 el.afterFx(o);
10186             };
10187
10188             var a, zero = {to: 0};
10189             switch(anchor.toLowerCase()){
10190                 case "t":
10191                     st.left = st.bottom = "0";
10192                     a = {height: zero};
10193                 break;
10194                 case "l":
10195                     st.right = st.top = "0";
10196                     a = {width: zero};
10197                 break;
10198                 case "r":
10199                     st.left = st.top = "0";
10200                     a = {width: zero, points: {to:[b.right, b.y]}};
10201                 break;
10202                 case "b":
10203                     st.left = st.top = "0";
10204                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10205                 break;
10206                 case "tl":
10207                     st.right = st.bottom = "0";
10208                     a = {width: zero, height: zero};
10209                 break;
10210                 case "bl":
10211                     st.right = st.top = "0";
10212                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10213                 break;
10214                 case "br":
10215                     st.left = st.top = "0";
10216                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10217                 break;
10218                 case "tr":
10219                     st.left = st.bottom = "0";
10220                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10221                 break;
10222             }
10223
10224             arguments.callee.anim = wrap.fxanim(a,
10225                 o,
10226                 'motion',
10227                 .5,
10228                 "easeOut", after);
10229         });
10230         return this;
10231     },
10232
10233         /**
10234          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10235          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10236          * The element must be removed from the DOM using the 'remove' config option if desired.
10237          * Usage:
10238          *<pre><code>
10239 // default
10240 el.puff();
10241
10242 // common config options shown with default values
10243 el.puff({
10244     easing: 'easeOut',
10245     duration: .5,
10246     remove: false,
10247     useDisplay: false
10248 });
10249 </code></pre>
10250          * @param {Object} options (optional) Object literal with any of the Fx config options
10251          * @return {Roo.Element} The Element
10252          */
10253     puff : function(o){
10254         var el = this.getFxEl();
10255         o = o || {};
10256
10257         el.queueFx(o, function(){
10258             this.clearOpacity();
10259             this.show();
10260
10261             // restore values after effect
10262             var r = this.getFxRestore();
10263             var st = this.dom.style;
10264
10265             var after = function(){
10266                 if(o.useDisplay){
10267                     el.setDisplayed(false);
10268                 }else{
10269                     el.hide();
10270                 }
10271
10272                 el.clearOpacity();
10273
10274                 el.setPositioning(r.pos);
10275                 st.width = r.width;
10276                 st.height = r.height;
10277                 st.fontSize = '';
10278                 el.afterFx(o);
10279             };
10280
10281             var width = this.getWidth();
10282             var height = this.getHeight();
10283
10284             arguments.callee.anim = this.fxanim({
10285                     width : {to: this.adjustWidth(width * 2)},
10286                     height : {to: this.adjustHeight(height * 2)},
10287                     points : {by: [-(width * .5), -(height * .5)]},
10288                     opacity : {to: 0},
10289                     fontSize: {to:200, unit: "%"}
10290                 },
10291                 o,
10292                 'motion',
10293                 .5,
10294                 "easeOut", after);
10295         });
10296         return this;
10297     },
10298
10299         /**
10300          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10301          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10302          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10303          * Usage:
10304          *<pre><code>
10305 // default
10306 el.switchOff();
10307
10308 // all config options shown with default values
10309 el.switchOff({
10310     easing: 'easeIn',
10311     duration: .3,
10312     remove: false,
10313     useDisplay: false
10314 });
10315 </code></pre>
10316          * @param {Object} options (optional) Object literal with any of the Fx config options
10317          * @return {Roo.Element} The Element
10318          */
10319     switchOff : function(o){
10320         var el = this.getFxEl();
10321         o = o || {};
10322
10323         el.queueFx(o, function(){
10324             this.clearOpacity();
10325             this.clip();
10326
10327             // restore values after effect
10328             var r = this.getFxRestore();
10329             var st = this.dom.style;
10330
10331             var after = function(){
10332                 if(o.useDisplay){
10333                     el.setDisplayed(false);
10334                 }else{
10335                     el.hide();
10336                 }
10337
10338                 el.clearOpacity();
10339                 el.setPositioning(r.pos);
10340                 st.width = r.width;
10341                 st.height = r.height;
10342
10343                 el.afterFx(o);
10344             };
10345
10346             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10347                 this.clearOpacity();
10348                 (function(){
10349                     this.fxanim({
10350                         height:{to:1},
10351                         points:{by:[0, this.getHeight() * .5]}
10352                     }, o, 'motion', 0.3, 'easeIn', after);
10353                 }).defer(100, this);
10354             });
10355         });
10356         return this;
10357     },
10358
10359     /**
10360      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10361      * changed using the "attr" config option) and then fading back to the original color. If no original
10362      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10363      * Usage:
10364 <pre><code>
10365 // default: highlight background to yellow
10366 el.highlight();
10367
10368 // custom: highlight foreground text to blue for 2 seconds
10369 el.highlight("0000ff", { attr: 'color', duration: 2 });
10370
10371 // common config options shown with default values
10372 el.highlight("ffff9c", {
10373     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10374     endColor: (current color) or "ffffff",
10375     easing: 'easeIn',
10376     duration: 1
10377 });
10378 </code></pre>
10379      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10380      * @param {Object} options (optional) Object literal with any of the Fx config options
10381      * @return {Roo.Element} The Element
10382      */ 
10383     highlight : function(color, o){
10384         var el = this.getFxEl();
10385         o = o || {};
10386
10387         el.queueFx(o, function(){
10388             color = color || "ffff9c";
10389             attr = o.attr || "backgroundColor";
10390
10391             this.clearOpacity();
10392             this.show();
10393
10394             var origColor = this.getColor(attr);
10395             var restoreColor = this.dom.style[attr];
10396             endColor = (o.endColor || origColor) || "ffffff";
10397
10398             var after = function(){
10399                 el.dom.style[attr] = restoreColor;
10400                 el.afterFx(o);
10401             };
10402
10403             var a = {};
10404             a[attr] = {from: color, to: endColor};
10405             arguments.callee.anim = this.fxanim(a,
10406                 o,
10407                 'color',
10408                 1,
10409                 'easeIn', after);
10410         });
10411         return this;
10412     },
10413
10414    /**
10415     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10416     * Usage:
10417 <pre><code>
10418 // default: a single light blue ripple
10419 el.frame();
10420
10421 // custom: 3 red ripples lasting 3 seconds total
10422 el.frame("ff0000", 3, { duration: 3 });
10423
10424 // common config options shown with default values
10425 el.frame("C3DAF9", 1, {
10426     duration: 1 //duration of entire animation (not each individual ripple)
10427     // Note: Easing is not configurable and will be ignored if included
10428 });
10429 </code></pre>
10430     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10431     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10432     * @param {Object} options (optional) Object literal with any of the Fx config options
10433     * @return {Roo.Element} The Element
10434     */
10435     frame : function(color, count, o){
10436         var el = this.getFxEl();
10437         o = o || {};
10438
10439         el.queueFx(o, function(){
10440             color = color || "#C3DAF9";
10441             if(color.length == 6){
10442                 color = "#" + color;
10443             }
10444             count = count || 1;
10445             duration = o.duration || 1;
10446             this.show();
10447
10448             var b = this.getBox();
10449             var animFn = function(){
10450                 var proxy = this.createProxy({
10451
10452                      style:{
10453                         visbility:"hidden",
10454                         position:"absolute",
10455                         "z-index":"35000", // yee haw
10456                         border:"0px solid " + color
10457                      }
10458                   });
10459                 var scale = Roo.isBorderBox ? 2 : 1;
10460                 proxy.animate({
10461                     top:{from:b.y, to:b.y - 20},
10462                     left:{from:b.x, to:b.x - 20},
10463                     borderWidth:{from:0, to:10},
10464                     opacity:{from:1, to:0},
10465                     height:{from:b.height, to:(b.height + (20*scale))},
10466                     width:{from:b.width, to:(b.width + (20*scale))}
10467                 }, duration, function(){
10468                     proxy.remove();
10469                 });
10470                 if(--count > 0){
10471                      animFn.defer((duration/2)*1000, this);
10472                 }else{
10473                     el.afterFx(o);
10474                 }
10475             };
10476             animFn.call(this);
10477         });
10478         return this;
10479     },
10480
10481    /**
10482     * Creates a pause before any subsequent queued effects begin.  If there are
10483     * no effects queued after the pause it will have no effect.
10484     * Usage:
10485 <pre><code>
10486 el.pause(1);
10487 </code></pre>
10488     * @param {Number} seconds The length of time to pause (in seconds)
10489     * @return {Roo.Element} The Element
10490     */
10491     pause : function(seconds){
10492         var el = this.getFxEl();
10493         var o = {};
10494
10495         el.queueFx(o, function(){
10496             setTimeout(function(){
10497                 el.afterFx(o);
10498             }, seconds * 1000);
10499         });
10500         return this;
10501     },
10502
10503    /**
10504     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10505     * using the "endOpacity" config option.
10506     * Usage:
10507 <pre><code>
10508 // default: fade in from opacity 0 to 100%
10509 el.fadeIn();
10510
10511 // custom: fade in from opacity 0 to 75% over 2 seconds
10512 el.fadeIn({ endOpacity: .75, duration: 2});
10513
10514 // common config options shown with default values
10515 el.fadeIn({
10516     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10517     easing: 'easeOut',
10518     duration: .5
10519 });
10520 </code></pre>
10521     * @param {Object} options (optional) Object literal with any of the Fx config options
10522     * @return {Roo.Element} The Element
10523     */
10524     fadeIn : function(o){
10525         var el = this.getFxEl();
10526         o = o || {};
10527         el.queueFx(o, function(){
10528             this.setOpacity(0);
10529             this.fixDisplay();
10530             this.dom.style.visibility = 'visible';
10531             var to = o.endOpacity || 1;
10532             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10533                 o, null, .5, "easeOut", function(){
10534                 if(to == 1){
10535                     this.clearOpacity();
10536                 }
10537                 el.afterFx(o);
10538             });
10539         });
10540         return this;
10541     },
10542
10543    /**
10544     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10545     * using the "endOpacity" config option.
10546     * Usage:
10547 <pre><code>
10548 // default: fade out from the element's current opacity to 0
10549 el.fadeOut();
10550
10551 // custom: fade out from the element's current opacity to 25% over 2 seconds
10552 el.fadeOut({ endOpacity: .25, duration: 2});
10553
10554 // common config options shown with default values
10555 el.fadeOut({
10556     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10557     easing: 'easeOut',
10558     duration: .5
10559     remove: false,
10560     useDisplay: false
10561 });
10562 </code></pre>
10563     * @param {Object} options (optional) Object literal with any of the Fx config options
10564     * @return {Roo.Element} The Element
10565     */
10566     fadeOut : function(o){
10567         var el = this.getFxEl();
10568         o = o || {};
10569         el.queueFx(o, function(){
10570             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10571                 o, null, .5, "easeOut", function(){
10572                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10573                      this.dom.style.display = "none";
10574                 }else{
10575                      this.dom.style.visibility = "hidden";
10576                 }
10577                 this.clearOpacity();
10578                 el.afterFx(o);
10579             });
10580         });
10581         return this;
10582     },
10583
10584    /**
10585     * Animates the transition of an element's dimensions from a starting height/width
10586     * to an ending height/width.
10587     * Usage:
10588 <pre><code>
10589 // change height and width to 100x100 pixels
10590 el.scale(100, 100);
10591
10592 // common config options shown with default values.  The height and width will default to
10593 // the element's existing values if passed as null.
10594 el.scale(
10595     [element's width],
10596     [element's height], {
10597     easing: 'easeOut',
10598     duration: .35
10599 });
10600 </code></pre>
10601     * @param {Number} width  The new width (pass undefined to keep the original width)
10602     * @param {Number} height  The new height (pass undefined to keep the original height)
10603     * @param {Object} options (optional) Object literal with any of the Fx config options
10604     * @return {Roo.Element} The Element
10605     */
10606     scale : function(w, h, o){
10607         this.shift(Roo.apply({}, o, {
10608             width: w,
10609             height: h
10610         }));
10611         return this;
10612     },
10613
10614    /**
10615     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10616     * Any of these properties not specified in the config object will not be changed.  This effect 
10617     * requires that at least one new dimension, position or opacity setting must be passed in on
10618     * the config object in order for the function to have any effect.
10619     * Usage:
10620 <pre><code>
10621 // slide the element horizontally to x position 200 while changing the height and opacity
10622 el.shift({ x: 200, height: 50, opacity: .8 });
10623
10624 // common config options shown with default values.
10625 el.shift({
10626     width: [element's width],
10627     height: [element's height],
10628     x: [element's x position],
10629     y: [element's y position],
10630     opacity: [element's opacity],
10631     easing: 'easeOut',
10632     duration: .35
10633 });
10634 </code></pre>
10635     * @param {Object} options  Object literal with any of the Fx config options
10636     * @return {Roo.Element} The Element
10637     */
10638     shift : function(o){
10639         var el = this.getFxEl();
10640         o = o || {};
10641         el.queueFx(o, function(){
10642             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10643             if(w !== undefined){
10644                 a.width = {to: this.adjustWidth(w)};
10645             }
10646             if(h !== undefined){
10647                 a.height = {to: this.adjustHeight(h)};
10648             }
10649             if(x !== undefined || y !== undefined){
10650                 a.points = {to: [
10651                     x !== undefined ? x : this.getX(),
10652                     y !== undefined ? y : this.getY()
10653                 ]};
10654             }
10655             if(op !== undefined){
10656                 a.opacity = {to: op};
10657             }
10658             if(o.xy !== undefined){
10659                 a.points = {to: o.xy};
10660             }
10661             arguments.callee.anim = this.fxanim(a,
10662                 o, 'motion', .35, "easeOut", function(){
10663                 el.afterFx(o);
10664             });
10665         });
10666         return this;
10667     },
10668
10669         /**
10670          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10671          * ending point of the effect.
10672          * Usage:
10673          *<pre><code>
10674 // default: slide the element downward while fading out
10675 el.ghost();
10676
10677 // custom: slide the element out to the right with a 2-second duration
10678 el.ghost('r', { duration: 2 });
10679
10680 // common config options shown with default values
10681 el.ghost('b', {
10682     easing: 'easeOut',
10683     duration: .5
10684     remove: false,
10685     useDisplay: false
10686 });
10687 </code></pre>
10688          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10689          * @param {Object} options (optional) Object literal with any of the Fx config options
10690          * @return {Roo.Element} The Element
10691          */
10692     ghost : function(anchor, o){
10693         var el = this.getFxEl();
10694         o = o || {};
10695
10696         el.queueFx(o, function(){
10697             anchor = anchor || "b";
10698
10699             // restore values after effect
10700             var r = this.getFxRestore();
10701             var w = this.getWidth(),
10702                 h = this.getHeight();
10703
10704             var st = this.dom.style;
10705
10706             var after = function(){
10707                 if(o.useDisplay){
10708                     el.setDisplayed(false);
10709                 }else{
10710                     el.hide();
10711                 }
10712
10713                 el.clearOpacity();
10714                 el.setPositioning(r.pos);
10715                 st.width = r.width;
10716                 st.height = r.height;
10717
10718                 el.afterFx(o);
10719             };
10720
10721             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10722             switch(anchor.toLowerCase()){
10723                 case "t":
10724                     pt.by = [0, -h];
10725                 break;
10726                 case "l":
10727                     pt.by = [-w, 0];
10728                 break;
10729                 case "r":
10730                     pt.by = [w, 0];
10731                 break;
10732                 case "b":
10733                     pt.by = [0, h];
10734                 break;
10735                 case "tl":
10736                     pt.by = [-w, -h];
10737                 break;
10738                 case "bl":
10739                     pt.by = [-w, h];
10740                 break;
10741                 case "br":
10742                     pt.by = [w, h];
10743                 break;
10744                 case "tr":
10745                     pt.by = [w, -h];
10746                 break;
10747             }
10748
10749             arguments.callee.anim = this.fxanim(a,
10750                 o,
10751                 'motion',
10752                 .5,
10753                 "easeOut", after);
10754         });
10755         return this;
10756     },
10757
10758         /**
10759          * Ensures that all effects queued after syncFx is called on the element are
10760          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10761          * @return {Roo.Element} The Element
10762          */
10763     syncFx : function(){
10764         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10765             block : false,
10766             concurrent : true,
10767             stopFx : false
10768         });
10769         return this;
10770     },
10771
10772         /**
10773          * Ensures that all effects queued after sequenceFx is called on the element are
10774          * run in sequence.  This is the opposite of {@link #syncFx}.
10775          * @return {Roo.Element} The Element
10776          */
10777     sequenceFx : function(){
10778         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10779             block : false,
10780             concurrent : false,
10781             stopFx : false
10782         });
10783         return this;
10784     },
10785
10786         /* @private */
10787     nextFx : function(){
10788         var ef = this.fxQueue[0];
10789         if(ef){
10790             ef.call(this);
10791         }
10792     },
10793
10794         /**
10795          * Returns true if the element has any effects actively running or queued, else returns false.
10796          * @return {Boolean} True if element has active effects, else false
10797          */
10798     hasActiveFx : function(){
10799         return this.fxQueue && this.fxQueue[0];
10800     },
10801
10802         /**
10803          * Stops any running effects and clears the element's internal effects queue if it contains
10804          * any additional effects that haven't started yet.
10805          * @return {Roo.Element} The Element
10806          */
10807     stopFx : function(){
10808         if(this.hasActiveFx()){
10809             var cur = this.fxQueue[0];
10810             if(cur && cur.anim && cur.anim.isAnimated()){
10811                 this.fxQueue = [cur]; // clear out others
10812                 cur.anim.stop(true);
10813             }
10814         }
10815         return this;
10816     },
10817
10818         /* @private */
10819     beforeFx : function(o){
10820         if(this.hasActiveFx() && !o.concurrent){
10821            if(o.stopFx){
10822                this.stopFx();
10823                return true;
10824            }
10825            return false;
10826         }
10827         return true;
10828     },
10829
10830         /**
10831          * Returns true if the element is currently blocking so that no other effect can be queued
10832          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10833          * used to ensure that an effect initiated by a user action runs to completion prior to the
10834          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10835          * @return {Boolean} True if blocking, else false
10836          */
10837     hasFxBlock : function(){
10838         var q = this.fxQueue;
10839         return q && q[0] && q[0].block;
10840     },
10841
10842         /* @private */
10843     queueFx : function(o, fn){
10844         if(!this.fxQueue){
10845             this.fxQueue = [];
10846         }
10847         if(!this.hasFxBlock()){
10848             Roo.applyIf(o, this.fxDefaults);
10849             if(!o.concurrent){
10850                 var run = this.beforeFx(o);
10851                 fn.block = o.block;
10852                 this.fxQueue.push(fn);
10853                 if(run){
10854                     this.nextFx();
10855                 }
10856             }else{
10857                 fn.call(this);
10858             }
10859         }
10860         return this;
10861     },
10862
10863         /* @private */
10864     fxWrap : function(pos, o, vis){
10865         var wrap;
10866         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10867             var wrapXY;
10868             if(o.fixPosition){
10869                 wrapXY = this.getXY();
10870             }
10871             var div = document.createElement("div");
10872             div.style.visibility = vis;
10873             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10874             wrap.setPositioning(pos);
10875             if(wrap.getStyle("position") == "static"){
10876                 wrap.position("relative");
10877             }
10878             this.clearPositioning('auto');
10879             wrap.clip();
10880             wrap.dom.appendChild(this.dom);
10881             if(wrapXY){
10882                 wrap.setXY(wrapXY);
10883             }
10884         }
10885         return wrap;
10886     },
10887
10888         /* @private */
10889     fxUnwrap : function(wrap, pos, o){
10890         this.clearPositioning();
10891         this.setPositioning(pos);
10892         if(!o.wrap){
10893             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10894             wrap.remove();
10895         }
10896     },
10897
10898         /* @private */
10899     getFxRestore : function(){
10900         var st = this.dom.style;
10901         return {pos: this.getPositioning(), width: st.width, height : st.height};
10902     },
10903
10904         /* @private */
10905     afterFx : function(o){
10906         if(o.afterStyle){
10907             this.applyStyles(o.afterStyle);
10908         }
10909         if(o.afterCls){
10910             this.addClass(o.afterCls);
10911         }
10912         if(o.remove === true){
10913             this.remove();
10914         }
10915         Roo.callback(o.callback, o.scope, [this]);
10916         if(!o.concurrent){
10917             this.fxQueue.shift();
10918             this.nextFx();
10919         }
10920     },
10921
10922         /* @private */
10923     getFxEl : function(){ // support for composite element fx
10924         return Roo.get(this.dom);
10925     },
10926
10927         /* @private */
10928     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10929         animType = animType || 'run';
10930         opt = opt || {};
10931         var anim = Roo.lib.Anim[animType](
10932             this.dom, args,
10933             (opt.duration || defaultDur) || .35,
10934             (opt.easing || defaultEase) || 'easeOut',
10935             function(){
10936                 Roo.callback(cb, this);
10937             },
10938             this
10939         );
10940         opt.anim = anim;
10941         return anim;
10942     }
10943 };
10944
10945 // backwords compat
10946 Roo.Fx.resize = Roo.Fx.scale;
10947
10948 //When included, Roo.Fx is automatically applied to Element so that all basic
10949 //effects are available directly via the Element API
10950 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10951  * Based on:
10952  * Ext JS Library 1.1.1
10953  * Copyright(c) 2006-2007, Ext JS, LLC.
10954  *
10955  * Originally Released Under LGPL - original licence link has changed is not relivant.
10956  *
10957  * Fork - LGPL
10958  * <script type="text/javascript">
10959  */
10960
10961
10962 /**
10963  * @class Roo.CompositeElement
10964  * Standard composite class. Creates a Roo.Element for every element in the collection.
10965  * <br><br>
10966  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10967  * actions will be performed on all the elements in this collection.</b>
10968  * <br><br>
10969  * All methods return <i>this</i> and can be chained.
10970  <pre><code>
10971  var els = Roo.select("#some-el div.some-class", true);
10972  // or select directly from an existing element
10973  var el = Roo.get('some-el');
10974  el.select('div.some-class', true);
10975
10976  els.setWidth(100); // all elements become 100 width
10977  els.hide(true); // all elements fade out and hide
10978  // or
10979  els.setWidth(100).hide(true);
10980  </code></pre>
10981  */
10982 Roo.CompositeElement = function(els){
10983     this.elements = [];
10984     this.addElements(els);
10985 };
10986 Roo.CompositeElement.prototype = {
10987     isComposite: true,
10988     addElements : function(els){
10989         if(!els) return this;
10990         if(typeof els == "string"){
10991             els = Roo.Element.selectorFunction(els);
10992         }
10993         var yels = this.elements;
10994         var index = yels.length-1;
10995         for(var i = 0, len = els.length; i < len; i++) {
10996                 yels[++index] = Roo.get(els[i]);
10997         }
10998         return this;
10999     },
11000
11001     /**
11002     * Clears this composite and adds the elements returned by the passed selector.
11003     * @param {String/Array} els A string CSS selector, an array of elements or an element
11004     * @return {CompositeElement} this
11005     */
11006     fill : function(els){
11007         this.elements = [];
11008         this.add(els);
11009         return this;
11010     },
11011
11012     /**
11013     * Filters this composite to only elements that match the passed selector.
11014     * @param {String} selector A string CSS selector
11015     * @param {Boolean} inverse return inverse filter (not matches)
11016     * @return {CompositeElement} this
11017     */
11018     filter : function(selector, inverse){
11019         var els = [];
11020         inverse = inverse || false;
11021         this.each(function(el){
11022             var match = inverse ? !el.is(selector) : el.is(selector);
11023             if(match){
11024                 els[els.length] = el.dom;
11025             }
11026         });
11027         this.fill(els);
11028         return this;
11029     },
11030
11031     invoke : function(fn, args){
11032         var els = this.elements;
11033         for(var i = 0, len = els.length; i < len; i++) {
11034                 Roo.Element.prototype[fn].apply(els[i], args);
11035         }
11036         return this;
11037     },
11038     /**
11039     * Adds elements to this composite.
11040     * @param {String/Array} els A string CSS selector, an array of elements or an element
11041     * @return {CompositeElement} this
11042     */
11043     add : function(els){
11044         if(typeof els == "string"){
11045             this.addElements(Roo.Element.selectorFunction(els));
11046         }else if(els.length !== undefined){
11047             this.addElements(els);
11048         }else{
11049             this.addElements([els]);
11050         }
11051         return this;
11052     },
11053     /**
11054     * Calls the passed function passing (el, this, index) for each element in this composite.
11055     * @param {Function} fn The function to call
11056     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11057     * @return {CompositeElement} this
11058     */
11059     each : function(fn, scope){
11060         var els = this.elements;
11061         for(var i = 0, len = els.length; i < len; i++){
11062             if(fn.call(scope || els[i], els[i], this, i) === false) {
11063                 break;
11064             }
11065         }
11066         return this;
11067     },
11068
11069     /**
11070      * Returns the Element object at the specified index
11071      * @param {Number} index
11072      * @return {Roo.Element}
11073      */
11074     item : function(index){
11075         return this.elements[index] || null;
11076     },
11077
11078     /**
11079      * Returns the first Element
11080      * @return {Roo.Element}
11081      */
11082     first : function(){
11083         return this.item(0);
11084     },
11085
11086     /**
11087      * Returns the last Element
11088      * @return {Roo.Element}
11089      */
11090     last : function(){
11091         return this.item(this.elements.length-1);
11092     },
11093
11094     /**
11095      * Returns the number of elements in this composite
11096      * @return Number
11097      */
11098     getCount : function(){
11099         return this.elements.length;
11100     },
11101
11102     /**
11103      * Returns true if this composite contains the passed element
11104      * @return Boolean
11105      */
11106     contains : function(el){
11107         return this.indexOf(el) !== -1;
11108     },
11109
11110     /**
11111      * Returns true if this composite contains the passed element
11112      * @return Boolean
11113      */
11114     indexOf : function(el){
11115         return this.elements.indexOf(Roo.get(el));
11116     },
11117
11118
11119     /**
11120     * Removes the specified element(s).
11121     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11122     * or an array of any of those.
11123     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11124     * @return {CompositeElement} this
11125     */
11126     removeElement : function(el, removeDom){
11127         if(el instanceof Array){
11128             for(var i = 0, len = el.length; i < len; i++){
11129                 this.removeElement(el[i]);
11130             }
11131             return this;
11132         }
11133         var index = typeof el == 'number' ? el : this.indexOf(el);
11134         if(index !== -1){
11135             if(removeDom){
11136                 var d = this.elements[index];
11137                 if(d.dom){
11138                     d.remove();
11139                 }else{
11140                     d.parentNode.removeChild(d);
11141                 }
11142             }
11143             this.elements.splice(index, 1);
11144         }
11145         return this;
11146     },
11147
11148     /**
11149     * Replaces the specified element with the passed element.
11150     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11151     * to replace.
11152     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11153     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11154     * @return {CompositeElement} this
11155     */
11156     replaceElement : function(el, replacement, domReplace){
11157         var index = typeof el == 'number' ? el : this.indexOf(el);
11158         if(index !== -1){
11159             if(domReplace){
11160                 this.elements[index].replaceWith(replacement);
11161             }else{
11162                 this.elements.splice(index, 1, Roo.get(replacement))
11163             }
11164         }
11165         return this;
11166     },
11167
11168     /**
11169      * Removes all elements.
11170      */
11171     clear : function(){
11172         this.elements = [];
11173     }
11174 };
11175 (function(){
11176     Roo.CompositeElement.createCall = function(proto, fnName){
11177         if(!proto[fnName]){
11178             proto[fnName] = function(){
11179                 return this.invoke(fnName, arguments);
11180             };
11181         }
11182     };
11183     for(var fnName in Roo.Element.prototype){
11184         if(typeof Roo.Element.prototype[fnName] == "function"){
11185             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11186         }
11187     };
11188 })();
11189 /*
11190  * Based on:
11191  * Ext JS Library 1.1.1
11192  * Copyright(c) 2006-2007, Ext JS, LLC.
11193  *
11194  * Originally Released Under LGPL - original licence link has changed is not relivant.
11195  *
11196  * Fork - LGPL
11197  * <script type="text/javascript">
11198  */
11199
11200 /**
11201  * @class Roo.CompositeElementLite
11202  * @extends Roo.CompositeElement
11203  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11204  <pre><code>
11205  var els = Roo.select("#some-el div.some-class");
11206  // or select directly from an existing element
11207  var el = Roo.get('some-el');
11208  el.select('div.some-class');
11209
11210  els.setWidth(100); // all elements become 100 width
11211  els.hide(true); // all elements fade out and hide
11212  // or
11213  els.setWidth(100).hide(true);
11214  </code></pre><br><br>
11215  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11216  * actions will be performed on all the elements in this collection.</b>
11217  */
11218 Roo.CompositeElementLite = function(els){
11219     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11220     this.el = new Roo.Element.Flyweight();
11221 };
11222 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11223     addElements : function(els){
11224         if(els){
11225             if(els instanceof Array){
11226                 this.elements = this.elements.concat(els);
11227             }else{
11228                 var yels = this.elements;
11229                 var index = yels.length-1;
11230                 for(var i = 0, len = els.length; i < len; i++) {
11231                     yels[++index] = els[i];
11232                 }
11233             }
11234         }
11235         return this;
11236     },
11237     invoke : function(fn, args){
11238         var els = this.elements;
11239         var el = this.el;
11240         for(var i = 0, len = els.length; i < len; i++) {
11241             el.dom = els[i];
11242                 Roo.Element.prototype[fn].apply(el, args);
11243         }
11244         return this;
11245     },
11246     /**
11247      * Returns a flyweight Element of the dom element object at the specified index
11248      * @param {Number} index
11249      * @return {Roo.Element}
11250      */
11251     item : function(index){
11252         if(!this.elements[index]){
11253             return null;
11254         }
11255         this.el.dom = this.elements[index];
11256         return this.el;
11257     },
11258
11259     // fixes scope with flyweight
11260     addListener : function(eventName, handler, scope, opt){
11261         var els = this.elements;
11262         for(var i = 0, len = els.length; i < len; i++) {
11263             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11264         }
11265         return this;
11266     },
11267
11268     /**
11269     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11270     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11271     * a reference to the dom node, use el.dom.</b>
11272     * @param {Function} fn The function to call
11273     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11274     * @return {CompositeElement} this
11275     */
11276     each : function(fn, scope){
11277         var els = this.elements;
11278         var el = this.el;
11279         for(var i = 0, len = els.length; i < len; i++){
11280             el.dom = els[i];
11281                 if(fn.call(scope || el, el, this, i) === false){
11282                 break;
11283             }
11284         }
11285         return this;
11286     },
11287
11288     indexOf : function(el){
11289         return this.elements.indexOf(Roo.getDom(el));
11290     },
11291
11292     replaceElement : function(el, replacement, domReplace){
11293         var index = typeof el == 'number' ? el : this.indexOf(el);
11294         if(index !== -1){
11295             replacement = Roo.getDom(replacement);
11296             if(domReplace){
11297                 var d = this.elements[index];
11298                 d.parentNode.insertBefore(replacement, d);
11299                 d.parentNode.removeChild(d);
11300             }
11301             this.elements.splice(index, 1, replacement);
11302         }
11303         return this;
11304     }
11305 });
11306 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11307
11308 /*
11309  * Based on:
11310  * Ext JS Library 1.1.1
11311  * Copyright(c) 2006-2007, Ext JS, LLC.
11312  *
11313  * Originally Released Under LGPL - original licence link has changed is not relivant.
11314  *
11315  * Fork - LGPL
11316  * <script type="text/javascript">
11317  */
11318
11319  
11320
11321 /**
11322  * @class Roo.data.Connection
11323  * @extends Roo.util.Observable
11324  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11325  * either to a configured URL, or to a URL specified at request time.<br><br>
11326  * <p>
11327  * Requests made by this class are asynchronous, and will return immediately. No data from
11328  * the server will be available to the statement immediately following the {@link #request} call.
11329  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11330  * <p>
11331  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11332  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11333  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11334  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11335  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11336  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11337  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11338  * standard DOM methods.
11339  * @constructor
11340  * @param {Object} config a configuration object.
11341  */
11342 Roo.data.Connection = function(config){
11343     Roo.apply(this, config);
11344     this.addEvents({
11345         /**
11346          * @event beforerequest
11347          * Fires before a network request is made to retrieve a data object.
11348          * @param {Connection} conn This Connection object.
11349          * @param {Object} options The options config object passed to the {@link #request} method.
11350          */
11351         "beforerequest" : true,
11352         /**
11353          * @event requestcomplete
11354          * Fires if the request was successfully completed.
11355          * @param {Connection} conn This Connection object.
11356          * @param {Object} response The XHR object containing the response data.
11357          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11358          * @param {Object} options The options config object passed to the {@link #request} method.
11359          */
11360         "requestcomplete" : true,
11361         /**
11362          * @event requestexception
11363          * Fires if an error HTTP status was returned from the server.
11364          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11365          * @param {Connection} conn This Connection object.
11366          * @param {Object} response The XHR object containing the response data.
11367          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11368          * @param {Object} options The options config object passed to the {@link #request} method.
11369          */
11370         "requestexception" : true
11371     });
11372     Roo.data.Connection.superclass.constructor.call(this);
11373 };
11374
11375 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11376     /**
11377      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11378      */
11379     /**
11380      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11381      * extra parameters to each request made by this object. (defaults to undefined)
11382      */
11383     /**
11384      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11385      *  to each request made by this object. (defaults to undefined)
11386      */
11387     /**
11388      * @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)
11389      */
11390     /**
11391      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11392      */
11393     timeout : 30000,
11394     /**
11395      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11396      * @type Boolean
11397      */
11398     autoAbort:false,
11399
11400     /**
11401      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11402      * @type Boolean
11403      */
11404     disableCaching: true,
11405
11406     /**
11407      * Sends an HTTP request to a remote server.
11408      * @param {Object} options An object which may contain the following properties:<ul>
11409      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11410      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11411      * request, a url encoded string or a function to call to get either.</li>
11412      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11413      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11414      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11415      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11416      * <li>options {Object} The parameter to the request call.</li>
11417      * <li>success {Boolean} True if the request succeeded.</li>
11418      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11419      * </ul></li>
11420      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11421      * The callback is passed the following parameters:<ul>
11422      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11423      * <li>options {Object} The parameter to the request call.</li>
11424      * </ul></li>
11425      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11426      * The callback is passed the following parameters:<ul>
11427      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11428      * <li>options {Object} The parameter to the request call.</li>
11429      * </ul></li>
11430      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11431      * for the callback function. Defaults to the browser window.</li>
11432      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11433      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11434      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11435      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11436      * params for the post data. Any params will be appended to the URL.</li>
11437      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11438      * </ul>
11439      * @return {Number} transactionId
11440      */
11441     request : function(o){
11442         if(this.fireEvent("beforerequest", this, o) !== false){
11443             var p = o.params;
11444
11445             if(typeof p == "function"){
11446                 p = p.call(o.scope||window, o);
11447             }
11448             if(typeof p == "object"){
11449                 p = Roo.urlEncode(o.params);
11450             }
11451             if(this.extraParams){
11452                 var extras = Roo.urlEncode(this.extraParams);
11453                 p = p ? (p + '&' + extras) : extras;
11454             }
11455
11456             var url = o.url || this.url;
11457             if(typeof url == 'function'){
11458                 url = url.call(o.scope||window, o);
11459             }
11460
11461             if(o.form){
11462                 var form = Roo.getDom(o.form);
11463                 url = url || form.action;
11464
11465                 var enctype = form.getAttribute("enctype");
11466                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11467                     return this.doFormUpload(o, p, url);
11468                 }
11469                 var f = Roo.lib.Ajax.serializeForm(form);
11470                 p = p ? (p + '&' + f) : f;
11471             }
11472
11473             var hs = o.headers;
11474             if(this.defaultHeaders){
11475                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11476                 if(!o.headers){
11477                     o.headers = hs;
11478                 }
11479             }
11480
11481             var cb = {
11482                 success: this.handleResponse,
11483                 failure: this.handleFailure,
11484                 scope: this,
11485                 argument: {options: o},
11486                 timeout : o.timeout || this.timeout
11487             };
11488
11489             var method = o.method||this.method||(p ? "POST" : "GET");
11490
11491             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11492                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11493             }
11494
11495             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11496                 if(o.autoAbort){
11497                     this.abort();
11498                 }
11499             }else if(this.autoAbort !== false){
11500                 this.abort();
11501             }
11502
11503             if((method == 'GET' && p) || o.xmlData){
11504                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11505                 p = '';
11506             }
11507             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11508             return this.transId;
11509         }else{
11510             Roo.callback(o.callback, o.scope, [o, null, null]);
11511             return null;
11512         }
11513     },
11514
11515     /**
11516      * Determine whether this object has a request outstanding.
11517      * @param {Number} transactionId (Optional) defaults to the last transaction
11518      * @return {Boolean} True if there is an outstanding request.
11519      */
11520     isLoading : function(transId){
11521         if(transId){
11522             return Roo.lib.Ajax.isCallInProgress(transId);
11523         }else{
11524             return this.transId ? true : false;
11525         }
11526     },
11527
11528     /**
11529      * Aborts any outstanding request.
11530      * @param {Number} transactionId (Optional) defaults to the last transaction
11531      */
11532     abort : function(transId){
11533         if(transId || this.isLoading()){
11534             Roo.lib.Ajax.abort(transId || this.transId);
11535         }
11536     },
11537
11538     // private
11539     handleResponse : function(response){
11540         this.transId = false;
11541         var options = response.argument.options;
11542         response.argument = options ? options.argument : null;
11543         this.fireEvent("requestcomplete", this, response, options);
11544         Roo.callback(options.success, options.scope, [response, options]);
11545         Roo.callback(options.callback, options.scope, [options, true, response]);
11546     },
11547
11548     // private
11549     handleFailure : function(response, e){
11550         this.transId = false;
11551         var options = response.argument.options;
11552         response.argument = options ? options.argument : null;
11553         this.fireEvent("requestexception", this, response, options, e);
11554         Roo.callback(options.failure, options.scope, [response, options]);
11555         Roo.callback(options.callback, options.scope, [options, false, response]);
11556     },
11557
11558     // private
11559     doFormUpload : function(o, ps, url){
11560         var id = Roo.id();
11561         var frame = document.createElement('iframe');
11562         frame.id = id;
11563         frame.name = id;
11564         frame.className = 'x-hidden';
11565         if(Roo.isIE){
11566             frame.src = Roo.SSL_SECURE_URL;
11567         }
11568         document.body.appendChild(frame);
11569
11570         if(Roo.isIE){
11571            document.frames[id].name = id;
11572         }
11573
11574         var form = Roo.getDom(o.form);
11575         form.target = id;
11576         form.method = 'POST';
11577         form.enctype = form.encoding = 'multipart/form-data';
11578         if(url){
11579             form.action = url;
11580         }
11581
11582         var hiddens, hd;
11583         if(ps){ // add dynamic params
11584             hiddens = [];
11585             ps = Roo.urlDecode(ps, false);
11586             for(var k in ps){
11587                 if(ps.hasOwnProperty(k)){
11588                     hd = document.createElement('input');
11589                     hd.type = 'hidden';
11590                     hd.name = k;
11591                     hd.value = ps[k];
11592                     form.appendChild(hd);
11593                     hiddens.push(hd);
11594                 }
11595             }
11596         }
11597
11598         function cb(){
11599             var r = {  // bogus response object
11600                 responseText : '',
11601                 responseXML : null
11602             };
11603
11604             r.argument = o ? o.argument : null;
11605
11606             try { //
11607                 var doc;
11608                 if(Roo.isIE){
11609                     doc = frame.contentWindow.document;
11610                 }else {
11611                     doc = (frame.contentDocument || window.frames[id].document);
11612                 }
11613                 if(doc && doc.body){
11614                     r.responseText = doc.body.innerHTML;
11615                 }
11616                 if(doc && doc.XMLDocument){
11617                     r.responseXML = doc.XMLDocument;
11618                 }else {
11619                     r.responseXML = doc;
11620                 }
11621             }
11622             catch(e) {
11623                 // ignore
11624             }
11625
11626             Roo.EventManager.removeListener(frame, 'load', cb, this);
11627
11628             this.fireEvent("requestcomplete", this, r, o);
11629             Roo.callback(o.success, o.scope, [r, o]);
11630             Roo.callback(o.callback, o.scope, [o, true, r]);
11631
11632             setTimeout(function(){document.body.removeChild(frame);}, 100);
11633         }
11634
11635         Roo.EventManager.on(frame, 'load', cb, this);
11636         form.submit();
11637
11638         if(hiddens){ // remove dynamic params
11639             for(var i = 0, len = hiddens.length; i < len; i++){
11640                 form.removeChild(hiddens[i]);
11641             }
11642         }
11643     }
11644 });
11645 /*
11646  * Based on:
11647  * Ext JS Library 1.1.1
11648  * Copyright(c) 2006-2007, Ext JS, LLC.
11649  *
11650  * Originally Released Under LGPL - original licence link has changed is not relivant.
11651  *
11652  * Fork - LGPL
11653  * <script type="text/javascript">
11654  */
11655  
11656 /**
11657  * Global Ajax request class.
11658  * 
11659  * @class Roo.Ajax
11660  * @extends Roo.data.Connection
11661  * @static
11662  * 
11663  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11664  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11665  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11666  * @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)
11667  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11668  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11669  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11670  */
11671 Roo.Ajax = new Roo.data.Connection({
11672     // fix up the docs
11673     /**
11674      * @scope Roo.Ajax
11675      * @type {Boolear} 
11676      */
11677     autoAbort : false,
11678
11679     /**
11680      * Serialize the passed form into a url encoded string
11681      * @scope Roo.Ajax
11682      * @param {String/HTMLElement} form
11683      * @return {String}
11684      */
11685     serializeForm : function(form){
11686         return Roo.lib.Ajax.serializeForm(form);
11687     }
11688 });/*
11689  * Based on:
11690  * Ext JS Library 1.1.1
11691  * Copyright(c) 2006-2007, Ext JS, LLC.
11692  *
11693  * Originally Released Under LGPL - original licence link has changed is not relivant.
11694  *
11695  * Fork - LGPL
11696  * <script type="text/javascript">
11697  */
11698
11699  
11700 /**
11701  * @class Roo.UpdateManager
11702  * @extends Roo.util.Observable
11703  * Provides AJAX-style update for Element object.<br><br>
11704  * Usage:<br>
11705  * <pre><code>
11706  * // Get it from a Roo.Element object
11707  * var el = Roo.get("foo");
11708  * var mgr = el.getUpdateManager();
11709  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11710  * ...
11711  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11712  * <br>
11713  * // or directly (returns the same UpdateManager instance)
11714  * var mgr = new Roo.UpdateManager("myElementId");
11715  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11716  * mgr.on("update", myFcnNeedsToKnow);
11717  * <br>
11718    // short handed call directly from the element object
11719    Roo.get("foo").load({
11720         url: "bar.php",
11721         scripts:true,
11722         params: "for=bar",
11723         text: "Loading Foo..."
11724    });
11725  * </code></pre>
11726  * @constructor
11727  * Create new UpdateManager directly.
11728  * @param {String/HTMLElement/Roo.Element} el The element to update
11729  * @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).
11730  */
11731 Roo.UpdateManager = function(el, forceNew){
11732     el = Roo.get(el);
11733     if(!forceNew && el.updateManager){
11734         return el.updateManager;
11735     }
11736     /**
11737      * The Element object
11738      * @type Roo.Element
11739      */
11740     this.el = el;
11741     /**
11742      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11743      * @type String
11744      */
11745     this.defaultUrl = null;
11746
11747     this.addEvents({
11748         /**
11749          * @event beforeupdate
11750          * Fired before an update is made, return false from your handler and the update is cancelled.
11751          * @param {Roo.Element} el
11752          * @param {String/Object/Function} url
11753          * @param {String/Object} params
11754          */
11755         "beforeupdate": true,
11756         /**
11757          * @event update
11758          * Fired after successful update is made.
11759          * @param {Roo.Element} el
11760          * @param {Object} oResponseObject The response Object
11761          */
11762         "update": true,
11763         /**
11764          * @event failure
11765          * Fired on update failure.
11766          * @param {Roo.Element} el
11767          * @param {Object} oResponseObject The response Object
11768          */
11769         "failure": true
11770     });
11771     var d = Roo.UpdateManager.defaults;
11772     /**
11773      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11774      * @type String
11775      */
11776     this.sslBlankUrl = d.sslBlankUrl;
11777     /**
11778      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11779      * @type Boolean
11780      */
11781     this.disableCaching = d.disableCaching;
11782     /**
11783      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11784      * @type String
11785      */
11786     this.indicatorText = d.indicatorText;
11787     /**
11788      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11789      * @type String
11790      */
11791     this.showLoadIndicator = d.showLoadIndicator;
11792     /**
11793      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11794      * @type Number
11795      */
11796     this.timeout = d.timeout;
11797
11798     /**
11799      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11800      * @type Boolean
11801      */
11802     this.loadScripts = d.loadScripts;
11803
11804     /**
11805      * Transaction object of current executing transaction
11806      */
11807     this.transaction = null;
11808
11809     /**
11810      * @private
11811      */
11812     this.autoRefreshProcId = null;
11813     /**
11814      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11815      * @type Function
11816      */
11817     this.refreshDelegate = this.refresh.createDelegate(this);
11818     /**
11819      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11820      * @type Function
11821      */
11822     this.updateDelegate = this.update.createDelegate(this);
11823     /**
11824      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11825      * @type Function
11826      */
11827     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11828     /**
11829      * @private
11830      */
11831     this.successDelegate = this.processSuccess.createDelegate(this);
11832     /**
11833      * @private
11834      */
11835     this.failureDelegate = this.processFailure.createDelegate(this);
11836
11837     if(!this.renderer){
11838      /**
11839       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11840       */
11841     this.renderer = new Roo.UpdateManager.BasicRenderer();
11842     }
11843     
11844     Roo.UpdateManager.superclass.constructor.call(this);
11845 };
11846
11847 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11848     /**
11849      * Get the Element this UpdateManager is bound to
11850      * @return {Roo.Element} The element
11851      */
11852     getEl : function(){
11853         return this.el;
11854     },
11855     /**
11856      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11857      * @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:
11858 <pre><code>
11859 um.update({<br/>
11860     url: "your-url.php",<br/>
11861     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11862     callback: yourFunction,<br/>
11863     scope: yourObject, //(optional scope)  <br/>
11864     discardUrl: false, <br/>
11865     nocache: false,<br/>
11866     text: "Loading...",<br/>
11867     timeout: 30,<br/>
11868     scripts: false<br/>
11869 });
11870 </code></pre>
11871      * The only required property is url. The optional properties nocache, text and scripts
11872      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11873      * @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}
11874      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11875      * @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.
11876      */
11877     update : function(url, params, callback, discardUrl){
11878         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11879             var method = this.method,
11880                 cfg;
11881             if(typeof url == "object"){ // must be config object
11882                 cfg = url;
11883                 url = cfg.url;
11884                 params = params || cfg.params;
11885                 callback = callback || cfg.callback;
11886                 discardUrl = discardUrl || cfg.discardUrl;
11887                 if(callback && cfg.scope){
11888                     callback = callback.createDelegate(cfg.scope);
11889                 }
11890                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11891                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11892                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11893                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11894                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11895             }
11896             this.showLoading();
11897             if(!discardUrl){
11898                 this.defaultUrl = url;
11899             }
11900             if(typeof url == "function"){
11901                 url = url.call(this);
11902             }
11903
11904             method = method || (params ? "POST" : "GET");
11905             if(method == "GET"){
11906                 url = this.prepareUrl(url);
11907             }
11908
11909             var o = Roo.apply(cfg ||{}, {
11910                 url : url,
11911                 params: params,
11912                 success: this.successDelegate,
11913                 failure: this.failureDelegate,
11914                 callback: undefined,
11915                 timeout: (this.timeout*1000),
11916                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11917             });
11918             Roo.log("updated manager called with timeout of " + o.timeout);
11919             this.transaction = Roo.Ajax.request(o);
11920         }
11921     },
11922
11923     /**
11924      * 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.
11925      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11926      * @param {String/HTMLElement} form The form Id or form element
11927      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11928      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11929      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11930      */
11931     formUpdate : function(form, url, reset, callback){
11932         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11933             if(typeof url == "function"){
11934                 url = url.call(this);
11935             }
11936             form = Roo.getDom(form);
11937             this.transaction = Roo.Ajax.request({
11938                 form: form,
11939                 url:url,
11940                 success: this.successDelegate,
11941                 failure: this.failureDelegate,
11942                 timeout: (this.timeout*1000),
11943                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11944             });
11945             this.showLoading.defer(1, this);
11946         }
11947     },
11948
11949     /**
11950      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11951      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11952      */
11953     refresh : function(callback){
11954         if(this.defaultUrl == null){
11955             return;
11956         }
11957         this.update(this.defaultUrl, null, callback, true);
11958     },
11959
11960     /**
11961      * Set this element to auto refresh.
11962      * @param {Number} interval How often to update (in seconds).
11963      * @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)
11964      * @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}
11965      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11966      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11967      */
11968     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11969         if(refreshNow){
11970             this.update(url || this.defaultUrl, params, callback, true);
11971         }
11972         if(this.autoRefreshProcId){
11973             clearInterval(this.autoRefreshProcId);
11974         }
11975         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11976     },
11977
11978     /**
11979      * Stop auto refresh on this element.
11980      */
11981      stopAutoRefresh : function(){
11982         if(this.autoRefreshProcId){
11983             clearInterval(this.autoRefreshProcId);
11984             delete this.autoRefreshProcId;
11985         }
11986     },
11987
11988     isAutoRefreshing : function(){
11989        return this.autoRefreshProcId ? true : false;
11990     },
11991     /**
11992      * Called to update the element to "Loading" state. Override to perform custom action.
11993      */
11994     showLoading : function(){
11995         if(this.showLoadIndicator){
11996             this.el.update(this.indicatorText);
11997         }
11998     },
11999
12000     /**
12001      * Adds unique parameter to query string if disableCaching = true
12002      * @private
12003      */
12004     prepareUrl : function(url){
12005         if(this.disableCaching){
12006             var append = "_dc=" + (new Date().getTime());
12007             if(url.indexOf("?") !== -1){
12008                 url += "&" + append;
12009             }else{
12010                 url += "?" + append;
12011             }
12012         }
12013         return url;
12014     },
12015
12016     /**
12017      * @private
12018      */
12019     processSuccess : function(response){
12020         this.transaction = null;
12021         if(response.argument.form && response.argument.reset){
12022             try{ // put in try/catch since some older FF releases had problems with this
12023                 response.argument.form.reset();
12024             }catch(e){}
12025         }
12026         if(this.loadScripts){
12027             this.renderer.render(this.el, response, this,
12028                 this.updateComplete.createDelegate(this, [response]));
12029         }else{
12030             this.renderer.render(this.el, response, this);
12031             this.updateComplete(response);
12032         }
12033     },
12034
12035     updateComplete : function(response){
12036         this.fireEvent("update", this.el, response);
12037         if(typeof response.argument.callback == "function"){
12038             response.argument.callback(this.el, true, response);
12039         }
12040     },
12041
12042     /**
12043      * @private
12044      */
12045     processFailure : function(response){
12046         this.transaction = null;
12047         this.fireEvent("failure", this.el, response);
12048         if(typeof response.argument.callback == "function"){
12049             response.argument.callback(this.el, false, response);
12050         }
12051     },
12052
12053     /**
12054      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12055      * @param {Object} renderer The object implementing the render() method
12056      */
12057     setRenderer : function(renderer){
12058         this.renderer = renderer;
12059     },
12060
12061     getRenderer : function(){
12062        return this.renderer;
12063     },
12064
12065     /**
12066      * Set the defaultUrl used for updates
12067      * @param {String/Function} defaultUrl The url or a function to call to get the url
12068      */
12069     setDefaultUrl : function(defaultUrl){
12070         this.defaultUrl = defaultUrl;
12071     },
12072
12073     /**
12074      * Aborts the executing transaction
12075      */
12076     abort : function(){
12077         if(this.transaction){
12078             Roo.Ajax.abort(this.transaction);
12079         }
12080     },
12081
12082     /**
12083      * Returns true if an update is in progress
12084      * @return {Boolean}
12085      */
12086     isUpdating : function(){
12087         if(this.transaction){
12088             return Roo.Ajax.isLoading(this.transaction);
12089         }
12090         return false;
12091     }
12092 });
12093
12094 /**
12095  * @class Roo.UpdateManager.defaults
12096  * @static (not really - but it helps the doc tool)
12097  * The defaults collection enables customizing the default properties of UpdateManager
12098  */
12099    Roo.UpdateManager.defaults = {
12100        /**
12101          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12102          * @type Number
12103          */
12104          timeout : 30,
12105
12106          /**
12107          * True to process scripts by default (Defaults to false).
12108          * @type Boolean
12109          */
12110         loadScripts : false,
12111
12112         /**
12113         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12114         * @type String
12115         */
12116         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12117         /**
12118          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12119          * @type Boolean
12120          */
12121         disableCaching : false,
12122         /**
12123          * Whether to show indicatorText when loading (Defaults to true).
12124          * @type Boolean
12125          */
12126         showLoadIndicator : true,
12127         /**
12128          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12129          * @type String
12130          */
12131         indicatorText : '<div class="loading-indicator">Loading...</div>'
12132    };
12133
12134 /**
12135  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12136  *Usage:
12137  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12138  * @param {String/HTMLElement/Roo.Element} el The element to update
12139  * @param {String} url The url
12140  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12141  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12142  * @static
12143  * @deprecated
12144  * @member Roo.UpdateManager
12145  */
12146 Roo.UpdateManager.updateElement = function(el, url, params, options){
12147     var um = Roo.get(el, true).getUpdateManager();
12148     Roo.apply(um, options);
12149     um.update(url, params, options ? options.callback : null);
12150 };
12151 // alias for backwards compat
12152 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12153 /**
12154  * @class Roo.UpdateManager.BasicRenderer
12155  * Default Content renderer. Updates the elements innerHTML with the responseText.
12156  */
12157 Roo.UpdateManager.BasicRenderer = function(){};
12158
12159 Roo.UpdateManager.BasicRenderer.prototype = {
12160     /**
12161      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12162      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12163      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12164      * @param {Roo.Element} el The element being rendered
12165      * @param {Object} response The YUI Connect response object
12166      * @param {UpdateManager} updateManager The calling update manager
12167      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12168      */
12169      render : function(el, response, updateManager, callback){
12170         el.update(response.responseText, updateManager.loadScripts, callback);
12171     }
12172 };
12173 /*
12174  * Based on:
12175  * Roo JS
12176  * (c)) Alan Knowles
12177  * Licence : LGPL
12178  */
12179
12180
12181 /**
12182  * @class Roo.DomTemplate
12183  * @extends Roo.Template
12184  * An effort at a dom based template engine..
12185  *
12186  * Similar to XTemplate, except it uses dom parsing to create the template..
12187  *
12188  * Supported features:
12189  *
12190  *  Tags:
12191
12192 <pre><code>
12193       {a_variable} - output encoded.
12194       {a_variable.format:("Y-m-d")} - call a method on the variable
12195       {a_variable:raw} - unencoded output
12196       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12197       {a_variable:this.method_on_template(...)} - call a method on the template object.
12198  
12199 </code></pre>
12200  *  The tpl tag:
12201 <pre><code>
12202         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12203         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12204         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12205         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12206   
12207 </code></pre>
12208  *      
12209  */
12210 Roo.DomTemplate = function()
12211 {
12212      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12213      if (this.html) {
12214         this.compile();
12215      }
12216 };
12217
12218
12219 Roo.extend(Roo.DomTemplate, Roo.Template, {
12220     /**
12221      * id counter for sub templates.
12222      */
12223     id : 0,
12224     /**
12225      * flag to indicate if dom parser is inside a pre,
12226      * it will strip whitespace if not.
12227      */
12228     inPre : false,
12229     
12230     /**
12231      * The various sub templates
12232      */
12233     tpls : false,
12234     
12235     
12236     
12237     /**
12238      *
12239      * basic tag replacing syntax
12240      * WORD:WORD()
12241      *
12242      * // you can fake an object call by doing this
12243      *  x.t:(test,tesT) 
12244      * 
12245      */
12246     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12247     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12248     
12249     iterChild : function (node, method) {
12250         
12251         var oldPre = this.inPre;
12252         if (node.tagName == 'PRE') {
12253             this.inPre = true;
12254         }
12255         for( var i = 0; i < node.childNodes.length; i++) {
12256             method.call(this, node.childNodes[i]);
12257         }
12258         this.inPre = oldPre;
12259     },
12260     
12261     
12262     
12263     /**
12264      * compile the template
12265      *
12266      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12267      *
12268      */
12269     compile: function()
12270     {
12271         var s = this.html;
12272         
12273         // covert the html into DOM...
12274         var doc = false;
12275         var div =false;
12276         try {
12277             doc = document.implementation.createHTMLDocument("");
12278             doc.documentElement.innerHTML =   this.html  ;
12279             div = doc.documentElement;
12280         } catch (e) {
12281             // old IE... - nasty -- it causes all sorts of issues.. with
12282             // images getting pulled from server..
12283             div = document.createElement('div');
12284             div.innerHTML = this.html;
12285         }
12286         //doc.documentElement.innerHTML = htmlBody
12287          
12288         
12289         
12290         this.tpls = [];
12291         var _t = this;
12292         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12293         
12294         var tpls = this.tpls;
12295         
12296         // create a top level template from the snippet..
12297         
12298         //Roo.log(div.innerHTML);
12299         
12300         var tpl = {
12301             uid : 'master',
12302             id : this.id++,
12303             attr : false,
12304             value : false,
12305             body : div.innerHTML,
12306             
12307             forCall : false,
12308             execCall : false,
12309             dom : div,
12310             isTop : true
12311             
12312         };
12313         tpls.unshift(tpl);
12314         
12315         
12316         // compile them...
12317         this.tpls = [];
12318         Roo.each(tpls, function(tp){
12319             this.compileTpl(tp);
12320             this.tpls[tp.id] = tp;
12321         }, this);
12322         
12323         this.master = tpls[0];
12324         return this;
12325         
12326         
12327     },
12328     
12329     compileNode : function(node, istop) {
12330         // test for
12331         //Roo.log(node);
12332         
12333         
12334         // skip anything not a tag..
12335         if (node.nodeType != 1) {
12336             if (node.nodeType == 3 && !this.inPre) {
12337                 // reduce white space..
12338                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12339                 
12340             }
12341             return;
12342         }
12343         
12344         var tpl = {
12345             uid : false,
12346             id : false,
12347             attr : false,
12348             value : false,
12349             body : '',
12350             
12351             forCall : false,
12352             execCall : false,
12353             dom : false,
12354             isTop : istop
12355             
12356             
12357         };
12358         
12359         
12360         switch(true) {
12361             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12362             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12363             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12364             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12365             // no default..
12366         }
12367         
12368         
12369         if (!tpl.attr) {
12370             // just itterate children..
12371             this.iterChild(node,this.compileNode);
12372             return;
12373         }
12374         tpl.uid = this.id++;
12375         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12376         node.removeAttribute('roo-'+ tpl.attr);
12377         if (tpl.attr != 'name') {
12378             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12379             node.parentNode.replaceChild(placeholder,  node);
12380         } else {
12381             
12382             var placeholder =  document.createElement('span');
12383             placeholder.className = 'roo-tpl-' + tpl.value;
12384             node.parentNode.replaceChild(placeholder,  node);
12385         }
12386         
12387         // parent now sees '{domtplXXXX}
12388         this.iterChild(node,this.compileNode);
12389         
12390         // we should now have node body...
12391         var div = document.createElement('div');
12392         div.appendChild(node);
12393         tpl.dom = node;
12394         // this has the unfortunate side effect of converting tagged attributes
12395         // eg. href="{...}" into %7C...%7D
12396         // this has been fixed by searching for those combo's although it's a bit hacky..
12397         
12398         
12399         tpl.body = div.innerHTML;
12400         
12401         
12402          
12403         tpl.id = tpl.uid;
12404         switch(tpl.attr) {
12405             case 'for' :
12406                 switch (tpl.value) {
12407                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12408                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12409                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12410                 }
12411                 break;
12412             
12413             case 'exec':
12414                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12415                 break;
12416             
12417             case 'if':     
12418                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12419                 break;
12420             
12421             case 'name':
12422                 tpl.id  = tpl.value; // replace non characters???
12423                 break;
12424             
12425         }
12426         
12427         
12428         this.tpls.push(tpl);
12429         
12430         
12431         
12432     },
12433     
12434     
12435     
12436     
12437     /**
12438      * Compile a segment of the template into a 'sub-template'
12439      *
12440      * 
12441      * 
12442      *
12443      */
12444     compileTpl : function(tpl)
12445     {
12446         var fm = Roo.util.Format;
12447         var useF = this.disableFormats !== true;
12448         
12449         var sep = Roo.isGecko ? "+\n" : ",\n";
12450         
12451         var undef = function(str) {
12452             Roo.debug && Roo.log("Property not found :"  + str);
12453             return '';
12454         };
12455           
12456         //Roo.log(tpl.body);
12457         
12458         
12459         
12460         var fn = function(m, lbrace, name, format, args)
12461         {
12462             //Roo.log("ARGS");
12463             //Roo.log(arguments);
12464             args = args ? args.replace(/\\'/g,"'") : args;
12465             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12466             if (typeof(format) == 'undefined') {
12467                 format =  'htmlEncode'; 
12468             }
12469             if (format == 'raw' ) {
12470                 format = false;
12471             }
12472             
12473             if(name.substr(0, 6) == 'domtpl'){
12474                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12475             }
12476             
12477             // build an array of options to determine if value is undefined..
12478             
12479             // basically get 'xxxx.yyyy' then do
12480             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12481             //    (function () { Roo.log("Property not found"); return ''; })() :
12482             //    ......
12483             
12484             var udef_ar = [];
12485             var lookfor = '';
12486             Roo.each(name.split('.'), function(st) {
12487                 lookfor += (lookfor.length ? '.': '') + st;
12488                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12489             });
12490             
12491             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12492             
12493             
12494             if(format && useF){
12495                 
12496                 args = args ? ',' + args : "";
12497                  
12498                 if(format.substr(0, 5) != "this."){
12499                     format = "fm." + format + '(';
12500                 }else{
12501                     format = 'this.call("'+ format.substr(5) + '", ';
12502                     args = ", values";
12503                 }
12504                 
12505                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12506             }
12507              
12508             if (args && args.length) {
12509                 // called with xxyx.yuu:(test,test)
12510                 // change to ()
12511                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12512             }
12513             // raw.. - :raw modifier..
12514             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12515             
12516         };
12517         var body;
12518         // branched to use + in gecko and [].join() in others
12519         if(Roo.isGecko){
12520             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12521                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12522                     "';};};";
12523         }else{
12524             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12525             body.push(tpl.body.replace(/(\r\n|\n)/g,
12526                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12527             body.push("'].join('');};};");
12528             body = body.join('');
12529         }
12530         
12531         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12532        
12533         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12534         eval(body);
12535         
12536         return this;
12537     },
12538      
12539     /**
12540      * same as applyTemplate, except it's done to one of the subTemplates
12541      * when using named templates, you can do:
12542      *
12543      * var str = pl.applySubTemplate('your-name', values);
12544      *
12545      * 
12546      * @param {Number} id of the template
12547      * @param {Object} values to apply to template
12548      * @param {Object} parent (normaly the instance of this object)
12549      */
12550     applySubTemplate : function(id, values, parent)
12551     {
12552         
12553         
12554         var t = this.tpls[id];
12555         
12556         
12557         try { 
12558             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12559                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12560                 return '';
12561             }
12562         } catch(e) {
12563             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12564             Roo.log(values);
12565           
12566             return '';
12567         }
12568         try { 
12569             
12570             if(t.execCall && t.execCall.call(this, values, parent)){
12571                 return '';
12572             }
12573         } catch(e) {
12574             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12575             Roo.log(values);
12576             return '';
12577         }
12578         
12579         try {
12580             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12581             parent = t.target ? values : parent;
12582             if(t.forCall && vs instanceof Array){
12583                 var buf = [];
12584                 for(var i = 0, len = vs.length; i < len; i++){
12585                     try {
12586                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12587                     } catch (e) {
12588                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12589                         Roo.log(e.body);
12590                         //Roo.log(t.compiled);
12591                         Roo.log(vs[i]);
12592                     }   
12593                 }
12594                 return buf.join('');
12595             }
12596         } catch (e) {
12597             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12598             Roo.log(values);
12599             return '';
12600         }
12601         try {
12602             return t.compiled.call(this, vs, parent);
12603         } catch (e) {
12604             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12605             Roo.log(e.body);
12606             //Roo.log(t.compiled);
12607             Roo.log(values);
12608             return '';
12609         }
12610     },
12611
12612    
12613
12614     applyTemplate : function(values){
12615         return this.master.compiled.call(this, values, {});
12616         //var s = this.subs;
12617     },
12618
12619     apply : function(){
12620         return this.applyTemplate.apply(this, arguments);
12621     }
12622
12623  });
12624
12625 Roo.DomTemplate.from = function(el){
12626     el = Roo.getDom(el);
12627     return new Roo.Domtemplate(el.value || el.innerHTML);
12628 };/*
12629  * Based on:
12630  * Ext JS Library 1.1.1
12631  * Copyright(c) 2006-2007, Ext JS, LLC.
12632  *
12633  * Originally Released Under LGPL - original licence link has changed is not relivant.
12634  *
12635  * Fork - LGPL
12636  * <script type="text/javascript">
12637  */
12638
12639 /**
12640  * @class Roo.util.DelayedTask
12641  * Provides a convenient method of performing setTimeout where a new
12642  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12643  * You can use this class to buffer
12644  * the keypress events for a certain number of milliseconds, and perform only if they stop
12645  * for that amount of time.
12646  * @constructor The parameters to this constructor serve as defaults and are not required.
12647  * @param {Function} fn (optional) The default function to timeout
12648  * @param {Object} scope (optional) The default scope of that timeout
12649  * @param {Array} args (optional) The default Array of arguments
12650  */
12651 Roo.util.DelayedTask = function(fn, scope, args){
12652     var id = null, d, t;
12653
12654     var call = function(){
12655         var now = new Date().getTime();
12656         if(now - t >= d){
12657             clearInterval(id);
12658             id = null;
12659             fn.apply(scope, args || []);
12660         }
12661     };
12662     /**
12663      * Cancels any pending timeout and queues a new one
12664      * @param {Number} delay The milliseconds to delay
12665      * @param {Function} newFn (optional) Overrides function passed to constructor
12666      * @param {Object} newScope (optional) Overrides scope passed to constructor
12667      * @param {Array} newArgs (optional) Overrides args passed to constructor
12668      */
12669     this.delay = function(delay, newFn, newScope, newArgs){
12670         if(id && delay != d){
12671             this.cancel();
12672         }
12673         d = delay;
12674         t = new Date().getTime();
12675         fn = newFn || fn;
12676         scope = newScope || scope;
12677         args = newArgs || args;
12678         if(!id){
12679             id = setInterval(call, d);
12680         }
12681     };
12682
12683     /**
12684      * Cancel the last queued timeout
12685      */
12686     this.cancel = function(){
12687         if(id){
12688             clearInterval(id);
12689             id = null;
12690         }
12691     };
12692 };/*
12693  * Based on:
12694  * Ext JS Library 1.1.1
12695  * Copyright(c) 2006-2007, Ext JS, LLC.
12696  *
12697  * Originally Released Under LGPL - original licence link has changed is not relivant.
12698  *
12699  * Fork - LGPL
12700  * <script type="text/javascript">
12701  */
12702  
12703  
12704 Roo.util.TaskRunner = function(interval){
12705     interval = interval || 10;
12706     var tasks = [], removeQueue = [];
12707     var id = 0;
12708     var running = false;
12709
12710     var stopThread = function(){
12711         running = false;
12712         clearInterval(id);
12713         id = 0;
12714     };
12715
12716     var startThread = function(){
12717         if(!running){
12718             running = true;
12719             id = setInterval(runTasks, interval);
12720         }
12721     };
12722
12723     var removeTask = function(task){
12724         removeQueue.push(task);
12725         if(task.onStop){
12726             task.onStop();
12727         }
12728     };
12729
12730     var runTasks = function(){
12731         if(removeQueue.length > 0){
12732             for(var i = 0, len = removeQueue.length; i < len; i++){
12733                 tasks.remove(removeQueue[i]);
12734             }
12735             removeQueue = [];
12736             if(tasks.length < 1){
12737                 stopThread();
12738                 return;
12739             }
12740         }
12741         var now = new Date().getTime();
12742         for(var i = 0, len = tasks.length; i < len; ++i){
12743             var t = tasks[i];
12744             var itime = now - t.taskRunTime;
12745             if(t.interval <= itime){
12746                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12747                 t.taskRunTime = now;
12748                 if(rt === false || t.taskRunCount === t.repeat){
12749                     removeTask(t);
12750                     return;
12751                 }
12752             }
12753             if(t.duration && t.duration <= (now - t.taskStartTime)){
12754                 removeTask(t);
12755             }
12756         }
12757     };
12758
12759     /**
12760      * Queues a new task.
12761      * @param {Object} task
12762      */
12763     this.start = function(task){
12764         tasks.push(task);
12765         task.taskStartTime = new Date().getTime();
12766         task.taskRunTime = 0;
12767         task.taskRunCount = 0;
12768         startThread();
12769         return task;
12770     };
12771
12772     this.stop = function(task){
12773         removeTask(task);
12774         return task;
12775     };
12776
12777     this.stopAll = function(){
12778         stopThread();
12779         for(var i = 0, len = tasks.length; i < len; i++){
12780             if(tasks[i].onStop){
12781                 tasks[i].onStop();
12782             }
12783         }
12784         tasks = [];
12785         removeQueue = [];
12786     };
12787 };
12788
12789 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12790  * Based on:
12791  * Ext JS Library 1.1.1
12792  * Copyright(c) 2006-2007, Ext JS, LLC.
12793  *
12794  * Originally Released Under LGPL - original licence link has changed is not relivant.
12795  *
12796  * Fork - LGPL
12797  * <script type="text/javascript">
12798  */
12799
12800  
12801 /**
12802  * @class Roo.util.MixedCollection
12803  * @extends Roo.util.Observable
12804  * A Collection class that maintains both numeric indexes and keys and exposes events.
12805  * @constructor
12806  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12807  * collection (defaults to false)
12808  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12809  * and return the key value for that item.  This is used when available to look up the key on items that
12810  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12811  * equivalent to providing an implementation for the {@link #getKey} method.
12812  */
12813 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12814     this.items = [];
12815     this.map = {};
12816     this.keys = [];
12817     this.length = 0;
12818     this.addEvents({
12819         /**
12820          * @event clear
12821          * Fires when the collection is cleared.
12822          */
12823         "clear" : true,
12824         /**
12825          * @event add
12826          * Fires when an item is added to the collection.
12827          * @param {Number} index The index at which the item was added.
12828          * @param {Object} o The item added.
12829          * @param {String} key The key associated with the added item.
12830          */
12831         "add" : true,
12832         /**
12833          * @event replace
12834          * Fires when an item is replaced in the collection.
12835          * @param {String} key he key associated with the new added.
12836          * @param {Object} old The item being replaced.
12837          * @param {Object} new The new item.
12838          */
12839         "replace" : true,
12840         /**
12841          * @event remove
12842          * Fires when an item is removed from the collection.
12843          * @param {Object} o The item being removed.
12844          * @param {String} key (optional) The key associated with the removed item.
12845          */
12846         "remove" : true,
12847         "sort" : true
12848     });
12849     this.allowFunctions = allowFunctions === true;
12850     if(keyFn){
12851         this.getKey = keyFn;
12852     }
12853     Roo.util.MixedCollection.superclass.constructor.call(this);
12854 };
12855
12856 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12857     allowFunctions : false,
12858     
12859 /**
12860  * Adds an item to the collection.
12861  * @param {String} key The key to associate with the item
12862  * @param {Object} o The item to add.
12863  * @return {Object} The item added.
12864  */
12865     add : function(key, o){
12866         if(arguments.length == 1){
12867             o = key; //arguments[0];
12868             key = this.getKey(o);
12869         }
12870         if(typeof key == "undefined" || key === null){
12871             this.length++;
12872             this.items.push(o);
12873             this.keys.push(null);
12874         }else{
12875             var old = this.map[key];
12876             if(old){
12877                 return this.replace(key, o);
12878             }
12879             this.length++;
12880             this.items.push(o);
12881             this.map[key] = o;
12882             this.keys.push(key);
12883         }
12884         this.fireEvent("add", this.length-1, o, key);
12885         return o;
12886     },
12887        
12888 /**
12889   * MixedCollection has a generic way to fetch keys if you implement getKey.
12890 <pre><code>
12891 // normal way
12892 var mc = new Roo.util.MixedCollection();
12893 mc.add(someEl.dom.id, someEl);
12894 mc.add(otherEl.dom.id, otherEl);
12895 //and so on
12896
12897 // using getKey
12898 var mc = new Roo.util.MixedCollection();
12899 mc.getKey = function(el){
12900    return el.dom.id;
12901 };
12902 mc.add(someEl);
12903 mc.add(otherEl);
12904
12905 // or via the constructor
12906 var mc = new Roo.util.MixedCollection(false, function(el){
12907    return el.dom.id;
12908 });
12909 mc.add(someEl);
12910 mc.add(otherEl);
12911 </code></pre>
12912  * @param o {Object} The item for which to find the key.
12913  * @return {Object} The key for the passed item.
12914  */
12915     getKey : function(o){
12916          return o.id; 
12917     },
12918    
12919 /**
12920  * Replaces an item in the collection.
12921  * @param {String} key The key associated with the item to replace, or the item to replace.
12922  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12923  * @return {Object}  The new item.
12924  */
12925     replace : function(key, o){
12926         if(arguments.length == 1){
12927             o = arguments[0];
12928             key = this.getKey(o);
12929         }
12930         var old = this.item(key);
12931         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12932              return this.add(key, o);
12933         }
12934         var index = this.indexOfKey(key);
12935         this.items[index] = o;
12936         this.map[key] = o;
12937         this.fireEvent("replace", key, old, o);
12938         return o;
12939     },
12940    
12941 /**
12942  * Adds all elements of an Array or an Object to the collection.
12943  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12944  * an Array of values, each of which are added to the collection.
12945  */
12946     addAll : function(objs){
12947         if(arguments.length > 1 || objs instanceof Array){
12948             var args = arguments.length > 1 ? arguments : objs;
12949             for(var i = 0, len = args.length; i < len; i++){
12950                 this.add(args[i]);
12951             }
12952         }else{
12953             for(var key in objs){
12954                 if(this.allowFunctions || typeof objs[key] != "function"){
12955                     this.add(key, objs[key]);
12956                 }
12957             }
12958         }
12959     },
12960    
12961 /**
12962  * Executes the specified function once for every item in the collection, passing each
12963  * item as the first and only parameter. returning false from the function will stop the iteration.
12964  * @param {Function} fn The function to execute for each item.
12965  * @param {Object} scope (optional) The scope in which to execute the function.
12966  */
12967     each : function(fn, scope){
12968         var items = [].concat(this.items); // each safe for removal
12969         for(var i = 0, len = items.length; i < len; i++){
12970             if(fn.call(scope || items[i], items[i], i, len) === false){
12971                 break;
12972             }
12973         }
12974     },
12975    
12976 /**
12977  * Executes the specified function once for every key in the collection, passing each
12978  * key, and its associated item as the first two parameters.
12979  * @param {Function} fn The function to execute for each item.
12980  * @param {Object} scope (optional) The scope in which to execute the function.
12981  */
12982     eachKey : function(fn, scope){
12983         for(var i = 0, len = this.keys.length; i < len; i++){
12984             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12985         }
12986     },
12987    
12988 /**
12989  * Returns the first item in the collection which elicits a true return value from the
12990  * passed selection function.
12991  * @param {Function} fn The selection function to execute for each item.
12992  * @param {Object} scope (optional) The scope in which to execute the function.
12993  * @return {Object} The first item in the collection which returned true from the selection function.
12994  */
12995     find : function(fn, scope){
12996         for(var i = 0, len = this.items.length; i < len; i++){
12997             if(fn.call(scope || window, this.items[i], this.keys[i])){
12998                 return this.items[i];
12999             }
13000         }
13001         return null;
13002     },
13003    
13004 /**
13005  * Inserts an item at the specified index in the collection.
13006  * @param {Number} index The index to insert the item at.
13007  * @param {String} key The key to associate with the new item, or the item itself.
13008  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13009  * @return {Object} The item inserted.
13010  */
13011     insert : function(index, key, o){
13012         if(arguments.length == 2){
13013             o = arguments[1];
13014             key = this.getKey(o);
13015         }
13016         if(index >= this.length){
13017             return this.add(key, o);
13018         }
13019         this.length++;
13020         this.items.splice(index, 0, o);
13021         if(typeof key != "undefined" && key != null){
13022             this.map[key] = o;
13023         }
13024         this.keys.splice(index, 0, key);
13025         this.fireEvent("add", index, o, key);
13026         return o;
13027     },
13028    
13029 /**
13030  * Removed an item from the collection.
13031  * @param {Object} o The item to remove.
13032  * @return {Object} The item removed.
13033  */
13034     remove : function(o){
13035         return this.removeAt(this.indexOf(o));
13036     },
13037    
13038 /**
13039  * Remove an item from a specified index in the collection.
13040  * @param {Number} index The index within the collection of the item to remove.
13041  */
13042     removeAt : function(index){
13043         if(index < this.length && index >= 0){
13044             this.length--;
13045             var o = this.items[index];
13046             this.items.splice(index, 1);
13047             var key = this.keys[index];
13048             if(typeof key != "undefined"){
13049                 delete this.map[key];
13050             }
13051             this.keys.splice(index, 1);
13052             this.fireEvent("remove", o, key);
13053         }
13054     },
13055    
13056 /**
13057  * Removed an item associated with the passed key fom the collection.
13058  * @param {String} key The key of the item to remove.
13059  */
13060     removeKey : function(key){
13061         return this.removeAt(this.indexOfKey(key));
13062     },
13063    
13064 /**
13065  * Returns the number of items in the collection.
13066  * @return {Number} the number of items in the collection.
13067  */
13068     getCount : function(){
13069         return this.length; 
13070     },
13071    
13072 /**
13073  * Returns index within the collection of the passed Object.
13074  * @param {Object} o The item to find the index of.
13075  * @return {Number} index of the item.
13076  */
13077     indexOf : function(o){
13078         if(!this.items.indexOf){
13079             for(var i = 0, len = this.items.length; i < len; i++){
13080                 if(this.items[i] == o) return i;
13081             }
13082             return -1;
13083         }else{
13084             return this.items.indexOf(o);
13085         }
13086     },
13087    
13088 /**
13089  * Returns index within the collection of the passed key.
13090  * @param {String} key The key to find the index of.
13091  * @return {Number} index of the key.
13092  */
13093     indexOfKey : function(key){
13094         if(!this.keys.indexOf){
13095             for(var i = 0, len = this.keys.length; i < len; i++){
13096                 if(this.keys[i] == key) return i;
13097             }
13098             return -1;
13099         }else{
13100             return this.keys.indexOf(key);
13101         }
13102     },
13103    
13104 /**
13105  * Returns the item associated with the passed key OR index. Key has priority over index.
13106  * @param {String/Number} key The key or index of the item.
13107  * @return {Object} The item associated with the passed key.
13108  */
13109     item : function(key){
13110         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13111         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13112     },
13113     
13114 /**
13115  * Returns the item at the specified index.
13116  * @param {Number} index The index of the item.
13117  * @return {Object}
13118  */
13119     itemAt : function(index){
13120         return this.items[index];
13121     },
13122     
13123 /**
13124  * Returns the item associated with the passed key.
13125  * @param {String/Number} key The key of the item.
13126  * @return {Object} The item associated with the passed key.
13127  */
13128     key : function(key){
13129         return this.map[key];
13130     },
13131    
13132 /**
13133  * Returns true if the collection contains the passed Object as an item.
13134  * @param {Object} o  The Object to look for in the collection.
13135  * @return {Boolean} True if the collection contains the Object as an item.
13136  */
13137     contains : function(o){
13138         return this.indexOf(o) != -1;
13139     },
13140    
13141 /**
13142  * Returns true if the collection contains the passed Object as a key.
13143  * @param {String} key The key to look for in the collection.
13144  * @return {Boolean} True if the collection contains the Object as a key.
13145  */
13146     containsKey : function(key){
13147         return typeof this.map[key] != "undefined";
13148     },
13149    
13150 /**
13151  * Removes all items from the collection.
13152  */
13153     clear : function(){
13154         this.length = 0;
13155         this.items = [];
13156         this.keys = [];
13157         this.map = {};
13158         this.fireEvent("clear");
13159     },
13160    
13161 /**
13162  * Returns the first item in the collection.
13163  * @return {Object} the first item in the collection..
13164  */
13165     first : function(){
13166         return this.items[0]; 
13167     },
13168    
13169 /**
13170  * Returns the last item in the collection.
13171  * @return {Object} the last item in the collection..
13172  */
13173     last : function(){
13174         return this.items[this.length-1];   
13175     },
13176     
13177     _sort : function(property, dir, fn){
13178         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13179         fn = fn || function(a, b){
13180             return a-b;
13181         };
13182         var c = [], k = this.keys, items = this.items;
13183         for(var i = 0, len = items.length; i < len; i++){
13184             c[c.length] = {key: k[i], value: items[i], index: i};
13185         }
13186         c.sort(function(a, b){
13187             var v = fn(a[property], b[property]) * dsc;
13188             if(v == 0){
13189                 v = (a.index < b.index ? -1 : 1);
13190             }
13191             return v;
13192         });
13193         for(var i = 0, len = c.length; i < len; i++){
13194             items[i] = c[i].value;
13195             k[i] = c[i].key;
13196         }
13197         this.fireEvent("sort", this);
13198     },
13199     
13200     /**
13201      * Sorts this collection with the passed comparison function
13202      * @param {String} direction (optional) "ASC" or "DESC"
13203      * @param {Function} fn (optional) comparison function
13204      */
13205     sort : function(dir, fn){
13206         this._sort("value", dir, fn);
13207     },
13208     
13209     /**
13210      * Sorts this collection by keys
13211      * @param {String} direction (optional) "ASC" or "DESC"
13212      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13213      */
13214     keySort : function(dir, fn){
13215         this._sort("key", dir, fn || function(a, b){
13216             return String(a).toUpperCase()-String(b).toUpperCase();
13217         });
13218     },
13219     
13220     /**
13221      * Returns a range of items in this collection
13222      * @param {Number} startIndex (optional) defaults to 0
13223      * @param {Number} endIndex (optional) default to the last item
13224      * @return {Array} An array of items
13225      */
13226     getRange : function(start, end){
13227         var items = this.items;
13228         if(items.length < 1){
13229             return [];
13230         }
13231         start = start || 0;
13232         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13233         var r = [];
13234         if(start <= end){
13235             for(var i = start; i <= end; i++) {
13236                     r[r.length] = items[i];
13237             }
13238         }else{
13239             for(var i = start; i >= end; i--) {
13240                     r[r.length] = items[i];
13241             }
13242         }
13243         return r;
13244     },
13245         
13246     /**
13247      * Filter the <i>objects</i> in this collection by a specific property. 
13248      * Returns a new collection that has been filtered.
13249      * @param {String} property A property on your objects
13250      * @param {String/RegExp} value Either string that the property values 
13251      * should start with or a RegExp to test against the property
13252      * @return {MixedCollection} The new filtered collection
13253      */
13254     filter : function(property, value){
13255         if(!value.exec){ // not a regex
13256             value = String(value);
13257             if(value.length == 0){
13258                 return this.clone();
13259             }
13260             value = new RegExp("^" + Roo.escapeRe(value), "i");
13261         }
13262         return this.filterBy(function(o){
13263             return o && value.test(o[property]);
13264         });
13265         },
13266     
13267     /**
13268      * Filter by a function. * Returns a new collection that has been filtered.
13269      * The passed function will be called with each 
13270      * object in the collection. If the function returns true, the value is included 
13271      * otherwise it is filtered.
13272      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13273      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13274      * @return {MixedCollection} The new filtered collection
13275      */
13276     filterBy : function(fn, scope){
13277         var r = new Roo.util.MixedCollection();
13278         r.getKey = this.getKey;
13279         var k = this.keys, it = this.items;
13280         for(var i = 0, len = it.length; i < len; i++){
13281             if(fn.call(scope||this, it[i], k[i])){
13282                                 r.add(k[i], it[i]);
13283                         }
13284         }
13285         return r;
13286     },
13287     
13288     /**
13289      * Creates a duplicate of this collection
13290      * @return {MixedCollection}
13291      */
13292     clone : function(){
13293         var r = new Roo.util.MixedCollection();
13294         var k = this.keys, it = this.items;
13295         for(var i = 0, len = it.length; i < len; i++){
13296             r.add(k[i], it[i]);
13297         }
13298         r.getKey = this.getKey;
13299         return r;
13300     }
13301 });
13302 /**
13303  * Returns the item associated with the passed key or index.
13304  * @method
13305  * @param {String/Number} key The key or index of the item.
13306  * @return {Object} The item associated with the passed key.
13307  */
13308 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13309  * Based on:
13310  * Ext JS Library 1.1.1
13311  * Copyright(c) 2006-2007, Ext JS, LLC.
13312  *
13313  * Originally Released Under LGPL - original licence link has changed is not relivant.
13314  *
13315  * Fork - LGPL
13316  * <script type="text/javascript">
13317  */
13318 /**
13319  * @class Roo.util.JSON
13320  * Modified version of Douglas Crockford"s json.js that doesn"t
13321  * mess with the Object prototype 
13322  * http://www.json.org/js.html
13323  * @singleton
13324  */
13325 Roo.util.JSON = new (function(){
13326     var useHasOwn = {}.hasOwnProperty ? true : false;
13327     
13328     // crashes Safari in some instances
13329     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13330     
13331     var pad = function(n) {
13332         return n < 10 ? "0" + n : n;
13333     };
13334     
13335     var m = {
13336         "\b": '\\b',
13337         "\t": '\\t',
13338         "\n": '\\n',
13339         "\f": '\\f',
13340         "\r": '\\r',
13341         '"' : '\\"',
13342         "\\": '\\\\'
13343     };
13344
13345     var encodeString = function(s){
13346         if (/["\\\x00-\x1f]/.test(s)) {
13347             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13348                 var c = m[b];
13349                 if(c){
13350                     return c;
13351                 }
13352                 c = b.charCodeAt();
13353                 return "\\u00" +
13354                     Math.floor(c / 16).toString(16) +
13355                     (c % 16).toString(16);
13356             }) + '"';
13357         }
13358         return '"' + s + '"';
13359     };
13360     
13361     var encodeArray = function(o){
13362         var a = ["["], b, i, l = o.length, v;
13363             for (i = 0; i < l; i += 1) {
13364                 v = o[i];
13365                 switch (typeof v) {
13366                     case "undefined":
13367                     case "function":
13368                     case "unknown":
13369                         break;
13370                     default:
13371                         if (b) {
13372                             a.push(',');
13373                         }
13374                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13375                         b = true;
13376                 }
13377             }
13378             a.push("]");
13379             return a.join("");
13380     };
13381     
13382     var encodeDate = function(o){
13383         return '"' + o.getFullYear() + "-" +
13384                 pad(o.getMonth() + 1) + "-" +
13385                 pad(o.getDate()) + "T" +
13386                 pad(o.getHours()) + ":" +
13387                 pad(o.getMinutes()) + ":" +
13388                 pad(o.getSeconds()) + '"';
13389     };
13390     
13391     /**
13392      * Encodes an Object, Array or other value
13393      * @param {Mixed} o The variable to encode
13394      * @return {String} The JSON string
13395      */
13396     this.encode = function(o)
13397     {
13398         // should this be extended to fully wrap stringify..
13399         
13400         if(typeof o == "undefined" || o === null){
13401             return "null";
13402         }else if(o instanceof Array){
13403             return encodeArray(o);
13404         }else if(o instanceof Date){
13405             return encodeDate(o);
13406         }else if(typeof o == "string"){
13407             return encodeString(o);
13408         }else if(typeof o == "number"){
13409             return isFinite(o) ? String(o) : "null";
13410         }else if(typeof o == "boolean"){
13411             return String(o);
13412         }else {
13413             var a = ["{"], b, i, v;
13414             for (i in o) {
13415                 if(!useHasOwn || o.hasOwnProperty(i)) {
13416                     v = o[i];
13417                     switch (typeof v) {
13418                     case "undefined":
13419                     case "function":
13420                     case "unknown":
13421                         break;
13422                     default:
13423                         if(b){
13424                             a.push(',');
13425                         }
13426                         a.push(this.encode(i), ":",
13427                                 v === null ? "null" : this.encode(v));
13428                         b = true;
13429                     }
13430                 }
13431             }
13432             a.push("}");
13433             return a.join("");
13434         }
13435     };
13436     
13437     /**
13438      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13439      * @param {String} json The JSON string
13440      * @return {Object} The resulting object
13441      */
13442     this.decode = function(json){
13443         
13444         return  /** eval:var:json */ eval("(" + json + ')');
13445     };
13446 })();
13447 /** 
13448  * Shorthand for {@link Roo.util.JSON#encode}
13449  * @member Roo encode 
13450  * @method */
13451 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13452 /** 
13453  * Shorthand for {@link Roo.util.JSON#decode}
13454  * @member Roo decode 
13455  * @method */
13456 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13457 /*
13458  * Based on:
13459  * Ext JS Library 1.1.1
13460  * Copyright(c) 2006-2007, Ext JS, LLC.
13461  *
13462  * Originally Released Under LGPL - original licence link has changed is not relivant.
13463  *
13464  * Fork - LGPL
13465  * <script type="text/javascript">
13466  */
13467  
13468 /**
13469  * @class Roo.util.Format
13470  * Reusable data formatting functions
13471  * @singleton
13472  */
13473 Roo.util.Format = function(){
13474     var trimRe = /^\s+|\s+$/g;
13475     return {
13476         /**
13477          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13478          * @param {String} value The string to truncate
13479          * @param {Number} length The maximum length to allow before truncating
13480          * @return {String} The converted text
13481          */
13482         ellipsis : function(value, len){
13483             if(value && value.length > len){
13484                 return value.substr(0, len-3)+"...";
13485             }
13486             return value;
13487         },
13488
13489         /**
13490          * Checks a reference and converts it to empty string if it is undefined
13491          * @param {Mixed} value Reference to check
13492          * @return {Mixed} Empty string if converted, otherwise the original value
13493          */
13494         undef : function(value){
13495             return typeof value != "undefined" ? value : "";
13496         },
13497
13498         /**
13499          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13500          * @param {String} value The string to encode
13501          * @return {String} The encoded text
13502          */
13503         htmlEncode : function(value){
13504             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13505         },
13506
13507         /**
13508          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13509          * @param {String} value The string to decode
13510          * @return {String} The decoded text
13511          */
13512         htmlDecode : function(value){
13513             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13514         },
13515
13516         /**
13517          * Trims any whitespace from either side of a string
13518          * @param {String} value The text to trim
13519          * @return {String} The trimmed text
13520          */
13521         trim : function(value){
13522             return String(value).replace(trimRe, "");
13523         },
13524
13525         /**
13526          * Returns a substring from within an original string
13527          * @param {String} value The original text
13528          * @param {Number} start The start index of the substring
13529          * @param {Number} length The length of the substring
13530          * @return {String} The substring
13531          */
13532         substr : function(value, start, length){
13533             return String(value).substr(start, length);
13534         },
13535
13536         /**
13537          * Converts a string to all lower case letters
13538          * @param {String} value The text to convert
13539          * @return {String} The converted text
13540          */
13541         lowercase : function(value){
13542             return String(value).toLowerCase();
13543         },
13544
13545         /**
13546          * Converts a string to all upper case letters
13547          * @param {String} value The text to convert
13548          * @return {String} The converted text
13549          */
13550         uppercase : function(value){
13551             return String(value).toUpperCase();
13552         },
13553
13554         /**
13555          * Converts the first character only of a string to upper case
13556          * @param {String} value The text to convert
13557          * @return {String} The converted text
13558          */
13559         capitalize : function(value){
13560             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13561         },
13562
13563         // private
13564         call : function(value, fn){
13565             if(arguments.length > 2){
13566                 var args = Array.prototype.slice.call(arguments, 2);
13567                 args.unshift(value);
13568                  
13569                 return /** eval:var:value */  eval(fn).apply(window, args);
13570             }else{
13571                 /** eval:var:value */
13572                 return /** eval:var:value */ eval(fn).call(window, value);
13573             }
13574         },
13575
13576        
13577         /**
13578          * safer version of Math.toFixed..??/
13579          * @param {Number/String} value The numeric value to format
13580          * @param {Number/String} value Decimal places 
13581          * @return {String} The formatted currency string
13582          */
13583         toFixed : function(v, n)
13584         {
13585             // why not use to fixed - precision is buggered???
13586             if (!n) {
13587                 return Math.round(v-0);
13588             }
13589             var fact = Math.pow(10,n+1);
13590             v = (Math.round((v-0)*fact))/fact;
13591             var z = (''+fact).substring(2);
13592             if (v == Math.floor(v)) {
13593                 return Math.floor(v) + '.' + z;
13594             }
13595             
13596             // now just padd decimals..
13597             var ps = String(v).split('.');
13598             var fd = (ps[1] + z);
13599             var r = fd.substring(0,n); 
13600             var rm = fd.substring(n); 
13601             if (rm < 5) {
13602                 return ps[0] + '.' + r;
13603             }
13604             r*=1; // turn it into a number;
13605             r++;
13606             if (String(r).length != n) {
13607                 ps[0]*=1;
13608                 ps[0]++;
13609                 r = String(r).substring(1); // chop the end off.
13610             }
13611             
13612             return ps[0] + '.' + r;
13613              
13614         },
13615         
13616         /**
13617          * Format a number as US currency
13618          * @param {Number/String} value The numeric value to format
13619          * @return {String} The formatted currency string
13620          */
13621         usMoney : function(v){
13622             return '$' + Roo.util.Format.number(v);
13623         },
13624         
13625         /**
13626          * Format a number
13627          * eventually this should probably emulate php's number_format
13628          * @param {Number/String} value The numeric value to format
13629          * @param {Number} decimals number of decimal places
13630          * @return {String} The formatted currency string
13631          */
13632         number : function(v,decimals)
13633         {
13634             // multiply and round.
13635             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13636             var mul = Math.pow(10, decimals);
13637             var zero = String(mul).substring(1);
13638             v = (Math.round((v-0)*mul))/mul;
13639             
13640             // if it's '0' number.. then
13641             
13642             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13643             v = String(v);
13644             var ps = v.split('.');
13645             var whole = ps[0];
13646             
13647             
13648             var r = /(\d+)(\d{3})/;
13649             // add comma's
13650             while (r.test(whole)) {
13651                 whole = whole.replace(r, '$1' + ',' + '$2');
13652             }
13653             
13654             
13655             var sub = ps[1] ?
13656                     // has decimals..
13657                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13658                     // does not have decimals
13659                     (decimals ? ('.' + zero) : '');
13660             
13661             
13662             return whole + sub ;
13663         },
13664         
13665         /**
13666          * Parse a value into a formatted date using the specified format pattern.
13667          * @param {Mixed} value The value to format
13668          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13669          * @return {String} The formatted date string
13670          */
13671         date : function(v, format){
13672             if(!v){
13673                 return "";
13674             }
13675             if(!(v instanceof Date)){
13676                 v = new Date(Date.parse(v));
13677             }
13678             return v.dateFormat(format || Roo.util.Format.defaults.date);
13679         },
13680
13681         /**
13682          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13683          * @param {String} format Any valid date format string
13684          * @return {Function} The date formatting function
13685          */
13686         dateRenderer : function(format){
13687             return function(v){
13688                 return Roo.util.Format.date(v, format);  
13689             };
13690         },
13691
13692         // private
13693         stripTagsRE : /<\/?[^>]+>/gi,
13694         
13695         /**
13696          * Strips all HTML tags
13697          * @param {Mixed} value The text from which to strip tags
13698          * @return {String} The stripped text
13699          */
13700         stripTags : function(v){
13701             return !v ? v : String(v).replace(this.stripTagsRE, "");
13702         }
13703     };
13704 }();
13705 Roo.util.Format.defaults = {
13706     date : 'd/M/Y'
13707 };/*
13708  * Based on:
13709  * Ext JS Library 1.1.1
13710  * Copyright(c) 2006-2007, Ext JS, LLC.
13711  *
13712  * Originally Released Under LGPL - original licence link has changed is not relivant.
13713  *
13714  * Fork - LGPL
13715  * <script type="text/javascript">
13716  */
13717
13718
13719  
13720
13721 /**
13722  * @class Roo.MasterTemplate
13723  * @extends Roo.Template
13724  * Provides a template that can have child templates. The syntax is:
13725 <pre><code>
13726 var t = new Roo.MasterTemplate(
13727         '&lt;select name="{name}"&gt;',
13728                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13729         '&lt;/select&gt;'
13730 );
13731 t.add('options', {value: 'foo', text: 'bar'});
13732 // or you can add multiple child elements in one shot
13733 t.addAll('options', [
13734     {value: 'foo', text: 'bar'},
13735     {value: 'foo2', text: 'bar2'},
13736     {value: 'foo3', text: 'bar3'}
13737 ]);
13738 // then append, applying the master template values
13739 t.append('my-form', {name: 'my-select'});
13740 </code></pre>
13741 * A name attribute for the child template is not required if you have only one child
13742 * template or you want to refer to them by index.
13743  */
13744 Roo.MasterTemplate = function(){
13745     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13746     this.originalHtml = this.html;
13747     var st = {};
13748     var m, re = this.subTemplateRe;
13749     re.lastIndex = 0;
13750     var subIndex = 0;
13751     while(m = re.exec(this.html)){
13752         var name = m[1], content = m[2];
13753         st[subIndex] = {
13754             name: name,
13755             index: subIndex,
13756             buffer: [],
13757             tpl : new Roo.Template(content)
13758         };
13759         if(name){
13760             st[name] = st[subIndex];
13761         }
13762         st[subIndex].tpl.compile();
13763         st[subIndex].tpl.call = this.call.createDelegate(this);
13764         subIndex++;
13765     }
13766     this.subCount = subIndex;
13767     this.subs = st;
13768 };
13769 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13770     /**
13771     * The regular expression used to match sub templates
13772     * @type RegExp
13773     * @property
13774     */
13775     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13776
13777     /**
13778      * Applies the passed values to a child template.
13779      * @param {String/Number} name (optional) The name or index of the child template
13780      * @param {Array/Object} values The values to be applied to the template
13781      * @return {MasterTemplate} this
13782      */
13783      add : function(name, values){
13784         if(arguments.length == 1){
13785             values = arguments[0];
13786             name = 0;
13787         }
13788         var s = this.subs[name];
13789         s.buffer[s.buffer.length] = s.tpl.apply(values);
13790         return this;
13791     },
13792
13793     /**
13794      * Applies all the passed values to a child template.
13795      * @param {String/Number} name (optional) The name or index of the child template
13796      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13797      * @param {Boolean} reset (optional) True to reset the template first
13798      * @return {MasterTemplate} this
13799      */
13800     fill : function(name, values, reset){
13801         var a = arguments;
13802         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13803             values = a[0];
13804             name = 0;
13805             reset = a[1];
13806         }
13807         if(reset){
13808             this.reset();
13809         }
13810         for(var i = 0, len = values.length; i < len; i++){
13811             this.add(name, values[i]);
13812         }
13813         return this;
13814     },
13815
13816     /**
13817      * Resets the template for reuse
13818      * @return {MasterTemplate} this
13819      */
13820      reset : function(){
13821         var s = this.subs;
13822         for(var i = 0; i < this.subCount; i++){
13823             s[i].buffer = [];
13824         }
13825         return this;
13826     },
13827
13828     applyTemplate : function(values){
13829         var s = this.subs;
13830         var replaceIndex = -1;
13831         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13832             return s[++replaceIndex].buffer.join("");
13833         });
13834         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13835     },
13836
13837     apply : function(){
13838         return this.applyTemplate.apply(this, arguments);
13839     },
13840
13841     compile : function(){return this;}
13842 });
13843
13844 /**
13845  * Alias for fill().
13846  * @method
13847  */
13848 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13849  /**
13850  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13851  * var tpl = Roo.MasterTemplate.from('element-id');
13852  * @param {String/HTMLElement} el
13853  * @param {Object} config
13854  * @static
13855  */
13856 Roo.MasterTemplate.from = function(el, config){
13857     el = Roo.getDom(el);
13858     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13859 };/*
13860  * Based on:
13861  * Ext JS Library 1.1.1
13862  * Copyright(c) 2006-2007, Ext JS, LLC.
13863  *
13864  * Originally Released Under LGPL - original licence link has changed is not relivant.
13865  *
13866  * Fork - LGPL
13867  * <script type="text/javascript">
13868  */
13869
13870  
13871 /**
13872  * @class Roo.util.CSS
13873  * Utility class for manipulating CSS rules
13874  * @singleton
13875  */
13876 Roo.util.CSS = function(){
13877         var rules = null;
13878         var doc = document;
13879
13880     var camelRe = /(-[a-z])/gi;
13881     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13882
13883    return {
13884    /**
13885     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13886     * tag and appended to the HEAD of the document.
13887     * @param {String|Object} cssText The text containing the css rules
13888     * @param {String} id An id to add to the stylesheet for later removal
13889     * @return {StyleSheet}
13890     */
13891     createStyleSheet : function(cssText, id){
13892         var ss;
13893         var head = doc.getElementsByTagName("head")[0];
13894         var nrules = doc.createElement("style");
13895         nrules.setAttribute("type", "text/css");
13896         if(id){
13897             nrules.setAttribute("id", id);
13898         }
13899         if (typeof(cssText) != 'string') {
13900             // support object maps..
13901             // not sure if this a good idea.. 
13902             // perhaps it should be merged with the general css handling
13903             // and handle js style props.
13904             var cssTextNew = [];
13905             for(var n in cssText) {
13906                 var citems = [];
13907                 for(var k in cssText[n]) {
13908                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13909                 }
13910                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13911                 
13912             }
13913             cssText = cssTextNew.join("\n");
13914             
13915         }
13916        
13917        
13918        if(Roo.isIE){
13919            head.appendChild(nrules);
13920            ss = nrules.styleSheet;
13921            ss.cssText = cssText;
13922        }else{
13923            try{
13924                 nrules.appendChild(doc.createTextNode(cssText));
13925            }catch(e){
13926                nrules.cssText = cssText; 
13927            }
13928            head.appendChild(nrules);
13929            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13930        }
13931        this.cacheStyleSheet(ss);
13932        return ss;
13933    },
13934
13935    /**
13936     * Removes a style or link tag by id
13937     * @param {String} id The id of the tag
13938     */
13939    removeStyleSheet : function(id){
13940        var existing = doc.getElementById(id);
13941        if(existing){
13942            existing.parentNode.removeChild(existing);
13943        }
13944    },
13945
13946    /**
13947     * Dynamically swaps an existing stylesheet reference for a new one
13948     * @param {String} id The id of an existing link tag to remove
13949     * @param {String} url The href of the new stylesheet to include
13950     */
13951    swapStyleSheet : function(id, url){
13952        this.removeStyleSheet(id);
13953        var ss = doc.createElement("link");
13954        ss.setAttribute("rel", "stylesheet");
13955        ss.setAttribute("type", "text/css");
13956        ss.setAttribute("id", id);
13957        ss.setAttribute("href", url);
13958        doc.getElementsByTagName("head")[0].appendChild(ss);
13959    },
13960    
13961    /**
13962     * Refresh the rule cache if you have dynamically added stylesheets
13963     * @return {Object} An object (hash) of rules indexed by selector
13964     */
13965    refreshCache : function(){
13966        return this.getRules(true);
13967    },
13968
13969    // private
13970    cacheStyleSheet : function(stylesheet){
13971        if(!rules){
13972            rules = {};
13973        }
13974        try{// try catch for cross domain access issue
13975            var ssRules = stylesheet.cssRules || stylesheet.rules;
13976            for(var j = ssRules.length-1; j >= 0; --j){
13977                rules[ssRules[j].selectorText] = ssRules[j];
13978            }
13979        }catch(e){}
13980    },
13981    
13982    /**
13983     * Gets all css rules for the document
13984     * @param {Boolean} refreshCache true to refresh the internal cache
13985     * @return {Object} An object (hash) of rules indexed by selector
13986     */
13987    getRules : function(refreshCache){
13988                 if(rules == null || refreshCache){
13989                         rules = {};
13990                         var ds = doc.styleSheets;
13991                         for(var i =0, len = ds.length; i < len; i++){
13992                             try{
13993                         this.cacheStyleSheet(ds[i]);
13994                     }catch(e){} 
13995                 }
13996                 }
13997                 return rules;
13998         },
13999         
14000         /**
14001     * Gets an an individual CSS rule by selector(s)
14002     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14003     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14004     * @return {CSSRule} The CSS rule or null if one is not found
14005     */
14006    getRule : function(selector, refreshCache){
14007                 var rs = this.getRules(refreshCache);
14008                 if(!(selector instanceof Array)){
14009                     return rs[selector];
14010                 }
14011                 for(var i = 0; i < selector.length; i++){
14012                         if(rs[selector[i]]){
14013                                 return rs[selector[i]];
14014                         }
14015                 }
14016                 return null;
14017         },
14018         
14019         
14020         /**
14021     * Updates a rule property
14022     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14023     * @param {String} property The css property
14024     * @param {String} value The new value for the property
14025     * @return {Boolean} true If a rule was found and updated
14026     */
14027    updateRule : function(selector, property, value){
14028                 if(!(selector instanceof Array)){
14029                         var rule = this.getRule(selector);
14030                         if(rule){
14031                                 rule.style[property.replace(camelRe, camelFn)] = value;
14032                                 return true;
14033                         }
14034                 }else{
14035                         for(var i = 0; i < selector.length; i++){
14036                                 if(this.updateRule(selector[i], property, value)){
14037                                         return true;
14038                                 }
14039                         }
14040                 }
14041                 return false;
14042         }
14043    };   
14044 }();/*
14045  * Based on:
14046  * Ext JS Library 1.1.1
14047  * Copyright(c) 2006-2007, Ext JS, LLC.
14048  *
14049  * Originally Released Under LGPL - original licence link has changed is not relivant.
14050  *
14051  * Fork - LGPL
14052  * <script type="text/javascript">
14053  */
14054
14055  
14056
14057 /**
14058  * @class Roo.util.ClickRepeater
14059  * @extends Roo.util.Observable
14060  * 
14061  * A wrapper class which can be applied to any element. Fires a "click" event while the
14062  * mouse is pressed. The interval between firings may be specified in the config but
14063  * defaults to 10 milliseconds.
14064  * 
14065  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14066  * 
14067  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14068  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14069  * Similar to an autorepeat key delay.
14070  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14071  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14072  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14073  *           "interval" and "delay" are ignored. "immediate" is honored.
14074  * @cfg {Boolean} preventDefault True to prevent the default click event
14075  * @cfg {Boolean} stopDefault True to stop the default click event
14076  * 
14077  * @history
14078  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14079  *     2007-02-02 jvs Renamed to ClickRepeater
14080  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14081  *
14082  *  @constructor
14083  * @param {String/HTMLElement/Element} el The element to listen on
14084  * @param {Object} config
14085  **/
14086 Roo.util.ClickRepeater = function(el, config)
14087 {
14088     this.el = Roo.get(el);
14089     this.el.unselectable();
14090
14091     Roo.apply(this, config);
14092
14093     this.addEvents({
14094     /**
14095      * @event mousedown
14096      * Fires when the mouse button is depressed.
14097      * @param {Roo.util.ClickRepeater} this
14098      */
14099         "mousedown" : true,
14100     /**
14101      * @event click
14102      * Fires on a specified interval during the time the element is pressed.
14103      * @param {Roo.util.ClickRepeater} this
14104      */
14105         "click" : true,
14106     /**
14107      * @event mouseup
14108      * Fires when the mouse key is released.
14109      * @param {Roo.util.ClickRepeater} this
14110      */
14111         "mouseup" : true
14112     });
14113
14114     this.el.on("mousedown", this.handleMouseDown, this);
14115     if(this.preventDefault || this.stopDefault){
14116         this.el.on("click", function(e){
14117             if(this.preventDefault){
14118                 e.preventDefault();
14119             }
14120             if(this.stopDefault){
14121                 e.stopEvent();
14122             }
14123         }, this);
14124     }
14125
14126     // allow inline handler
14127     if(this.handler){
14128         this.on("click", this.handler,  this.scope || this);
14129     }
14130
14131     Roo.util.ClickRepeater.superclass.constructor.call(this);
14132 };
14133
14134 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14135     interval : 20,
14136     delay: 250,
14137     preventDefault : true,
14138     stopDefault : false,
14139     timer : 0,
14140
14141     // private
14142     handleMouseDown : function(){
14143         clearTimeout(this.timer);
14144         this.el.blur();
14145         if(this.pressClass){
14146             this.el.addClass(this.pressClass);
14147         }
14148         this.mousedownTime = new Date();
14149
14150         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14151         this.el.on("mouseout", this.handleMouseOut, this);
14152
14153         this.fireEvent("mousedown", this);
14154         this.fireEvent("click", this);
14155         
14156         this.timer = this.click.defer(this.delay || this.interval, this);
14157     },
14158
14159     // private
14160     click : function(){
14161         this.fireEvent("click", this);
14162         this.timer = this.click.defer(this.getInterval(), this);
14163     },
14164
14165     // private
14166     getInterval: function(){
14167         if(!this.accelerate){
14168             return this.interval;
14169         }
14170         var pressTime = this.mousedownTime.getElapsed();
14171         if(pressTime < 500){
14172             return 400;
14173         }else if(pressTime < 1700){
14174             return 320;
14175         }else if(pressTime < 2600){
14176             return 250;
14177         }else if(pressTime < 3500){
14178             return 180;
14179         }else if(pressTime < 4400){
14180             return 140;
14181         }else if(pressTime < 5300){
14182             return 80;
14183         }else if(pressTime < 6200){
14184             return 50;
14185         }else{
14186             return 10;
14187         }
14188     },
14189
14190     // private
14191     handleMouseOut : function(){
14192         clearTimeout(this.timer);
14193         if(this.pressClass){
14194             this.el.removeClass(this.pressClass);
14195         }
14196         this.el.on("mouseover", this.handleMouseReturn, this);
14197     },
14198
14199     // private
14200     handleMouseReturn : function(){
14201         this.el.un("mouseover", this.handleMouseReturn);
14202         if(this.pressClass){
14203             this.el.addClass(this.pressClass);
14204         }
14205         this.click();
14206     },
14207
14208     // private
14209     handleMouseUp : function(){
14210         clearTimeout(this.timer);
14211         this.el.un("mouseover", this.handleMouseReturn);
14212         this.el.un("mouseout", this.handleMouseOut);
14213         Roo.get(document).un("mouseup", this.handleMouseUp);
14214         this.el.removeClass(this.pressClass);
14215         this.fireEvent("mouseup", this);
14216     }
14217 });/*
14218  * Based on:
14219  * Ext JS Library 1.1.1
14220  * Copyright(c) 2006-2007, Ext JS, LLC.
14221  *
14222  * Originally Released Under LGPL - original licence link has changed is not relivant.
14223  *
14224  * Fork - LGPL
14225  * <script type="text/javascript">
14226  */
14227
14228  
14229 /**
14230  * @class Roo.KeyNav
14231  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14232  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14233  * way to implement custom navigation schemes for any UI component.</p>
14234  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14235  * pageUp, pageDown, del, home, end.  Usage:</p>
14236  <pre><code>
14237 var nav = new Roo.KeyNav("my-element", {
14238     "left" : function(e){
14239         this.moveLeft(e.ctrlKey);
14240     },
14241     "right" : function(e){
14242         this.moveRight(e.ctrlKey);
14243     },
14244     "enter" : function(e){
14245         this.save();
14246     },
14247     scope : this
14248 });
14249 </code></pre>
14250  * @constructor
14251  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14252  * @param {Object} config The config
14253  */
14254 Roo.KeyNav = function(el, config){
14255     this.el = Roo.get(el);
14256     Roo.apply(this, config);
14257     if(!this.disabled){
14258         this.disabled = true;
14259         this.enable();
14260     }
14261 };
14262
14263 Roo.KeyNav.prototype = {
14264     /**
14265      * @cfg {Boolean} disabled
14266      * True to disable this KeyNav instance (defaults to false)
14267      */
14268     disabled : false,
14269     /**
14270      * @cfg {String} defaultEventAction
14271      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14272      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14273      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14274      */
14275     defaultEventAction: "stopEvent",
14276     /**
14277      * @cfg {Boolean} forceKeyDown
14278      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14279      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14280      * handle keydown instead of keypress.
14281      */
14282     forceKeyDown : false,
14283
14284     // private
14285     prepareEvent : function(e){
14286         var k = e.getKey();
14287         var h = this.keyToHandler[k];
14288         //if(h && this[h]){
14289         //    e.stopPropagation();
14290         //}
14291         if(Roo.isSafari && h && k >= 37 && k <= 40){
14292             e.stopEvent();
14293         }
14294     },
14295
14296     // private
14297     relay : function(e){
14298         var k = e.getKey();
14299         var h = this.keyToHandler[k];
14300         if(h && this[h]){
14301             if(this.doRelay(e, this[h], h) !== true){
14302                 e[this.defaultEventAction]();
14303             }
14304         }
14305     },
14306
14307     // private
14308     doRelay : function(e, h, hname){
14309         return h.call(this.scope || this, e);
14310     },
14311
14312     // possible handlers
14313     enter : false,
14314     left : false,
14315     right : false,
14316     up : false,
14317     down : false,
14318     tab : false,
14319     esc : false,
14320     pageUp : false,
14321     pageDown : false,
14322     del : false,
14323     home : false,
14324     end : false,
14325
14326     // quick lookup hash
14327     keyToHandler : {
14328         37 : "left",
14329         39 : "right",
14330         38 : "up",
14331         40 : "down",
14332         33 : "pageUp",
14333         34 : "pageDown",
14334         46 : "del",
14335         36 : "home",
14336         35 : "end",
14337         13 : "enter",
14338         27 : "esc",
14339         9  : "tab"
14340     },
14341
14342         /**
14343          * Enable this KeyNav
14344          */
14345         enable: function(){
14346                 if(this.disabled){
14347             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14348             // the EventObject will normalize Safari automatically
14349             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14350                 this.el.on("keydown", this.relay,  this);
14351             }else{
14352                 this.el.on("keydown", this.prepareEvent,  this);
14353                 this.el.on("keypress", this.relay,  this);
14354             }
14355                     this.disabled = false;
14356                 }
14357         },
14358
14359         /**
14360          * Disable this KeyNav
14361          */
14362         disable: function(){
14363                 if(!this.disabled){
14364                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14365                 this.el.un("keydown", this.relay);
14366             }else{
14367                 this.el.un("keydown", this.prepareEvent);
14368                 this.el.un("keypress", this.relay);
14369             }
14370                     this.disabled = true;
14371                 }
14372         }
14373 };/*
14374  * Based on:
14375  * Ext JS Library 1.1.1
14376  * Copyright(c) 2006-2007, Ext JS, LLC.
14377  *
14378  * Originally Released Under LGPL - original licence link has changed is not relivant.
14379  *
14380  * Fork - LGPL
14381  * <script type="text/javascript">
14382  */
14383
14384  
14385 /**
14386  * @class Roo.KeyMap
14387  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14388  * The constructor accepts the same config object as defined by {@link #addBinding}.
14389  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14390  * combination it will call the function with this signature (if the match is a multi-key
14391  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14392  * A KeyMap can also handle a string representation of keys.<br />
14393  * Usage:
14394  <pre><code>
14395 // map one key by key code
14396 var map = new Roo.KeyMap("my-element", {
14397     key: 13, // or Roo.EventObject.ENTER
14398     fn: myHandler,
14399     scope: myObject
14400 });
14401
14402 // map multiple keys to one action by string
14403 var map = new Roo.KeyMap("my-element", {
14404     key: "a\r\n\t",
14405     fn: myHandler,
14406     scope: myObject
14407 });
14408
14409 // map multiple keys to multiple actions by strings and array of codes
14410 var map = new Roo.KeyMap("my-element", [
14411     {
14412         key: [10,13],
14413         fn: function(){ alert("Return was pressed"); }
14414     }, {
14415         key: "abc",
14416         fn: function(){ alert('a, b or c was pressed'); }
14417     }, {
14418         key: "\t",
14419         ctrl:true,
14420         shift:true,
14421         fn: function(){ alert('Control + shift + tab was pressed.'); }
14422     }
14423 ]);
14424 </code></pre>
14425  * <b>Note: A KeyMap starts enabled</b>
14426  * @constructor
14427  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14428  * @param {Object} config The config (see {@link #addBinding})
14429  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14430  */
14431 Roo.KeyMap = function(el, config, eventName){
14432     this.el  = Roo.get(el);
14433     this.eventName = eventName || "keydown";
14434     this.bindings = [];
14435     if(config){
14436         this.addBinding(config);
14437     }
14438     this.enable();
14439 };
14440
14441 Roo.KeyMap.prototype = {
14442     /**
14443      * True to stop the event from bubbling and prevent the default browser action if the
14444      * key was handled by the KeyMap (defaults to false)
14445      * @type Boolean
14446      */
14447     stopEvent : false,
14448
14449     /**
14450      * Add a new binding to this KeyMap. The following config object properties are supported:
14451      * <pre>
14452 Property    Type             Description
14453 ----------  ---------------  ----------------------------------------------------------------------
14454 key         String/Array     A single keycode or an array of keycodes to handle
14455 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14456 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14457 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14458 fn          Function         The function to call when KeyMap finds the expected key combination
14459 scope       Object           The scope of the callback function
14460 </pre>
14461      *
14462      * Usage:
14463      * <pre><code>
14464 // Create a KeyMap
14465 var map = new Roo.KeyMap(document, {
14466     key: Roo.EventObject.ENTER,
14467     fn: handleKey,
14468     scope: this
14469 });
14470
14471 //Add a new binding to the existing KeyMap later
14472 map.addBinding({
14473     key: 'abc',
14474     shift: true,
14475     fn: handleKey,
14476     scope: this
14477 });
14478 </code></pre>
14479      * @param {Object/Array} config A single KeyMap config or an array of configs
14480      */
14481         addBinding : function(config){
14482         if(config instanceof Array){
14483             for(var i = 0, len = config.length; i < len; i++){
14484                 this.addBinding(config[i]);
14485             }
14486             return;
14487         }
14488         var keyCode = config.key,
14489             shift = config.shift, 
14490             ctrl = config.ctrl, 
14491             alt = config.alt,
14492             fn = config.fn,
14493             scope = config.scope;
14494         if(typeof keyCode == "string"){
14495             var ks = [];
14496             var keyString = keyCode.toUpperCase();
14497             for(var j = 0, len = keyString.length; j < len; j++){
14498                 ks.push(keyString.charCodeAt(j));
14499             }
14500             keyCode = ks;
14501         }
14502         var keyArray = keyCode instanceof Array;
14503         var handler = function(e){
14504             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14505                 var k = e.getKey();
14506                 if(keyArray){
14507                     for(var i = 0, len = keyCode.length; i < len; i++){
14508                         if(keyCode[i] == k){
14509                           if(this.stopEvent){
14510                               e.stopEvent();
14511                           }
14512                           fn.call(scope || window, k, e);
14513                           return;
14514                         }
14515                     }
14516                 }else{
14517                     if(k == keyCode){
14518                         if(this.stopEvent){
14519                            e.stopEvent();
14520                         }
14521                         fn.call(scope || window, k, e);
14522                     }
14523                 }
14524             }
14525         };
14526         this.bindings.push(handler);  
14527         },
14528
14529     /**
14530      * Shorthand for adding a single key listener
14531      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14532      * following options:
14533      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14534      * @param {Function} fn The function to call
14535      * @param {Object} scope (optional) The scope of the function
14536      */
14537     on : function(key, fn, scope){
14538         var keyCode, shift, ctrl, alt;
14539         if(typeof key == "object" && !(key instanceof Array)){
14540             keyCode = key.key;
14541             shift = key.shift;
14542             ctrl = key.ctrl;
14543             alt = key.alt;
14544         }else{
14545             keyCode = key;
14546         }
14547         this.addBinding({
14548             key: keyCode,
14549             shift: shift,
14550             ctrl: ctrl,
14551             alt: alt,
14552             fn: fn,
14553             scope: scope
14554         })
14555     },
14556
14557     // private
14558     handleKeyDown : function(e){
14559             if(this.enabled){ //just in case
14560             var b = this.bindings;
14561             for(var i = 0, len = b.length; i < len; i++){
14562                 b[i].call(this, e);
14563             }
14564             }
14565         },
14566         
14567         /**
14568          * Returns true if this KeyMap is enabled
14569          * @return {Boolean} 
14570          */
14571         isEnabled : function(){
14572             return this.enabled;  
14573         },
14574         
14575         /**
14576          * Enables this KeyMap
14577          */
14578         enable: function(){
14579                 if(!this.enabled){
14580                     this.el.on(this.eventName, this.handleKeyDown, this);
14581                     this.enabled = true;
14582                 }
14583         },
14584
14585         /**
14586          * Disable this KeyMap
14587          */
14588         disable: function(){
14589                 if(this.enabled){
14590                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14591                     this.enabled = false;
14592                 }
14593         }
14594 };/*
14595  * Based on:
14596  * Ext JS Library 1.1.1
14597  * Copyright(c) 2006-2007, Ext JS, LLC.
14598  *
14599  * Originally Released Under LGPL - original licence link has changed is not relivant.
14600  *
14601  * Fork - LGPL
14602  * <script type="text/javascript">
14603  */
14604
14605  
14606 /**
14607  * @class Roo.util.TextMetrics
14608  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14609  * wide, in pixels, a given block of text will be.
14610  * @singleton
14611  */
14612 Roo.util.TextMetrics = function(){
14613     var shared;
14614     return {
14615         /**
14616          * Measures the size of the specified text
14617          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14618          * that can affect the size of the rendered text
14619          * @param {String} text The text to measure
14620          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14621          * in order to accurately measure the text height
14622          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14623          */
14624         measure : function(el, text, fixedWidth){
14625             if(!shared){
14626                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14627             }
14628             shared.bind(el);
14629             shared.setFixedWidth(fixedWidth || 'auto');
14630             return shared.getSize(text);
14631         },
14632
14633         /**
14634          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14635          * the overhead of multiple calls to initialize the style properties on each measurement.
14636          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14637          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14638          * in order to accurately measure the text height
14639          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14640          */
14641         createInstance : function(el, fixedWidth){
14642             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14643         }
14644     };
14645 }();
14646
14647  
14648
14649 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14650     var ml = new Roo.Element(document.createElement('div'));
14651     document.body.appendChild(ml.dom);
14652     ml.position('absolute');
14653     ml.setLeftTop(-1000, -1000);
14654     ml.hide();
14655
14656     if(fixedWidth){
14657         ml.setWidth(fixedWidth);
14658     }
14659      
14660     var instance = {
14661         /**
14662          * Returns the size of the specified text based on the internal element's style and width properties
14663          * @memberOf Roo.util.TextMetrics.Instance#
14664          * @param {String} text The text to measure
14665          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14666          */
14667         getSize : function(text){
14668             ml.update(text);
14669             var s = ml.getSize();
14670             ml.update('');
14671             return s;
14672         },
14673
14674         /**
14675          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14676          * that can affect the size of the rendered text
14677          * @memberOf Roo.util.TextMetrics.Instance#
14678          * @param {String/HTMLElement} el The element, dom node or id
14679          */
14680         bind : function(el){
14681             ml.setStyle(
14682                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14683             );
14684         },
14685
14686         /**
14687          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14688          * to set a fixed width in order to accurately measure the text height.
14689          * @memberOf Roo.util.TextMetrics.Instance#
14690          * @param {Number} width The width to set on the element
14691          */
14692         setFixedWidth : function(width){
14693             ml.setWidth(width);
14694         },
14695
14696         /**
14697          * Returns the measured width of the specified text
14698          * @memberOf Roo.util.TextMetrics.Instance#
14699          * @param {String} text The text to measure
14700          * @return {Number} width The width in pixels
14701          */
14702         getWidth : function(text){
14703             ml.dom.style.width = 'auto';
14704             return this.getSize(text).width;
14705         },
14706
14707         /**
14708          * Returns the measured height of the specified text.  For multiline text, be sure to call
14709          * {@link #setFixedWidth} if necessary.
14710          * @memberOf Roo.util.TextMetrics.Instance#
14711          * @param {String} text The text to measure
14712          * @return {Number} height The height in pixels
14713          */
14714         getHeight : function(text){
14715             return this.getSize(text).height;
14716         }
14717     };
14718
14719     instance.bind(bindTo);
14720
14721     return instance;
14722 };
14723
14724 // backwards compat
14725 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14726  * Based on:
14727  * Ext JS Library 1.1.1
14728  * Copyright(c) 2006-2007, Ext JS, LLC.
14729  *
14730  * Originally Released Under LGPL - original licence link has changed is not relivant.
14731  *
14732  * Fork - LGPL
14733  * <script type="text/javascript">
14734  */
14735
14736 /**
14737  * @class Roo.state.Provider
14738  * Abstract base class for state provider implementations. This class provides methods
14739  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14740  * Provider interface.
14741  */
14742 Roo.state.Provider = function(){
14743     /**
14744      * @event statechange
14745      * Fires when a state change occurs.
14746      * @param {Provider} this This state provider
14747      * @param {String} key The state key which was changed
14748      * @param {String} value The encoded value for the state
14749      */
14750     this.addEvents({
14751         "statechange": true
14752     });
14753     this.state = {};
14754     Roo.state.Provider.superclass.constructor.call(this);
14755 };
14756 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14757     /**
14758      * Returns the current value for a key
14759      * @param {String} name The key name
14760      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14761      * @return {Mixed} The state data
14762      */
14763     get : function(name, defaultValue){
14764         return typeof this.state[name] == "undefined" ?
14765             defaultValue : this.state[name];
14766     },
14767     
14768     /**
14769      * Clears a value from the state
14770      * @param {String} name The key name
14771      */
14772     clear : function(name){
14773         delete this.state[name];
14774         this.fireEvent("statechange", this, name, null);
14775     },
14776     
14777     /**
14778      * Sets the value for a key
14779      * @param {String} name The key name
14780      * @param {Mixed} value The value to set
14781      */
14782     set : function(name, value){
14783         this.state[name] = value;
14784         this.fireEvent("statechange", this, name, value);
14785     },
14786     
14787     /**
14788      * Decodes a string previously encoded with {@link #encodeValue}.
14789      * @param {String} value The value to decode
14790      * @return {Mixed} The decoded value
14791      */
14792     decodeValue : function(cookie){
14793         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14794         var matches = re.exec(unescape(cookie));
14795         if(!matches || !matches[1]) return; // non state cookie
14796         var type = matches[1];
14797         var v = matches[2];
14798         switch(type){
14799             case "n":
14800                 return parseFloat(v);
14801             case "d":
14802                 return new Date(Date.parse(v));
14803             case "b":
14804                 return (v == "1");
14805             case "a":
14806                 var all = [];
14807                 var values = v.split("^");
14808                 for(var i = 0, len = values.length; i < len; i++){
14809                     all.push(this.decodeValue(values[i]));
14810                 }
14811                 return all;
14812            case "o":
14813                 var all = {};
14814                 var values = v.split("^");
14815                 for(var i = 0, len = values.length; i < len; i++){
14816                     var kv = values[i].split("=");
14817                     all[kv[0]] = this.decodeValue(kv[1]);
14818                 }
14819                 return all;
14820            default:
14821                 return v;
14822         }
14823     },
14824     
14825     /**
14826      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14827      * @param {Mixed} value The value to encode
14828      * @return {String} The encoded value
14829      */
14830     encodeValue : function(v){
14831         var enc;
14832         if(typeof v == "number"){
14833             enc = "n:" + v;
14834         }else if(typeof v == "boolean"){
14835             enc = "b:" + (v ? "1" : "0");
14836         }else if(v instanceof Date){
14837             enc = "d:" + v.toGMTString();
14838         }else if(v instanceof Array){
14839             var flat = "";
14840             for(var i = 0, len = v.length; i < len; i++){
14841                 flat += this.encodeValue(v[i]);
14842                 if(i != len-1) flat += "^";
14843             }
14844             enc = "a:" + flat;
14845         }else if(typeof v == "object"){
14846             var flat = "";
14847             for(var key in v){
14848                 if(typeof v[key] != "function"){
14849                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14850                 }
14851             }
14852             enc = "o:" + flat.substring(0, flat.length-1);
14853         }else{
14854             enc = "s:" + v;
14855         }
14856         return escape(enc);        
14857     }
14858 });
14859
14860 /*
14861  * Based on:
14862  * Ext JS Library 1.1.1
14863  * Copyright(c) 2006-2007, Ext JS, LLC.
14864  *
14865  * Originally Released Under LGPL - original licence link has changed is not relivant.
14866  *
14867  * Fork - LGPL
14868  * <script type="text/javascript">
14869  */
14870 /**
14871  * @class Roo.state.Manager
14872  * This is the global state manager. By default all components that are "state aware" check this class
14873  * for state information if you don't pass them a custom state provider. In order for this class
14874  * to be useful, it must be initialized with a provider when your application initializes.
14875  <pre><code>
14876 // in your initialization function
14877 init : function(){
14878    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14879    ...
14880    // supposed you have a {@link Roo.BorderLayout}
14881    var layout = new Roo.BorderLayout(...);
14882    layout.restoreState();
14883    // or a {Roo.BasicDialog}
14884    var dialog = new Roo.BasicDialog(...);
14885    dialog.restoreState();
14886  </code></pre>
14887  * @singleton
14888  */
14889 Roo.state.Manager = function(){
14890     var provider = new Roo.state.Provider();
14891     
14892     return {
14893         /**
14894          * Configures the default state provider for your application
14895          * @param {Provider} stateProvider The state provider to set
14896          */
14897         setProvider : function(stateProvider){
14898             provider = stateProvider;
14899         },
14900         
14901         /**
14902          * Returns the current value for a key
14903          * @param {String} name The key name
14904          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14905          * @return {Mixed} The state data
14906          */
14907         get : function(key, defaultValue){
14908             return provider.get(key, defaultValue);
14909         },
14910         
14911         /**
14912          * Sets the value for a key
14913          * @param {String} name The key name
14914          * @param {Mixed} value The state data
14915          */
14916          set : function(key, value){
14917             provider.set(key, value);
14918         },
14919         
14920         /**
14921          * Clears a value from the state
14922          * @param {String} name The key name
14923          */
14924         clear : function(key){
14925             provider.clear(key);
14926         },
14927         
14928         /**
14929          * Gets the currently configured state provider
14930          * @return {Provider} The state provider
14931          */
14932         getProvider : function(){
14933             return provider;
14934         }
14935     };
14936 }();
14937 /*
14938  * Based on:
14939  * Ext JS Library 1.1.1
14940  * Copyright(c) 2006-2007, Ext JS, LLC.
14941  *
14942  * Originally Released Under LGPL - original licence link has changed is not relivant.
14943  *
14944  * Fork - LGPL
14945  * <script type="text/javascript">
14946  */
14947 /**
14948  * @class Roo.state.CookieProvider
14949  * @extends Roo.state.Provider
14950  * The default Provider implementation which saves state via cookies.
14951  * <br />Usage:
14952  <pre><code>
14953    var cp = new Roo.state.CookieProvider({
14954        path: "/cgi-bin/",
14955        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14956        domain: "roojs.com"
14957    })
14958    Roo.state.Manager.setProvider(cp);
14959  </code></pre>
14960  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14961  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14962  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14963  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14964  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14965  * domain the page is running on including the 'www' like 'www.roojs.com')
14966  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14967  * @constructor
14968  * Create a new CookieProvider
14969  * @param {Object} config The configuration object
14970  */
14971 Roo.state.CookieProvider = function(config){
14972     Roo.state.CookieProvider.superclass.constructor.call(this);
14973     this.path = "/";
14974     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14975     this.domain = null;
14976     this.secure = false;
14977     Roo.apply(this, config);
14978     this.state = this.readCookies();
14979 };
14980
14981 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14982     // private
14983     set : function(name, value){
14984         if(typeof value == "undefined" || value === null){
14985             this.clear(name);
14986             return;
14987         }
14988         this.setCookie(name, value);
14989         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14990     },
14991
14992     // private
14993     clear : function(name){
14994         this.clearCookie(name);
14995         Roo.state.CookieProvider.superclass.clear.call(this, name);
14996     },
14997
14998     // private
14999     readCookies : function(){
15000         var cookies = {};
15001         var c = document.cookie + ";";
15002         var re = /\s?(.*?)=(.*?);/g;
15003         var matches;
15004         while((matches = re.exec(c)) != null){
15005             var name = matches[1];
15006             var value = matches[2];
15007             if(name && name.substring(0,3) == "ys-"){
15008                 cookies[name.substr(3)] = this.decodeValue(value);
15009             }
15010         }
15011         return cookies;
15012     },
15013
15014     // private
15015     setCookie : function(name, value){
15016         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15017            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15018            ((this.path == null) ? "" : ("; path=" + this.path)) +
15019            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15020            ((this.secure == true) ? "; secure" : "");
15021     },
15022
15023     // private
15024     clearCookie : function(name){
15025         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15026            ((this.path == null) ? "" : ("; path=" + this.path)) +
15027            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15028            ((this.secure == true) ? "; secure" : "");
15029     }
15030 });/*
15031  * Based on:
15032  * Ext JS Library 1.1.1
15033  * Copyright(c) 2006-2007, Ext JS, LLC.
15034  *
15035  * Originally Released Under LGPL - original licence link has changed is not relivant.
15036  *
15037  * Fork - LGPL
15038  * <script type="text/javascript">
15039  */
15040  
15041
15042 /**
15043  * @class Roo.ComponentMgr
15044  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15045  * @singleton
15046  */
15047 Roo.ComponentMgr = function(){
15048     var all = new Roo.util.MixedCollection();
15049
15050     return {
15051         /**
15052          * Registers a component.
15053          * @param {Roo.Component} c The component
15054          */
15055         register : function(c){
15056             all.add(c);
15057         },
15058
15059         /**
15060          * Unregisters a component.
15061          * @param {Roo.Component} c The component
15062          */
15063         unregister : function(c){
15064             all.remove(c);
15065         },
15066
15067         /**
15068          * Returns a component by id
15069          * @param {String} id The component id
15070          */
15071         get : function(id){
15072             return all.get(id);
15073         },
15074
15075         /**
15076          * Registers a function that will be called when a specified component is added to ComponentMgr
15077          * @param {String} id The component id
15078          * @param {Funtction} fn The callback function
15079          * @param {Object} scope The scope of the callback
15080          */
15081         onAvailable : function(id, fn, scope){
15082             all.on("add", function(index, o){
15083                 if(o.id == id){
15084                     fn.call(scope || o, o);
15085                     all.un("add", fn, scope);
15086                 }
15087             });
15088         }
15089     };
15090 }();/*
15091  * Based on:
15092  * Ext JS Library 1.1.1
15093  * Copyright(c) 2006-2007, Ext JS, LLC.
15094  *
15095  * Originally Released Under LGPL - original licence link has changed is not relivant.
15096  *
15097  * Fork - LGPL
15098  * <script type="text/javascript">
15099  */
15100  
15101 /**
15102  * @class Roo.Component
15103  * @extends Roo.util.Observable
15104  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15105  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15106  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15107  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15108  * All visual components (widgets) that require rendering into a layout should subclass Component.
15109  * @constructor
15110  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15111  * 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
15112  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15113  */
15114 Roo.Component = function(config){
15115     config = config || {};
15116     if(config.tagName || config.dom || typeof config == "string"){ // element object
15117         config = {el: config, id: config.id || config};
15118     }
15119     this.initialConfig = config;
15120
15121     Roo.apply(this, config);
15122     this.addEvents({
15123         /**
15124          * @event disable
15125          * Fires after the component is disabled.
15126              * @param {Roo.Component} this
15127              */
15128         disable : true,
15129         /**
15130          * @event enable
15131          * Fires after the component is enabled.
15132              * @param {Roo.Component} this
15133              */
15134         enable : true,
15135         /**
15136          * @event beforeshow
15137          * Fires before the component is shown.  Return false to stop the show.
15138              * @param {Roo.Component} this
15139              */
15140         beforeshow : true,
15141         /**
15142          * @event show
15143          * Fires after the component is shown.
15144              * @param {Roo.Component} this
15145              */
15146         show : true,
15147         /**
15148          * @event beforehide
15149          * Fires before the component is hidden. Return false to stop the hide.
15150              * @param {Roo.Component} this
15151              */
15152         beforehide : true,
15153         /**
15154          * @event hide
15155          * Fires after the component is hidden.
15156              * @param {Roo.Component} this
15157              */
15158         hide : true,
15159         /**
15160          * @event beforerender
15161          * Fires before the component is rendered. Return false to stop the render.
15162              * @param {Roo.Component} this
15163              */
15164         beforerender : true,
15165         /**
15166          * @event render
15167          * Fires after the component is rendered.
15168              * @param {Roo.Component} this
15169              */
15170         render : true,
15171         /**
15172          * @event beforedestroy
15173          * Fires before the component is destroyed. Return false to stop the destroy.
15174              * @param {Roo.Component} this
15175              */
15176         beforedestroy : true,
15177         /**
15178          * @event destroy
15179          * Fires after the component is destroyed.
15180              * @param {Roo.Component} this
15181              */
15182         destroy : true
15183     });
15184     if(!this.id){
15185         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15186     }
15187     Roo.ComponentMgr.register(this);
15188     Roo.Component.superclass.constructor.call(this);
15189     this.initComponent();
15190     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15191         this.render(this.renderTo);
15192         delete this.renderTo;
15193     }
15194 };
15195
15196 /** @private */
15197 Roo.Component.AUTO_ID = 1000;
15198
15199 Roo.extend(Roo.Component, Roo.util.Observable, {
15200     /**
15201      * @scope Roo.Component.prototype
15202      * @type {Boolean}
15203      * true if this component is hidden. Read-only.
15204      */
15205     hidden : false,
15206     /**
15207      * @type {Boolean}
15208      * true if this component is disabled. Read-only.
15209      */
15210     disabled : false,
15211     /**
15212      * @type {Boolean}
15213      * true if this component has been rendered. Read-only.
15214      */
15215     rendered : false,
15216     
15217     /** @cfg {String} disableClass
15218      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15219      */
15220     disabledClass : "x-item-disabled",
15221         /** @cfg {Boolean} allowDomMove
15222          * Whether the component can move the Dom node when rendering (defaults to true).
15223          */
15224     allowDomMove : true,
15225     /** @cfg {String} hideMode (display|visibility)
15226      * How this component should hidden. Supported values are
15227      * "visibility" (css visibility), "offsets" (negative offset position) and
15228      * "display" (css display) - defaults to "display".
15229      */
15230     hideMode: 'display',
15231
15232     /** @private */
15233     ctype : "Roo.Component",
15234
15235     /**
15236      * @cfg {String} actionMode 
15237      * which property holds the element that used for  hide() / show() / disable() / enable()
15238      * default is 'el' 
15239      */
15240     actionMode : "el",
15241
15242     /** @private */
15243     getActionEl : function(){
15244         return this[this.actionMode];
15245     },
15246
15247     initComponent : Roo.emptyFn,
15248     /**
15249      * If this is a lazy rendering component, render it to its container element.
15250      * @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.
15251      */
15252     render : function(container, position){
15253         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15254             if(!container && this.el){
15255                 this.el = Roo.get(this.el);
15256                 container = this.el.dom.parentNode;
15257                 this.allowDomMove = false;
15258             }
15259             this.container = Roo.get(container);
15260             this.rendered = true;
15261             if(position !== undefined){
15262                 if(typeof position == 'number'){
15263                     position = this.container.dom.childNodes[position];
15264                 }else{
15265                     position = Roo.getDom(position);
15266                 }
15267             }
15268             this.onRender(this.container, position || null);
15269             if(this.cls){
15270                 this.el.addClass(this.cls);
15271                 delete this.cls;
15272             }
15273             if(this.style){
15274                 this.el.applyStyles(this.style);
15275                 delete this.style;
15276             }
15277             this.fireEvent("render", this);
15278             this.afterRender(this.container);
15279             if(this.hidden){
15280                 this.hide();
15281             }
15282             if(this.disabled){
15283                 this.disable();
15284             }
15285         }
15286         return this;
15287     },
15288
15289     /** @private */
15290     // default function is not really useful
15291     onRender : function(ct, position){
15292         if(this.el){
15293             this.el = Roo.get(this.el);
15294             if(this.allowDomMove !== false){
15295                 ct.dom.insertBefore(this.el.dom, position);
15296             }
15297         }
15298     },
15299
15300     /** @private */
15301     getAutoCreate : function(){
15302         var cfg = typeof this.autoCreate == "object" ?
15303                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15304         if(this.id && !cfg.id){
15305             cfg.id = this.id;
15306         }
15307         return cfg;
15308     },
15309
15310     /** @private */
15311     afterRender : Roo.emptyFn,
15312
15313     /**
15314      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15315      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15316      */
15317     destroy : function(){
15318         if(this.fireEvent("beforedestroy", this) !== false){
15319             this.purgeListeners();
15320             this.beforeDestroy();
15321             if(this.rendered){
15322                 this.el.removeAllListeners();
15323                 this.el.remove();
15324                 if(this.actionMode == "container"){
15325                     this.container.remove();
15326                 }
15327             }
15328             this.onDestroy();
15329             Roo.ComponentMgr.unregister(this);
15330             this.fireEvent("destroy", this);
15331         }
15332     },
15333
15334         /** @private */
15335     beforeDestroy : function(){
15336
15337     },
15338
15339         /** @private */
15340         onDestroy : function(){
15341
15342     },
15343
15344     /**
15345      * Returns the underlying {@link Roo.Element}.
15346      * @return {Roo.Element} The element
15347      */
15348     getEl : function(){
15349         return this.el;
15350     },
15351
15352     /**
15353      * Returns the id of this component.
15354      * @return {String}
15355      */
15356     getId : function(){
15357         return this.id;
15358     },
15359
15360     /**
15361      * Try to focus this component.
15362      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15363      * @return {Roo.Component} this
15364      */
15365     focus : function(selectText){
15366         if(this.rendered){
15367             this.el.focus();
15368             if(selectText === true){
15369                 this.el.dom.select();
15370             }
15371         }
15372         return this;
15373     },
15374
15375     /** @private */
15376     blur : function(){
15377         if(this.rendered){
15378             this.el.blur();
15379         }
15380         return this;
15381     },
15382
15383     /**
15384      * Disable this component.
15385      * @return {Roo.Component} this
15386      */
15387     disable : function(){
15388         if(this.rendered){
15389             this.onDisable();
15390         }
15391         this.disabled = true;
15392         this.fireEvent("disable", this);
15393         return this;
15394     },
15395
15396         // private
15397     onDisable : function(){
15398         this.getActionEl().addClass(this.disabledClass);
15399         this.el.dom.disabled = true;
15400     },
15401
15402     /**
15403      * Enable this component.
15404      * @return {Roo.Component} this
15405      */
15406     enable : function(){
15407         if(this.rendered){
15408             this.onEnable();
15409         }
15410         this.disabled = false;
15411         this.fireEvent("enable", this);
15412         return this;
15413     },
15414
15415         // private
15416     onEnable : function(){
15417         this.getActionEl().removeClass(this.disabledClass);
15418         this.el.dom.disabled = false;
15419     },
15420
15421     /**
15422      * Convenience function for setting disabled/enabled by boolean.
15423      * @param {Boolean} disabled
15424      */
15425     setDisabled : function(disabled){
15426         this[disabled ? "disable" : "enable"]();
15427     },
15428
15429     /**
15430      * Show this component.
15431      * @return {Roo.Component} this
15432      */
15433     show: function(){
15434         if(this.fireEvent("beforeshow", this) !== false){
15435             this.hidden = false;
15436             if(this.rendered){
15437                 this.onShow();
15438             }
15439             this.fireEvent("show", this);
15440         }
15441         return this;
15442     },
15443
15444     // private
15445     onShow : function(){
15446         var ae = this.getActionEl();
15447         if(this.hideMode == 'visibility'){
15448             ae.dom.style.visibility = "visible";
15449         }else if(this.hideMode == 'offsets'){
15450             ae.removeClass('x-hidden');
15451         }else{
15452             ae.dom.style.display = "";
15453         }
15454     },
15455
15456     /**
15457      * Hide this component.
15458      * @return {Roo.Component} this
15459      */
15460     hide: function(){
15461         if(this.fireEvent("beforehide", this) !== false){
15462             this.hidden = true;
15463             if(this.rendered){
15464                 this.onHide();
15465             }
15466             this.fireEvent("hide", this);
15467         }
15468         return this;
15469     },
15470
15471     // private
15472     onHide : function(){
15473         var ae = this.getActionEl();
15474         if(this.hideMode == 'visibility'){
15475             ae.dom.style.visibility = "hidden";
15476         }else if(this.hideMode == 'offsets'){
15477             ae.addClass('x-hidden');
15478         }else{
15479             ae.dom.style.display = "none";
15480         }
15481     },
15482
15483     /**
15484      * Convenience function to hide or show this component by boolean.
15485      * @param {Boolean} visible True to show, false to hide
15486      * @return {Roo.Component} this
15487      */
15488     setVisible: function(visible){
15489         if(visible) {
15490             this.show();
15491         }else{
15492             this.hide();
15493         }
15494         return this;
15495     },
15496
15497     /**
15498      * Returns true if this component is visible.
15499      */
15500     isVisible : function(){
15501         return this.getActionEl().isVisible();
15502     },
15503
15504     cloneConfig : function(overrides){
15505         overrides = overrides || {};
15506         var id = overrides.id || Roo.id();
15507         var cfg = Roo.applyIf(overrides, this.initialConfig);
15508         cfg.id = id; // prevent dup id
15509         return new this.constructor(cfg);
15510     }
15511 });/*
15512  * Based on:
15513  * Ext JS Library 1.1.1
15514  * Copyright(c) 2006-2007, Ext JS, LLC.
15515  *
15516  * Originally Released Under LGPL - original licence link has changed is not relivant.
15517  *
15518  * Fork - LGPL
15519  * <script type="text/javascript">
15520  */
15521
15522 /**
15523  * @class Roo.BoxComponent
15524  * @extends Roo.Component
15525  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15526  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15527  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15528  * layout containers.
15529  * @constructor
15530  * @param {Roo.Element/String/Object} config The configuration options.
15531  */
15532 Roo.BoxComponent = function(config){
15533     Roo.Component.call(this, config);
15534     this.addEvents({
15535         /**
15536          * @event resize
15537          * Fires after the component is resized.
15538              * @param {Roo.Component} this
15539              * @param {Number} adjWidth The box-adjusted width that was set
15540              * @param {Number} adjHeight The box-adjusted height that was set
15541              * @param {Number} rawWidth The width that was originally specified
15542              * @param {Number} rawHeight The height that was originally specified
15543              */
15544         resize : true,
15545         /**
15546          * @event move
15547          * Fires after the component is moved.
15548              * @param {Roo.Component} this
15549              * @param {Number} x The new x position
15550              * @param {Number} y The new y position
15551              */
15552         move : true
15553     });
15554 };
15555
15556 Roo.extend(Roo.BoxComponent, Roo.Component, {
15557     // private, set in afterRender to signify that the component has been rendered
15558     boxReady : false,
15559     // private, used to defer height settings to subclasses
15560     deferHeight: false,
15561     /** @cfg {Number} width
15562      * width (optional) size of component
15563      */
15564      /** @cfg {Number} height
15565      * height (optional) size of component
15566      */
15567      
15568     /**
15569      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15570      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15571      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15572      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15573      * @return {Roo.BoxComponent} this
15574      */
15575     setSize : function(w, h){
15576         // support for standard size objects
15577         if(typeof w == 'object'){
15578             h = w.height;
15579             w = w.width;
15580         }
15581         // not rendered
15582         if(!this.boxReady){
15583             this.width = w;
15584             this.height = h;
15585             return this;
15586         }
15587
15588         // prevent recalcs when not needed
15589         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15590             return this;
15591         }
15592         this.lastSize = {width: w, height: h};
15593
15594         var adj = this.adjustSize(w, h);
15595         var aw = adj.width, ah = adj.height;
15596         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15597             var rz = this.getResizeEl();
15598             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15599                 rz.setSize(aw, ah);
15600             }else if(!this.deferHeight && ah !== undefined){
15601                 rz.setHeight(ah);
15602             }else if(aw !== undefined){
15603                 rz.setWidth(aw);
15604             }
15605             this.onResize(aw, ah, w, h);
15606             this.fireEvent('resize', this, aw, ah, w, h);
15607         }
15608         return this;
15609     },
15610
15611     /**
15612      * Gets the current size of the component's underlying element.
15613      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15614      */
15615     getSize : function(){
15616         return this.el.getSize();
15617     },
15618
15619     /**
15620      * Gets the current XY position of the component's underlying element.
15621      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15622      * @return {Array} The XY position of the element (e.g., [100, 200])
15623      */
15624     getPosition : function(local){
15625         if(local === true){
15626             return [this.el.getLeft(true), this.el.getTop(true)];
15627         }
15628         return this.xy || this.el.getXY();
15629     },
15630
15631     /**
15632      * Gets the current box measurements of the component's underlying element.
15633      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15634      * @returns {Object} box An object in the format {x, y, width, height}
15635      */
15636     getBox : function(local){
15637         var s = this.el.getSize();
15638         if(local){
15639             s.x = this.el.getLeft(true);
15640             s.y = this.el.getTop(true);
15641         }else{
15642             var xy = this.xy || this.el.getXY();
15643             s.x = xy[0];
15644             s.y = xy[1];
15645         }
15646         return s;
15647     },
15648
15649     /**
15650      * Sets the current box measurements of the component's underlying element.
15651      * @param {Object} box An object in the format {x, y, width, height}
15652      * @returns {Roo.BoxComponent} this
15653      */
15654     updateBox : function(box){
15655         this.setSize(box.width, box.height);
15656         this.setPagePosition(box.x, box.y);
15657         return this;
15658     },
15659
15660     // protected
15661     getResizeEl : function(){
15662         return this.resizeEl || this.el;
15663     },
15664
15665     // protected
15666     getPositionEl : function(){
15667         return this.positionEl || this.el;
15668     },
15669
15670     /**
15671      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15672      * This method fires the move event.
15673      * @param {Number} left The new left
15674      * @param {Number} top The new top
15675      * @returns {Roo.BoxComponent} this
15676      */
15677     setPosition : function(x, y){
15678         this.x = x;
15679         this.y = y;
15680         if(!this.boxReady){
15681             return this;
15682         }
15683         var adj = this.adjustPosition(x, y);
15684         var ax = adj.x, ay = adj.y;
15685
15686         var el = this.getPositionEl();
15687         if(ax !== undefined || ay !== undefined){
15688             if(ax !== undefined && ay !== undefined){
15689                 el.setLeftTop(ax, ay);
15690             }else if(ax !== undefined){
15691                 el.setLeft(ax);
15692             }else if(ay !== undefined){
15693                 el.setTop(ay);
15694             }
15695             this.onPosition(ax, ay);
15696             this.fireEvent('move', this, ax, ay);
15697         }
15698         return this;
15699     },
15700
15701     /**
15702      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15703      * This method fires the move event.
15704      * @param {Number} x The new x position
15705      * @param {Number} y The new y position
15706      * @returns {Roo.BoxComponent} this
15707      */
15708     setPagePosition : function(x, y){
15709         this.pageX = x;
15710         this.pageY = y;
15711         if(!this.boxReady){
15712             return;
15713         }
15714         if(x === undefined || y === undefined){ // cannot translate undefined points
15715             return;
15716         }
15717         var p = this.el.translatePoints(x, y);
15718         this.setPosition(p.left, p.top);
15719         return this;
15720     },
15721
15722     // private
15723     onRender : function(ct, position){
15724         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15725         if(this.resizeEl){
15726             this.resizeEl = Roo.get(this.resizeEl);
15727         }
15728         if(this.positionEl){
15729             this.positionEl = Roo.get(this.positionEl);
15730         }
15731     },
15732
15733     // private
15734     afterRender : function(){
15735         Roo.BoxComponent.superclass.afterRender.call(this);
15736         this.boxReady = true;
15737         this.setSize(this.width, this.height);
15738         if(this.x || this.y){
15739             this.setPosition(this.x, this.y);
15740         }
15741         if(this.pageX || this.pageY){
15742             this.setPagePosition(this.pageX, this.pageY);
15743         }
15744     },
15745
15746     /**
15747      * Force the component's size to recalculate based on the underlying element's current height and width.
15748      * @returns {Roo.BoxComponent} this
15749      */
15750     syncSize : function(){
15751         delete this.lastSize;
15752         this.setSize(this.el.getWidth(), this.el.getHeight());
15753         return this;
15754     },
15755
15756     /**
15757      * Called after the component is resized, this method is empty by default but can be implemented by any
15758      * subclass that needs to perform custom logic after a resize occurs.
15759      * @param {Number} adjWidth The box-adjusted width that was set
15760      * @param {Number} adjHeight The box-adjusted height that was set
15761      * @param {Number} rawWidth The width that was originally specified
15762      * @param {Number} rawHeight The height that was originally specified
15763      */
15764     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15765
15766     },
15767
15768     /**
15769      * Called after the component is moved, this method is empty by default but can be implemented by any
15770      * subclass that needs to perform custom logic after a move occurs.
15771      * @param {Number} x The new x position
15772      * @param {Number} y The new y position
15773      */
15774     onPosition : function(x, y){
15775
15776     },
15777
15778     // private
15779     adjustSize : function(w, h){
15780         if(this.autoWidth){
15781             w = 'auto';
15782         }
15783         if(this.autoHeight){
15784             h = 'auto';
15785         }
15786         return {width : w, height: h};
15787     },
15788
15789     // private
15790     adjustPosition : function(x, y){
15791         return {x : x, y: y};
15792     }
15793 });/*
15794  * Original code for Roojs - LGPL
15795  * <script type="text/javascript">
15796  */
15797  
15798 /**
15799  * @class Roo.XComponent
15800  * A delayed Element creator...
15801  * Or a way to group chunks of interface together.
15802  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15803  *  used in conjunction with XComponent.build() it will create an instance of each element,
15804  *  then call addxtype() to build the User interface.
15805  * 
15806  * Mypart.xyx = new Roo.XComponent({
15807
15808     parent : 'Mypart.xyz', // empty == document.element.!!
15809     order : '001',
15810     name : 'xxxx'
15811     region : 'xxxx'
15812     disabled : function() {} 
15813      
15814     tree : function() { // return an tree of xtype declared components
15815         var MODULE = this;
15816         return 
15817         {
15818             xtype : 'NestedLayoutPanel',
15819             // technicall
15820         }
15821      ]
15822  *})
15823  *
15824  *
15825  * It can be used to build a big heiracy, with parent etc.
15826  * or you can just use this to render a single compoent to a dom element
15827  * MYPART.render(Roo.Element | String(id) | dom_element )
15828  *
15829  *
15830  * Usage patterns.
15831  *
15832  * Classic Roo
15833  *
15834  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15835  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15836  *
15837  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15838  *
15839  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15840  * - if mulitple topModules exist, the last one is defined as the top module.
15841  *
15842  * Embeded Roo
15843  * 
15844  * When the top level or multiple modules are to embedded into a existing HTML page,
15845  * the parent element can container '#id' of the element where the module will be drawn.
15846  *
15847  * Bootstrap Roo
15848  *
15849  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15850  * it relies more on a include mechanism, where sub modules are included into an outer page.
15851  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15852  * 
15853  * Bootstrap Roo Included elements
15854  *
15855  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15856  * hence confusing the component builder as it thinks there are multiple top level elements. 
15857  *
15858  * 
15859  * 
15860  * @extends Roo.util.Observable
15861  * @constructor
15862  * @param cfg {Object} configuration of component
15863  * 
15864  */
15865 Roo.XComponent = function(cfg) {
15866     Roo.apply(this, cfg);
15867     this.addEvents({ 
15868         /**
15869              * @event built
15870              * Fires when this the componnt is built
15871              * @param {Roo.XComponent} c the component
15872              */
15873         'built' : true
15874         
15875     });
15876     this.region = this.region || 'center'; // default..
15877     Roo.XComponent.register(this);
15878     this.modules = false;
15879     this.el = false; // where the layout goes..
15880     
15881     
15882 }
15883 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15884     /**
15885      * @property el
15886      * The created element (with Roo.factory())
15887      * @type {Roo.Layout}
15888      */
15889     el  : false,
15890     
15891     /**
15892      * @property el
15893      * for BC  - use el in new code
15894      * @type {Roo.Layout}
15895      */
15896     panel : false,
15897     
15898     /**
15899      * @property layout
15900      * for BC  - use el in new code
15901      * @type {Roo.Layout}
15902      */
15903     layout : false,
15904     
15905      /**
15906      * @cfg {Function|boolean} disabled
15907      * If this module is disabled by some rule, return true from the funtion
15908      */
15909     disabled : false,
15910     
15911     /**
15912      * @cfg {String} parent 
15913      * Name of parent element which it get xtype added to..
15914      */
15915     parent: false,
15916     
15917     /**
15918      * @cfg {String} order
15919      * Used to set the order in which elements are created (usefull for multiple tabs)
15920      */
15921     
15922     order : false,
15923     /**
15924      * @cfg {String} name
15925      * String to display while loading.
15926      */
15927     name : false,
15928     /**
15929      * @cfg {String} region
15930      * Region to render component to (defaults to center)
15931      */
15932     region : 'center',
15933     
15934     /**
15935      * @cfg {Array} items
15936      * A single item array - the first element is the root of the tree..
15937      * It's done this way to stay compatible with the Xtype system...
15938      */
15939     items : false,
15940     
15941     /**
15942      * @property _tree
15943      * The method that retuns the tree of parts that make up this compoennt 
15944      * @type {function}
15945      */
15946     _tree  : false,
15947     
15948      /**
15949      * render
15950      * render element to dom or tree
15951      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15952      */
15953     
15954     render : function(el)
15955     {
15956         
15957         el = el || false;
15958         var hp = this.parent ? 1 : 0;
15959         Roo.debug &&  Roo.log(this);
15960         
15961         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15962             // if parent is a '#.....' string, then let's use that..
15963             var ename = this.parent.substr(1);
15964             this.parent = false;
15965             Roo.debug && Roo.log(ename);
15966             switch (ename) {
15967                 case 'bootstrap-body' :
15968                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15969                         this.parent = { el :  new  Roo.bootstrap.Body() };
15970                         Roo.debug && Roo.log("setting el to doc body");
15971                          
15972                     } else {
15973                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15974                     }
15975                     break;
15976                 case 'bootstrap':
15977                     this.parent = { el : true};
15978                     // fall through
15979                 default:
15980                     el = Roo.get(ename);
15981                     break;
15982             }
15983                 
15984             
15985             if (!el && !this.parent) {
15986                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15987                 return;
15988             }
15989         }
15990         Roo.debug && Roo.log("EL:");
15991         Roo.debug && Roo.log(el);
15992         Roo.debug && Roo.log("this.parent.el:");
15993         Roo.debug && Roo.log(this.parent.el);
15994         
15995         var tree = this._tree ? this._tree() : this.tree();
15996
15997         // altertive root elements ??? - we need a better way to indicate these.
15998         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15999                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16000         
16001         if (!this.parent && is_alt) {
16002             //el = Roo.get(document.body);
16003             this.parent = { el : true };
16004         }
16005             
16006             
16007         
16008         if (!this.parent) {
16009             
16010             Roo.debug && Roo.log("no parent - creating one");
16011             
16012             el = el ? Roo.get(el) : false;      
16013             
16014             // it's a top level one..
16015             this.parent =  {
16016                 el : new Roo.BorderLayout(el || document.body, {
16017                 
16018                      center: {
16019                          titlebar: false,
16020                          autoScroll:false,
16021                          closeOnTab: true,
16022                          tabPosition: 'top',
16023                           //resizeTabs: true,
16024                          alwaysShowTabs: el && hp? false :  true,
16025                          hideTabs: el || !hp ? true :  false,
16026                          minTabWidth: 140
16027                      }
16028                  })
16029             }
16030         }
16031         
16032         if (!this.parent.el) {
16033                 // probably an old style ctor, which has been disabled.
16034                 return;
16035
16036         }
16037                 // The 'tree' method is  '_tree now' 
16038             
16039         tree.region = tree.region || this.region;
16040         
16041         if (this.parent.el === true) {
16042             // bootstrap... - body..
16043             this.parent.el = Roo.factory(tree);
16044         }
16045         
16046         this.el = this.parent.el.addxtype(tree);
16047         this.fireEvent('built', this);
16048         
16049         this.panel = this.el;
16050         this.layout = this.panel.layout;
16051         this.parentLayout = this.parent.layout  || false;  
16052          
16053     }
16054     
16055 });
16056
16057 Roo.apply(Roo.XComponent, {
16058     /**
16059      * @property  hideProgress
16060      * true to disable the building progress bar.. usefull on single page renders.
16061      * @type Boolean
16062      */
16063     hideProgress : false,
16064     /**
16065      * @property  buildCompleted
16066      * True when the builder has completed building the interface.
16067      * @type Boolean
16068      */
16069     buildCompleted : false,
16070      
16071     /**
16072      * @property  topModule
16073      * the upper most module - uses document.element as it's constructor.
16074      * @type Object
16075      */
16076      
16077     topModule  : false,
16078       
16079     /**
16080      * @property  modules
16081      * array of modules to be created by registration system.
16082      * @type {Array} of Roo.XComponent
16083      */
16084     
16085     modules : [],
16086     /**
16087      * @property  elmodules
16088      * array of modules to be created by which use #ID 
16089      * @type {Array} of Roo.XComponent
16090      */
16091      
16092     elmodules : [],
16093
16094      /**
16095      * @property  build_from_html
16096      * Build elements from html - used by bootstrap HTML stuff 
16097      *    - this is cleared after build is completed
16098      * @type {boolean} true  (default false)
16099      */
16100      
16101     build_from_html : false,
16102
16103     /**
16104      * Register components to be built later.
16105      *
16106      * This solves the following issues
16107      * - Building is not done on page load, but after an authentication process has occured.
16108      * - Interface elements are registered on page load
16109      * - Parent Interface elements may not be loaded before child, so this handles that..
16110      * 
16111      *
16112      * example:
16113      * 
16114      * MyApp.register({
16115           order : '000001',
16116           module : 'Pman.Tab.projectMgr',
16117           region : 'center',
16118           parent : 'Pman.layout',
16119           disabled : false,  // or use a function..
16120         })
16121      
16122      * * @param {Object} details about module
16123      */
16124     register : function(obj) {
16125                 
16126         Roo.XComponent.event.fireEvent('register', obj);
16127         switch(typeof(obj.disabled) ) {
16128                 
16129             case 'undefined':
16130                 break;
16131             
16132             case 'function':
16133                 if ( obj.disabled() ) {
16134                         return;
16135                 }
16136                 break;
16137             
16138             default:
16139                 if (obj.disabled) {
16140                         return;
16141                 }
16142                 break;
16143         }
16144                 
16145         this.modules.push(obj);
16146          
16147     },
16148     /**
16149      * convert a string to an object..
16150      * eg. 'AAA.BBB' -> finds AAA.BBB
16151
16152      */
16153     
16154     toObject : function(str)
16155     {
16156         if (!str || typeof(str) == 'object') {
16157             return str;
16158         }
16159         if (str.substring(0,1) == '#') {
16160             return str;
16161         }
16162
16163         var ar = str.split('.');
16164         var rt, o;
16165         rt = ar.shift();
16166             /** eval:var:o */
16167         try {
16168             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16169         } catch (e) {
16170             throw "Module not found : " + str;
16171         }
16172         
16173         if (o === false) {
16174             throw "Module not found : " + str;
16175         }
16176         Roo.each(ar, function(e) {
16177             if (typeof(o[e]) == 'undefined') {
16178                 throw "Module not found : " + str;
16179             }
16180             o = o[e];
16181         });
16182         
16183         return o;
16184         
16185     },
16186     
16187     
16188     /**
16189      * move modules into their correct place in the tree..
16190      * 
16191      */
16192     preBuild : function ()
16193     {
16194         var _t = this;
16195         Roo.each(this.modules , function (obj)
16196         {
16197             Roo.XComponent.event.fireEvent('beforebuild', obj);
16198             
16199             var opar = obj.parent;
16200             try { 
16201                 obj.parent = this.toObject(opar);
16202             } catch(e) {
16203                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16204                 return;
16205             }
16206             
16207             if (!obj.parent) {
16208                 Roo.debug && Roo.log("GOT top level module");
16209                 Roo.debug && Roo.log(obj);
16210                 obj.modules = new Roo.util.MixedCollection(false, 
16211                     function(o) { return o.order + '' }
16212                 );
16213                 this.topModule = obj;
16214                 return;
16215             }
16216                         // parent is a string (usually a dom element name..)
16217             if (typeof(obj.parent) == 'string') {
16218                 this.elmodules.push(obj);
16219                 return;
16220             }
16221             if (obj.parent.constructor != Roo.XComponent) {
16222                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16223             }
16224             if (!obj.parent.modules) {
16225                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16226                     function(o) { return o.order + '' }
16227                 );
16228             }
16229             if (obj.parent.disabled) {
16230                 obj.disabled = true;
16231             }
16232             obj.parent.modules.add(obj);
16233         }, this);
16234     },
16235     
16236      /**
16237      * make a list of modules to build.
16238      * @return {Array} list of modules. 
16239      */ 
16240     
16241     buildOrder : function()
16242     {
16243         var _this = this;
16244         var cmp = function(a,b) {   
16245             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16246         };
16247         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16248             throw "No top level modules to build";
16249         }
16250         
16251         // make a flat list in order of modules to build.
16252         var mods = this.topModule ? [ this.topModule ] : [];
16253                 
16254         
16255         // elmodules (is a list of DOM based modules )
16256         Roo.each(this.elmodules, function(e) {
16257             mods.push(e);
16258             if (!this.topModule &&
16259                 typeof(e.parent) == 'string' &&
16260                 e.parent.substring(0,1) == '#' &&
16261                 Roo.get(e.parent.substr(1))
16262                ) {
16263                 
16264                 _this.topModule = e;
16265             }
16266             
16267         });
16268
16269         
16270         // add modules to their parents..
16271         var addMod = function(m) {
16272             Roo.debug && Roo.log("build Order: add: " + m.name);
16273                 
16274             mods.push(m);
16275             if (m.modules && !m.disabled) {
16276                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16277                 m.modules.keySort('ASC',  cmp );
16278                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16279     
16280                 m.modules.each(addMod);
16281             } else {
16282                 Roo.debug && Roo.log("build Order: no child modules");
16283             }
16284             // not sure if this is used any more..
16285             if (m.finalize) {
16286                 m.finalize.name = m.name + " (clean up) ";
16287                 mods.push(m.finalize);
16288             }
16289             
16290         }
16291         if (this.topModule && this.topModule.modules) { 
16292             this.topModule.modules.keySort('ASC',  cmp );
16293             this.topModule.modules.each(addMod);
16294         } 
16295         return mods;
16296     },
16297     
16298      /**
16299      * Build the registered modules.
16300      * @param {Object} parent element.
16301      * @param {Function} optional method to call after module has been added.
16302      * 
16303      */ 
16304    
16305     build : function(opts) 
16306     {
16307         
16308         if (typeof(opts) != 'undefined') {
16309             Roo.apply(this,opts);
16310         }
16311         
16312         this.preBuild();
16313         var mods = this.buildOrder();
16314       
16315         //this.allmods = mods;
16316         //Roo.debug && Roo.log(mods);
16317         //return;
16318         if (!mods.length) { // should not happen
16319             throw "NO modules!!!";
16320         }
16321         
16322         
16323         var msg = "Building Interface...";
16324         // flash it up as modal - so we store the mask!?
16325         if (!this.hideProgress && Roo.MessageBox) {
16326             Roo.MessageBox.show({ title: 'loading' });
16327             Roo.MessageBox.show({
16328                title: "Please wait...",
16329                msg: msg,
16330                width:450,
16331                progress:true,
16332                closable:false,
16333                modal: false
16334               
16335             });
16336         }
16337         var total = mods.length;
16338         
16339         var _this = this;
16340         var progressRun = function() {
16341             if (!mods.length) {
16342                 Roo.debug && Roo.log('hide?');
16343                 if (!this.hideProgress && Roo.MessageBox) {
16344                     Roo.MessageBox.hide();
16345                 }
16346                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16347                 
16348                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16349                 
16350                 // THE END...
16351                 return false;   
16352             }
16353             
16354             var m = mods.shift();
16355             
16356             
16357             Roo.debug && Roo.log(m);
16358             // not sure if this is supported any more.. - modules that are are just function
16359             if (typeof(m) == 'function') { 
16360                 m.call(this);
16361                 return progressRun.defer(10, _this);
16362             } 
16363             
16364             
16365             msg = "Building Interface " + (total  - mods.length) + 
16366                     " of " + total + 
16367                     (m.name ? (' - ' + m.name) : '');
16368                         Roo.debug && Roo.log(msg);
16369             if (!this.hideProgress &&  Roo.MessageBox) { 
16370                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16371             }
16372             
16373          
16374             // is the module disabled?
16375             var disabled = (typeof(m.disabled) == 'function') ?
16376                 m.disabled.call(m.module.disabled) : m.disabled;    
16377             
16378             
16379             if (disabled) {
16380                 return progressRun(); // we do not update the display!
16381             }
16382             
16383             // now build 
16384             
16385                         
16386                         
16387             m.render();
16388             // it's 10 on top level, and 1 on others??? why...
16389             return progressRun.defer(10, _this);
16390              
16391         }
16392         progressRun.defer(1, _this);
16393      
16394         
16395         
16396     },
16397         
16398         
16399         /**
16400          * Event Object.
16401          *
16402          *
16403          */
16404         event: false, 
16405     /**
16406          * wrapper for event.on - aliased later..  
16407          * Typically use to register a event handler for register:
16408          *
16409          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16410          *
16411          */
16412     on : false
16413    
16414     
16415     
16416 });
16417
16418 Roo.XComponent.event = new Roo.util.Observable({
16419                 events : { 
16420                         /**
16421                          * @event register
16422                          * Fires when an Component is registered,
16423                          * set the disable property on the Component to stop registration.
16424                          * @param {Roo.XComponent} c the component being registerd.
16425                          * 
16426                          */
16427                         'register' : true,
16428             /**
16429                          * @event beforebuild
16430                          * Fires before each Component is built
16431                          * can be used to apply permissions.
16432                          * @param {Roo.XComponent} c the component being registerd.
16433                          * 
16434                          */
16435                         'beforebuild' : true,
16436                         /**
16437                          * @event buildcomplete
16438                          * Fires on the top level element when all elements have been built
16439                          * @param {Roo.XComponent} the top level component.
16440                          */
16441                         'buildcomplete' : true
16442                         
16443                 }
16444 });
16445
16446 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16447