roojs-core-debug.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64         isTouch =  (function() {
65             try {  
66                 document.createEvent("TouchEvent");  
67                 return true;  
68             } catch (e) {  
69                 return false;  
70             } 
71             
72         })();
73     // remove css image flicker
74         if(isIE && !isIE7){
75         try{
76             document.execCommand("BackgroundImageCache", false, true);
77         }catch(e){}
78     }
79     
80     Roo.apply(Roo, {
81         /**
82          * True if the browser is in strict mode
83          * @type Boolean
84          */
85         isStrict : isStrict,
86         /**
87          * True if the page is running over SSL
88          * @type Boolean
89          */
90         isSecure : isSecure,
91         /**
92          * True when the document is fully initialized and ready for action
93          * @type Boolean
94          */
95         isReady : false,
96         /**
97          * Turn on debugging output (currently only the factory uses this)
98          * @type Boolean
99          */
100         
101         debug: false,
102
103         /**
104          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
105          * @type Boolean
106          */
107         enableGarbageCollector : true,
108
109         /**
110          * True to automatically purge event listeners after uncaching an element (defaults to false).
111          * Note: this only happens if enableGarbageCollector is true.
112          * @type Boolean
113          */
114         enableListenerCollection:false,
115
116         /**
117          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
118          * the IE insecure content warning (defaults to javascript:false).
119          * @type String
120          */
121         SSL_SECURE_URL : "javascript:false",
122
123         /**
124          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
125          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
126          * @type String
127          */
128         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
129
130         emptyFn : function(){},
131         
132         /**
133          * Copies all the properties of config to obj if they don't already exist.
134          * @param {Object} obj The receiver of the properties
135          * @param {Object} config The source of the properties
136          * @return {Object} returns obj
137          */
138         applyIf : function(o, c){
139             if(o && c){
140                 for(var p in c){
141                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
142                 }
143             }
144             return o;
145         },
146
147         /**
148          * Applies event listeners to elements by selectors when the document is ready.
149          * The event name is specified with an @ suffix.
150 <pre><code>
151 Roo.addBehaviors({
152    // add a listener for click on all anchors in element with id foo
153    '#foo a@click' : function(e, t){
154        // do something
155    },
156
157    // add the same listener to multiple selectors (separated by comma BEFORE the @)
158    '#foo a, #bar span.some-class@mouseover' : function(){
159        // do something
160    }
161 });
162 </code></pre>
163          * @param {Object} obj The list of behaviors to apply
164          */
165         addBehaviors : function(o){
166             if(!Roo.isReady){
167                 Roo.onReady(function(){
168                     Roo.addBehaviors(o);
169                 });
170                 return;
171             }
172             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
173             for(var b in o){
174                 var parts = b.split('@');
175                 if(parts[1]){ // for Object prototype breakers
176                     var s = parts[0];
177                     if(!cache[s]){
178                         cache[s] = Roo.select(s);
179                     }
180                     cache[s].on(parts[1], o[b]);
181                 }
182             }
183             cache = null;
184         },
185
186         /**
187          * Generates unique ids. If the element already has an id, it is unchanged
188          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
189          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
190          * @return {String} The generated Id.
191          */
192         id : function(el, prefix){
193             prefix = prefix || "roo-gen";
194             el = Roo.getDom(el);
195             var id = prefix + (++idSeed);
196             return el ? (el.id ? el.id : (el.id = id)) : id;
197         },
198          
199        
200         /**
201          * Extends one class with another class and optionally overrides members with the passed literal. This class
202          * also adds the function "override()" to the class that can be used to override
203          * members on an instance.
204          * @param {Object} subclass The class inheriting the functionality
205          * @param {Object} superclass The class being extended
206          * @param {Object} overrides (optional) A literal with members
207          * @method extend
208          */
209         extend : function(){
210             // inline overrides
211             var io = function(o){
212                 for(var m in o){
213                     this[m] = o[m];
214                 }
215             };
216             return function(sb, sp, overrides){
217                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
218                     overrides = sp;
219                     sp = sb;
220                     sb = function(){sp.apply(this, arguments);};
221                 }
222                 var F = function(){}, sbp, spp = sp.prototype;
223                 F.prototype = spp;
224                 sbp = sb.prototype = new F();
225                 sbp.constructor=sb;
226                 sb.superclass=spp;
227                 
228                 if(spp.constructor == Object.prototype.constructor){
229                     spp.constructor=sp;
230                    
231                 }
232                 
233                 sb.override = function(o){
234                     Roo.override(sb, o);
235                 };
236                 sbp.override = io;
237                 Roo.override(sb, overrides);
238                 return sb;
239             };
240         }(),
241
242         /**
243          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
244          * Usage:<pre><code>
245 Roo.override(MyClass, {
246     newMethod1: function(){
247         // etc.
248     },
249     newMethod2: function(foo){
250         // etc.
251     }
252 });
253  </code></pre>
254          * @param {Object} origclass The class to override
255          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
256          * containing one or more methods.
257          * @method override
258          */
259         override : function(origclass, overrides){
260             if(overrides){
261                 var p = origclass.prototype;
262                 for(var method in overrides){
263                     p[method] = overrides[method];
264                 }
265             }
266         },
267         /**
268          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
269          * <pre><code>
270 Roo.namespace('Company', 'Company.data');
271 Company.Widget = function() { ... }
272 Company.data.CustomStore = function(config) { ... }
273 </code></pre>
274          * @param {String} namespace1
275          * @param {String} namespace2
276          * @param {String} etc
277          * @method namespace
278          */
279         namespace : function(){
280             var a=arguments, o=null, i, j, d, rt;
281             for (i=0; i<a.length; ++i) {
282                 d=a[i].split(".");
283                 rt = d[0];
284                 /** eval:var:o */
285                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
286                 for (j=1; j<d.length; ++j) {
287                     o[d[j]]=o[d[j]] || {};
288                     o=o[d[j]];
289                 }
290             }
291         },
292         /**
293          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
294          * <pre><code>
295 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
296 Roo.factory(conf, Roo.data);
297 </code></pre>
298          * @param {String} classname
299          * @param {String} namespace (optional)
300          * @method factory
301          */
302          
303         factory : function(c, ns)
304         {
305             // no xtype, no ns or c.xns - or forced off by c.xns
306             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
307                 return c;
308             }
309             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
310             if (c.constructor == ns[c.xtype]) {// already created...
311                 return c;
312             }
313             if (ns[c.xtype]) {
314                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
315                 var ret = new ns[c.xtype](c);
316                 ret.xns = false;
317                 return ret;
318             }
319             c.xns = false; // prevent recursion..
320             return c;
321         },
322          /**
323          * Logs to console if it can.
324          *
325          * @param {String|Object} string
326          * @method log
327          */
328         log : function(s)
329         {
330             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
331                 return; // alerT?
332             }
333             console.log(s);
334             
335         },
336         /**
337          * 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.
338          * @param {Object} o
339          * @return {String}
340          */
341         urlEncode : function(o){
342             if(!o){
343                 return "";
344             }
345             var buf = [];
346             for(var key in o){
347                 var ov = o[key], k = Roo.encodeURIComponent(key);
348                 var type = typeof ov;
349                 if(type == 'undefined'){
350                     buf.push(k, "=&");
351                 }else if(type != "function" && type != "object"){
352                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
353                 }else if(ov instanceof Array){
354                     if (ov.length) {
355                             for(var i = 0, len = ov.length; i < len; i++) {
356                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
357                             }
358                         } else {
359                             buf.push(k, "=&");
360                         }
361                 }
362             }
363             buf.pop();
364             return buf.join("");
365         },
366          /**
367          * Safe version of encodeURIComponent
368          * @param {String} data 
369          * @return {String} 
370          */
371         
372         encodeURIComponent : function (data)
373         {
374             try {
375                 return encodeURIComponent(data);
376             } catch(e) {} // should be an uri encode error.
377             
378             if (data == '' || data == null){
379                return '';
380             }
381             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
382             function nibble_to_hex(nibble){
383                 var chars = '0123456789ABCDEF';
384                 return chars.charAt(nibble);
385             }
386             data = data.toString();
387             var buffer = '';
388             for(var i=0; i<data.length; i++){
389                 var c = data.charCodeAt(i);
390                 var bs = new Array();
391                 if (c > 0x10000){
392                         // 4 bytes
393                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
394                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
395                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
396                     bs[3] = 0x80 | (c & 0x3F);
397                 }else if (c > 0x800){
398                          // 3 bytes
399                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
400                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
401                     bs[2] = 0x80 | (c & 0x3F);
402                 }else if (c > 0x80){
403                        // 2 bytes
404                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
405                     bs[1] = 0x80 | (c & 0x3F);
406                 }else{
407                         // 1 byte
408                     bs[0] = c;
409                 }
410                 for(var j=0; j<bs.length; j++){
411                     var b = bs[j];
412                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
413                             + nibble_to_hex(b &0x0F);
414                     buffer += '%'+hex;
415                }
416             }
417             return buffer;    
418              
419         },
420
421         /**
422          * 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]}.
423          * @param {String} string
424          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
425          * @return {Object} A literal with members
426          */
427         urlDecode : function(string, overwrite){
428             if(!string || !string.length){
429                 return {};
430             }
431             var obj = {};
432             var pairs = string.split('&');
433             var pair, name, value;
434             for(var i = 0, len = pairs.length; i < len; i++){
435                 pair = pairs[i].split('=');
436                 name = decodeURIComponent(pair[0]);
437                 value = decodeURIComponent(pair[1]);
438                 if(overwrite !== true){
439                     if(typeof obj[name] == "undefined"){
440                         obj[name] = value;
441                     }else if(typeof obj[name] == "string"){
442                         obj[name] = [obj[name]];
443                         obj[name].push(value);
444                     }else{
445                         obj[name].push(value);
446                     }
447                 }else{
448                     obj[name] = value;
449                 }
450             }
451             return obj;
452         },
453
454         /**
455          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
456          * passed array is not really an array, your function is called once with it.
457          * The supplied function is called with (Object item, Number index, Array allItems).
458          * @param {Array/NodeList/Mixed} array
459          * @param {Function} fn
460          * @param {Object} scope
461          */
462         each : function(array, fn, scope){
463             if(typeof array.length == "undefined" || typeof array == "string"){
464                 array = [array];
465             }
466             for(var i = 0, len = array.length; i < len; i++){
467                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
468             }
469         },
470
471         // deprecated
472         combine : function(){
473             var as = arguments, l = as.length, r = [];
474             for(var i = 0; i < l; i++){
475                 var a = as[i];
476                 if(a instanceof Array){
477                     r = r.concat(a);
478                 }else if(a.length !== undefined && !a.substr){
479                     r = r.concat(Array.prototype.slice.call(a, 0));
480                 }else{
481                     r.push(a);
482                 }
483             }
484             return r;
485         },
486
487         /**
488          * Escapes the passed string for use in a regular expression
489          * @param {String} str
490          * @return {String}
491          */
492         escapeRe : function(s) {
493             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
494         },
495
496         // internal
497         callback : function(cb, scope, args, delay){
498             if(typeof cb == "function"){
499                 if(delay){
500                     cb.defer(delay, scope, args || []);
501                 }else{
502                     cb.apply(scope, args || []);
503                 }
504             }
505         },
506
507         /**
508          * Return the dom node for the passed string (id), dom node, or Roo.Element
509          * @param {String/HTMLElement/Roo.Element} el
510          * @return HTMLElement
511          */
512         getDom : function(el){
513             if(!el){
514                 return null;
515             }
516             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
517         },
518
519         /**
520         * Shorthand for {@link Roo.ComponentMgr#get}
521         * @param {String} id
522         * @return Roo.Component
523         */
524         getCmp : function(id){
525             return Roo.ComponentMgr.get(id);
526         },
527          
528         num : function(v, defaultValue){
529             if(typeof v != 'number'){
530                 return defaultValue;
531             }
532             return v;
533         },
534
535         destroy : function(){
536             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
537                 var as = a[i];
538                 if(as){
539                     if(as.dom){
540                         as.removeAllListeners();
541                         as.remove();
542                         continue;
543                     }
544                     if(typeof as.purgeListeners == 'function'){
545                         as.purgeListeners();
546                     }
547                     if(typeof as.destroy == 'function'){
548                         as.destroy();
549                     }
550                 }
551             }
552         },
553
554         // inpired by a similar function in mootools library
555         /**
556          * Returns the type of object that is passed in. If the object passed in is null or undefined it
557          * return false otherwise it returns one of the following values:<ul>
558          * <li><b>string</b>: If the object passed is a string</li>
559          * <li><b>number</b>: If the object passed is a number</li>
560          * <li><b>boolean</b>: If the object passed is a boolean value</li>
561          * <li><b>function</b>: If the object passed is a function reference</li>
562          * <li><b>object</b>: If the object passed is an object</li>
563          * <li><b>array</b>: If the object passed is an array</li>
564          * <li><b>regexp</b>: If the object passed is a regular expression</li>
565          * <li><b>element</b>: If the object passed is a DOM Element</li>
566          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
567          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
568          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
569          * @param {Mixed} object
570          * @return {String}
571          */
572         type : function(o){
573             if(o === undefined || o === null){
574                 return false;
575             }
576             if(o.htmlElement){
577                 return 'element';
578             }
579             var t = typeof o;
580             if(t == 'object' && o.nodeName) {
581                 switch(o.nodeType) {
582                     case 1: return 'element';
583                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
584                 }
585             }
586             if(t == 'object' || t == 'function') {
587                 switch(o.constructor) {
588                     case Array: return 'array';
589                     case RegExp: return 'regexp';
590                 }
591                 if(typeof o.length == 'number' && typeof o.item == 'function') {
592                     return 'nodelist';
593                 }
594             }
595             return t;
596         },
597
598         /**
599          * Returns true if the passed value is null, undefined or an empty string (optional).
600          * @param {Mixed} value The value to test
601          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
602          * @return {Boolean}
603          */
604         isEmpty : function(v, allowBlank){
605             return v === null || v === undefined || (!allowBlank ? v === '' : false);
606         },
607         
608         /** @type Boolean */
609         isOpera : isOpera,
610         /** @type Boolean */
611         isSafari : isSafari,
612         /** @type Boolean */
613         isIE : isIE,
614         /** @type Boolean */
615         isIE7 : isIE7,
616         /** @type Boolean */
617         isGecko : isGecko,
618         /** @type Boolean */
619         isBorderBox : isBorderBox,
620         /** @type Boolean */
621         isWindows : isWindows,
622         /** @type Boolean */
623         isLinux : isLinux,
624         /** @type Boolean */
625         isMac : isMac,
626         /** @type Boolean */
627         isTouch : isTouch,
628
629         /**
630          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
631          * you may want to set this to true.
632          * @type Boolean
633          */
634         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
635         
636         
637                 
638         /**
639          * Selects a single element as a Roo Element
640          * This is about as close as you can get to jQuery's $('do crazy stuff')
641          * @param {String} selector The selector/xpath query
642          * @param {Node} root (optional) The start of the query (defaults to document).
643          * @return {Roo.Element}
644          */
645         selectNode : function(selector, root) 
646         {
647             var node = Roo.DomQuery.selectNode(selector,root);
648             return node ? Roo.get(node) : new Roo.Element(false);
649         }
650         
651     });
652
653
654 })();
655
656 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
657                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
658                 "Roo.app", "Roo.ux",
659                 "Roo.bootstrap",
660                 "Roo.bootstrap.dash");
661 /*
662  * Based on:
663  * Ext JS Library 1.1.1
664  * Copyright(c) 2006-2007, Ext JS, LLC.
665  *
666  * Originally Released Under LGPL - original licence link has changed is not relivant.
667  *
668  * Fork - LGPL
669  * <script type="text/javascript">
670  */
671
672 (function() {    
673     // wrappedn so fnCleanup is not in global scope...
674     if(Roo.isIE) {
675         function fnCleanUp() {
676             var p = Function.prototype;
677             delete p.createSequence;
678             delete p.defer;
679             delete p.createDelegate;
680             delete p.createCallback;
681             delete p.createInterceptor;
682
683             window.detachEvent("onunload", fnCleanUp);
684         }
685         window.attachEvent("onunload", fnCleanUp);
686     }
687 })();
688
689
690 /**
691  * @class Function
692  * These functions are available on every Function object (any JavaScript function).
693  */
694 Roo.apply(Function.prototype, {
695      /**
696      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
697      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
698      * Will create a function that is bound to those 2 args.
699      * @return {Function} The new function
700     */
701     createCallback : function(/*args...*/){
702         // make args available, in function below
703         var args = arguments;
704         var method = this;
705         return function() {
706             return method.apply(window, args);
707         };
708     },
709
710     /**
711      * Creates a delegate (callback) that sets the scope to obj.
712      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
713      * Will create a function that is automatically scoped to this.
714      * @param {Object} obj (optional) The object for which the scope is set
715      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
716      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
717      *                                             if a number the args are inserted at the specified position
718      * @return {Function} The new function
719      */
720     createDelegate : function(obj, args, appendArgs){
721         var method = this;
722         return function() {
723             var callArgs = args || arguments;
724             if(appendArgs === true){
725                 callArgs = Array.prototype.slice.call(arguments, 0);
726                 callArgs = callArgs.concat(args);
727             }else if(typeof appendArgs == "number"){
728                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
729                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
730                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
731             }
732             return method.apply(obj || window, callArgs);
733         };
734     },
735
736     /**
737      * Calls this function after the number of millseconds specified.
738      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
739      * @param {Object} obj (optional) The object for which the scope is set
740      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
741      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
742      *                                             if a number the args are inserted at the specified position
743      * @return {Number} The timeout id that can be used with clearTimeout
744      */
745     defer : function(millis, obj, args, appendArgs){
746         var fn = this.createDelegate(obj, args, appendArgs);
747         if(millis){
748             return setTimeout(fn, millis);
749         }
750         fn();
751         return 0;
752     },
753     /**
754      * Create a combined function call sequence of the original function + the passed function.
755      * The resulting function returns the results of the original function.
756      * The passed fcn is called with the parameters of the original function
757      * @param {Function} fcn The function to sequence
758      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
759      * @return {Function} The new function
760      */
761     createSequence : function(fcn, scope){
762         if(typeof fcn != "function"){
763             return this;
764         }
765         var method = this;
766         return function() {
767             var retval = method.apply(this || window, arguments);
768             fcn.apply(scope || this || window, arguments);
769             return retval;
770         };
771     },
772
773     /**
774      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
775      * The resulting function returns the results of the original function.
776      * The passed fcn is called with the parameters of the original function.
777      * @addon
778      * @param {Function} fcn The function to call before the original
779      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
780      * @return {Function} The new function
781      */
782     createInterceptor : function(fcn, scope){
783         if(typeof fcn != "function"){
784             return this;
785         }
786         var method = this;
787         return function() {
788             fcn.target = this;
789             fcn.method = method;
790             if(fcn.apply(scope || this || window, arguments) === false){
791                 return;
792             }
793             return method.apply(this || window, arguments);
794         };
795     }
796 });
797 /*
798  * Based on:
799  * Ext JS Library 1.1.1
800  * Copyright(c) 2006-2007, Ext JS, LLC.
801  *
802  * Originally Released Under LGPL - original licence link has changed is not relivant.
803  *
804  * Fork - LGPL
805  * <script type="text/javascript">
806  */
807
808 Roo.applyIf(String, {
809     
810     /** @scope String */
811     
812     /**
813      * Escapes the passed string for ' and \
814      * @param {String} string The string to escape
815      * @return {String} The escaped string
816      * @static
817      */
818     escape : function(string) {
819         return string.replace(/('|\\)/g, "\\$1");
820     },
821
822     /**
823      * Pads the left side of a string with a specified character.  This is especially useful
824      * for normalizing number and date strings.  Example usage:
825      * <pre><code>
826 var s = String.leftPad('123', 5, '0');
827 // s now contains the string: '00123'
828 </code></pre>
829      * @param {String} string The original string
830      * @param {Number} size The total length of the output string
831      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
832      * @return {String} The padded string
833      * @static
834      */
835     leftPad : function (val, size, ch) {
836         var result = new String(val);
837         if(ch === null || ch === undefined || ch === '') {
838             ch = " ";
839         }
840         while (result.length < size) {
841             result = ch + result;
842         }
843         return result;
844     },
845
846     /**
847      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
848      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
849      * <pre><code>
850 var cls = 'my-class', text = 'Some text';
851 var s = String.format('<div class="{0}">{1}</div>', cls, text);
852 // s now contains the string: '<div class="my-class">Some text</div>'
853 </code></pre>
854      * @param {String} string The tokenized string to be formatted
855      * @param {String} value1 The value to replace token {0}
856      * @param {String} value2 Etc...
857      * @return {String} The formatted string
858      * @static
859      */
860     format : function(format){
861         var args = Array.prototype.slice.call(arguments, 1);
862         return format.replace(/\{(\d+)\}/g, function(m, i){
863             return Roo.util.Format.htmlEncode(args[i]);
864         });
865     }
866 });
867
868 /**
869  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
870  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
871  * they are already different, the first value passed in is returned.  Note that this method returns the new value
872  * but does not change the current string.
873  * <pre><code>
874 // alternate sort directions
875 sort = sort.toggle('ASC', 'DESC');
876
877 // instead of conditional logic:
878 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
879 </code></pre>
880  * @param {String} value The value to compare to the current string
881  * @param {String} other The new value to use if the string already equals the first value passed in
882  * @return {String} The new value
883  */
884  
885 String.prototype.toggle = function(value, other){
886     return this == value ? other : value;
887 };/*
888  * Based on:
889  * Ext JS Library 1.1.1
890  * Copyright(c) 2006-2007, Ext JS, LLC.
891  *
892  * Originally Released Under LGPL - original licence link has changed is not relivant.
893  *
894  * Fork - LGPL
895  * <script type="text/javascript">
896  */
897
898  /**
899  * @class Number
900  */
901 Roo.applyIf(Number.prototype, {
902     /**
903      * Checks whether or not the current number is within a desired range.  If the number is already within the
904      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
905      * exceeded.  Note that this method returns the constrained value but does not change the current number.
906      * @param {Number} min The minimum number in the range
907      * @param {Number} max The maximum number in the range
908      * @return {Number} The constrained value if outside the range, otherwise the current value
909      */
910     constrain : function(min, max){
911         return Math.min(Math.max(this, min), max);
912     }
913 });/*
914  * Based on:
915  * Ext JS Library 1.1.1
916  * Copyright(c) 2006-2007, Ext JS, LLC.
917  *
918  * Originally Released Under LGPL - original licence link has changed is not relivant.
919  *
920  * Fork - LGPL
921  * <script type="text/javascript">
922  */
923  /**
924  * @class Array
925  */
926 Roo.applyIf(Array.prototype, {
927     /**
928      * Checks whether or not the specified object exists in the array.
929      * @param {Object} o The object to check for
930      * @return {Number} The index of o in the array (or -1 if it is not found)
931      */
932     indexOf : function(o){
933        for (var i = 0, len = this.length; i < len; i++){
934               if(this[i] == o) return i;
935        }
936            return -1;
937     },
938
939     /**
940      * Removes the specified object from the array.  If the object is not found nothing happens.
941      * @param {Object} o The object to remove
942      */
943     remove : function(o){
944        var index = this.indexOf(o);
945        if(index != -1){
946            this.splice(index, 1);
947        }
948     },
949     /**
950      * Map (JS 1.6 compatibility)
951      * @param {Function} function  to call
952      */
953     map : function(fun )
954     {
955         var len = this.length >>> 0;
956         if (typeof fun != "function")
957             throw new TypeError();
958
959         var res = new Array(len);
960         var thisp = arguments[1];
961         for (var i = 0; i < len; i++)
962         {
963             if (i in this)
964                 res[i] = fun.call(thisp, this[i], i, this);
965         }
966
967         return res;
968     }
969     
970 });
971
972
973  /*
974  * Based on:
975  * Ext JS Library 1.1.1
976  * Copyright(c) 2006-2007, Ext JS, LLC.
977  *
978  * Originally Released Under LGPL - original licence link has changed is not relivant.
979  *
980  * Fork - LGPL
981  * <script type="text/javascript">
982  */
983
984 /**
985  * @class Date
986  *
987  * The date parsing and format syntax is a subset of
988  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
989  * supported will provide results equivalent to their PHP versions.
990  *
991  * Following is the list of all currently supported formats:
992  *<pre>
993 Sample date:
994 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
995
996 Format  Output      Description
997 ------  ----------  --------------------------------------------------------------
998   d      10         Day of the month, 2 digits with leading zeros
999   D      Wed        A textual representation of a day, three letters
1000   j      10         Day of the month without leading zeros
1001   l      Wednesday  A full textual representation of the day of the week
1002   S      th         English ordinal day of month suffix, 2 chars (use with j)
1003   w      3          Numeric representation of the day of the week
1004   z      9          The julian date, or day of the year (0-365)
1005   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1006   F      January    A full textual representation of the month
1007   m      01         Numeric representation of a month, with leading zeros
1008   M      Jan        Month name abbreviation, three letters
1009   n      1          Numeric representation of a month, without leading zeros
1010   t      31         Number of days in the given month
1011   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1012   Y      2007       A full numeric representation of a year, 4 digits
1013   y      07         A two digit representation of a year
1014   a      pm         Lowercase Ante meridiem and Post meridiem
1015   A      PM         Uppercase Ante meridiem and Post meridiem
1016   g      3          12-hour format of an hour without leading zeros
1017   G      15         24-hour format of an hour without leading zeros
1018   h      03         12-hour format of an hour with leading zeros
1019   H      15         24-hour format of an hour with leading zeros
1020   i      05         Minutes with leading zeros
1021   s      01         Seconds, with leading zeros
1022   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1023   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1024   T      CST        Timezone setting of the machine running the code
1025   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1026 </pre>
1027  *
1028  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1029  * <pre><code>
1030 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1031 document.write(dt.format('Y-m-d'));                         //2007-01-10
1032 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1033 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
1034  </code></pre>
1035  *
1036  * Here are some standard date/time patterns that you might find helpful.  They
1037  * are not part of the source of Date.js, but to use them you can simply copy this
1038  * block of code into any script that is included after Date.js and they will also become
1039  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1040  * <pre><code>
1041 Date.patterns = {
1042     ISO8601Long:"Y-m-d H:i:s",
1043     ISO8601Short:"Y-m-d",
1044     ShortDate: "n/j/Y",
1045     LongDate: "l, F d, Y",
1046     FullDateTime: "l, F d, Y g:i:s A",
1047     MonthDay: "F d",
1048     ShortTime: "g:i A",
1049     LongTime: "g:i:s A",
1050     SortableDateTime: "Y-m-d\\TH:i:s",
1051     UniversalSortableDateTime: "Y-m-d H:i:sO",
1052     YearMonth: "F, Y"
1053 };
1054 </code></pre>
1055  *
1056  * Example usage:
1057  * <pre><code>
1058 var dt = new Date();
1059 document.write(dt.format(Date.patterns.ShortDate));
1060  </code></pre>
1061  */
1062
1063 /*
1064  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1065  * They generate precompiled functions from date formats instead of parsing and
1066  * processing the pattern every time you format a date.  These functions are available
1067  * on every Date object (any javascript function).
1068  *
1069  * The original article and download are here:
1070  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1071  *
1072  */
1073  
1074  
1075  // was in core
1076 /**
1077  Returns the number of milliseconds between this date and date
1078  @param {Date} date (optional) Defaults to now
1079  @return {Number} The diff in milliseconds
1080  @member Date getElapsed
1081  */
1082 Date.prototype.getElapsed = function(date) {
1083         return Math.abs((date || new Date()).getTime()-this.getTime());
1084 };
1085 // was in date file..
1086
1087
1088 // private
1089 Date.parseFunctions = {count:0};
1090 // private
1091 Date.parseRegexes = [];
1092 // private
1093 Date.formatFunctions = {count:0};
1094
1095 // private
1096 Date.prototype.dateFormat = function(format) {
1097     if (Date.formatFunctions[format] == null) {
1098         Date.createNewFormat(format);
1099     }
1100     var func = Date.formatFunctions[format];
1101     return this[func]();
1102 };
1103
1104
1105 /**
1106  * Formats a date given the supplied format string
1107  * @param {String} format The format string
1108  * @return {String} The formatted date
1109  * @method
1110  */
1111 Date.prototype.format = Date.prototype.dateFormat;
1112
1113 // private
1114 Date.createNewFormat = function(format) {
1115     var funcName = "format" + Date.formatFunctions.count++;
1116     Date.formatFunctions[format] = funcName;
1117     var code = "Date.prototype." + funcName + " = function(){return ";
1118     var special = false;
1119     var ch = '';
1120     for (var i = 0; i < format.length; ++i) {
1121         ch = format.charAt(i);
1122         if (!special && ch == "\\") {
1123             special = true;
1124         }
1125         else if (special) {
1126             special = false;
1127             code += "'" + String.escape(ch) + "' + ";
1128         }
1129         else {
1130             code += Date.getFormatCode(ch);
1131         }
1132     }
1133     /** eval:var:zzzzzzzzzzzzz */
1134     eval(code.substring(0, code.length - 3) + ";}");
1135 };
1136
1137 // private
1138 Date.getFormatCode = function(character) {
1139     switch (character) {
1140     case "d":
1141         return "String.leftPad(this.getDate(), 2, '0') + ";
1142     case "D":
1143         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1144     case "j":
1145         return "this.getDate() + ";
1146     case "l":
1147         return "Date.dayNames[this.getDay()] + ";
1148     case "S":
1149         return "this.getSuffix() + ";
1150     case "w":
1151         return "this.getDay() + ";
1152     case "z":
1153         return "this.getDayOfYear() + ";
1154     case "W":
1155         return "this.getWeekOfYear() + ";
1156     case "F":
1157         return "Date.monthNames[this.getMonth()] + ";
1158     case "m":
1159         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1160     case "M":
1161         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1162     case "n":
1163         return "(this.getMonth() + 1) + ";
1164     case "t":
1165         return "this.getDaysInMonth() + ";
1166     case "L":
1167         return "(this.isLeapYear() ? 1 : 0) + ";
1168     case "Y":
1169         return "this.getFullYear() + ";
1170     case "y":
1171         return "('' + this.getFullYear()).substring(2, 4) + ";
1172     case "a":
1173         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1174     case "A":
1175         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1176     case "g":
1177         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1178     case "G":
1179         return "this.getHours() + ";
1180     case "h":
1181         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1182     case "H":
1183         return "String.leftPad(this.getHours(), 2, '0') + ";
1184     case "i":
1185         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1186     case "s":
1187         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1188     case "O":
1189         return "this.getGMTOffset() + ";
1190     case "P":
1191         return "this.getGMTColonOffset() + ";
1192     case "T":
1193         return "this.getTimezone() + ";
1194     case "Z":
1195         return "(this.getTimezoneOffset() * -60) + ";
1196     default:
1197         return "'" + String.escape(character) + "' + ";
1198     }
1199 };
1200
1201 /**
1202  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1203  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1204  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1205  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1206  * string or the parse operation will fail.
1207  * Example Usage:
1208 <pre><code>
1209 //dt = Fri May 25 2007 (current date)
1210 var dt = new Date();
1211
1212 //dt = Thu May 25 2006 (today's month/day in 2006)
1213 dt = Date.parseDate("2006", "Y");
1214
1215 //dt = Sun Jan 15 2006 (all date parts specified)
1216 dt = Date.parseDate("2006-1-15", "Y-m-d");
1217
1218 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1219 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1220 </code></pre>
1221  * @param {String} input The unparsed date as a string
1222  * @param {String} format The format the date is in
1223  * @return {Date} The parsed date
1224  * @static
1225  */
1226 Date.parseDate = function(input, format) {
1227     if (Date.parseFunctions[format] == null) {
1228         Date.createParser(format);
1229     }
1230     var func = Date.parseFunctions[format];
1231     return Date[func](input);
1232 };
1233 /**
1234  * @private
1235  */
1236 Date.createParser = function(format) {
1237     var funcName = "parse" + Date.parseFunctions.count++;
1238     var regexNum = Date.parseRegexes.length;
1239     var currentGroup = 1;
1240     Date.parseFunctions[format] = funcName;
1241
1242     var code = "Date." + funcName + " = function(input){\n"
1243         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1244         + "var d = new Date();\n"
1245         + "y = d.getFullYear();\n"
1246         + "m = d.getMonth();\n"
1247         + "d = d.getDate();\n"
1248         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1249         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1250         + "if (results && results.length > 0) {";
1251     var regex = "";
1252
1253     var special = false;
1254     var ch = '';
1255     for (var i = 0; i < format.length; ++i) {
1256         ch = format.charAt(i);
1257         if (!special && ch == "\\") {
1258             special = true;
1259         }
1260         else if (special) {
1261             special = false;
1262             regex += String.escape(ch);
1263         }
1264         else {
1265             var obj = Date.formatCodeToRegex(ch, currentGroup);
1266             currentGroup += obj.g;
1267             regex += obj.s;
1268             if (obj.g && obj.c) {
1269                 code += obj.c;
1270             }
1271         }
1272     }
1273
1274     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1275         + "{v = new Date(y, m, d, h, i, s);}\n"
1276         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1277         + "{v = new Date(y, m, d, h, i);}\n"
1278         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1279         + "{v = new Date(y, m, d, h);}\n"
1280         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1281         + "{v = new Date(y, m, d);}\n"
1282         + "else if (y >= 0 && m >= 0)\n"
1283         + "{v = new Date(y, m);}\n"
1284         + "else if (y >= 0)\n"
1285         + "{v = new Date(y);}\n"
1286         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1287         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1288         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1289         + ";}";
1290
1291     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1292     /** eval:var:zzzzzzzzzzzzz */
1293     eval(code);
1294 };
1295
1296 // private
1297 Date.formatCodeToRegex = function(character, currentGroup) {
1298     switch (character) {
1299     case "D":
1300         return {g:0,
1301         c:null,
1302         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1303     case "j":
1304         return {g:1,
1305             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1306             s:"(\\d{1,2})"}; // day of month without leading zeroes
1307     case "d":
1308         return {g:1,
1309             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1310             s:"(\\d{2})"}; // day of month with leading zeroes
1311     case "l":
1312         return {g:0,
1313             c:null,
1314             s:"(?:" + Date.dayNames.join("|") + ")"};
1315     case "S":
1316         return {g:0,
1317             c:null,
1318             s:"(?:st|nd|rd|th)"};
1319     case "w":
1320         return {g:0,
1321             c:null,
1322             s:"\\d"};
1323     case "z":
1324         return {g:0,
1325             c:null,
1326             s:"(?:\\d{1,3})"};
1327     case "W":
1328         return {g:0,
1329             c:null,
1330             s:"(?:\\d{2})"};
1331     case "F":
1332         return {g:1,
1333             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1334             s:"(" + Date.monthNames.join("|") + ")"};
1335     case "M":
1336         return {g:1,
1337             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1338             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1339     case "n":
1340         return {g:1,
1341             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1342             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1343     case "m":
1344         return {g:1,
1345             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1346             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1347     case "t":
1348         return {g:0,
1349             c:null,
1350             s:"\\d{1,2}"};
1351     case "L":
1352         return {g:0,
1353             c:null,
1354             s:"(?:1|0)"};
1355     case "Y":
1356         return {g:1,
1357             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1358             s:"(\\d{4})"};
1359     case "y":
1360         return {g:1,
1361             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1362                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1363             s:"(\\d{1,2})"};
1364     case "a":
1365         return {g:1,
1366             c:"if (results[" + currentGroup + "] == 'am') {\n"
1367                 + "if (h == 12) { h = 0; }\n"
1368                 + "} else { if (h < 12) { h += 12; }}",
1369             s:"(am|pm)"};
1370     case "A":
1371         return {g:1,
1372             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1373                 + "if (h == 12) { h = 0; }\n"
1374                 + "} else { if (h < 12) { h += 12; }}",
1375             s:"(AM|PM)"};
1376     case "g":
1377     case "G":
1378         return {g:1,
1379             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1380             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1381     case "h":
1382     case "H":
1383         return {g:1,
1384             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1385             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1386     case "i":
1387         return {g:1,
1388             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1389             s:"(\\d{2})"};
1390     case "s":
1391         return {g:1,
1392             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1393             s:"(\\d{2})"};
1394     case "O":
1395         return {g:1,
1396             c:[
1397                 "o = results[", currentGroup, "];\n",
1398                 "var sn = o.substring(0,1);\n", // get + / - sign
1399                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1400                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1401                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1402                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1403             ].join(""),
1404             s:"([+\-]\\d{2,4})"};
1405     
1406     
1407     case "P":
1408         return {g:1,
1409                 c:[
1410                    "o = results[", currentGroup, "];\n",
1411                    "var sn = o.substring(0,1);\n",
1412                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1413                    "var mn = o.substring(4,6) % 60;\n",
1414                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1415                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1416             ].join(""),
1417             s:"([+\-]\\d{4})"};
1418     case "T":
1419         return {g:0,
1420             c:null,
1421             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1422     case "Z":
1423         return {g:1,
1424             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1425                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1426             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1427     default:
1428         return {g:0,
1429             c:null,
1430             s:String.escape(character)};
1431     }
1432 };
1433
1434 /**
1435  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1436  * @return {String} The abbreviated timezone name (e.g. 'CST')
1437  */
1438 Date.prototype.getTimezone = function() {
1439     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1440 };
1441
1442 /**
1443  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1444  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1445  */
1446 Date.prototype.getGMTOffset = function() {
1447     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1448         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1449         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1450 };
1451
1452 /**
1453  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1454  * @return {String} 2-characters representing hours and 2-characters representing minutes
1455  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1456  */
1457 Date.prototype.getGMTColonOffset = function() {
1458         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1459                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1460                 + ":"
1461                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1462 }
1463
1464 /**
1465  * Get the numeric day number of the year, adjusted for leap year.
1466  * @return {Number} 0 through 364 (365 in leap years)
1467  */
1468 Date.prototype.getDayOfYear = function() {
1469     var num = 0;
1470     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1471     for (var i = 0; i < this.getMonth(); ++i) {
1472         num += Date.daysInMonth[i];
1473     }
1474     return num + this.getDate() - 1;
1475 };
1476
1477 /**
1478  * Get the string representation of the numeric week number of the year
1479  * (equivalent to the format specifier 'W').
1480  * @return {String} '00' through '52'
1481  */
1482 Date.prototype.getWeekOfYear = function() {
1483     // Skip to Thursday of this week
1484     var now = this.getDayOfYear() + (4 - this.getDay());
1485     // Find the first Thursday of the year
1486     var jan1 = new Date(this.getFullYear(), 0, 1);
1487     var then = (7 - jan1.getDay() + 4);
1488     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1489 };
1490
1491 /**
1492  * Whether or not the current date is in a leap year.
1493  * @return {Boolean} True if the current date is in a leap year, else false
1494  */
1495 Date.prototype.isLeapYear = function() {
1496     var year = this.getFullYear();
1497     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1498 };
1499
1500 /**
1501  * Get the first day of the current month, adjusted for leap year.  The returned value
1502  * is the numeric day index within the week (0-6) which can be used in conjunction with
1503  * the {@link #monthNames} array to retrieve the textual day name.
1504  * Example:
1505  *<pre><code>
1506 var dt = new Date('1/10/2007');
1507 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1508 </code></pre>
1509  * @return {Number} The day number (0-6)
1510  */
1511 Date.prototype.getFirstDayOfMonth = function() {
1512     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1513     return (day < 0) ? (day + 7) : day;
1514 };
1515
1516 /**
1517  * Get the last day of the current month, adjusted for leap year.  The returned value
1518  * is the numeric day index within the week (0-6) which can be used in conjunction with
1519  * the {@link #monthNames} array to retrieve the textual day name.
1520  * Example:
1521  *<pre><code>
1522 var dt = new Date('1/10/2007');
1523 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1524 </code></pre>
1525  * @return {Number} The day number (0-6)
1526  */
1527 Date.prototype.getLastDayOfMonth = function() {
1528     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1529     return (day < 0) ? (day + 7) : day;
1530 };
1531
1532
1533 /**
1534  * Get the first date of this date's month
1535  * @return {Date}
1536  */
1537 Date.prototype.getFirstDateOfMonth = function() {
1538     return new Date(this.getFullYear(), this.getMonth(), 1);
1539 };
1540
1541 /**
1542  * Get the last date of this date's month
1543  * @return {Date}
1544  */
1545 Date.prototype.getLastDateOfMonth = function() {
1546     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1547 };
1548 /**
1549  * Get the number of days in the current month, adjusted for leap year.
1550  * @return {Number} The number of days in the month
1551  */
1552 Date.prototype.getDaysInMonth = function() {
1553     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1554     return Date.daysInMonth[this.getMonth()];
1555 };
1556
1557 /**
1558  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1559  * @return {String} 'st, 'nd', 'rd' or 'th'
1560  */
1561 Date.prototype.getSuffix = function() {
1562     switch (this.getDate()) {
1563         case 1:
1564         case 21:
1565         case 31:
1566             return "st";
1567         case 2:
1568         case 22:
1569             return "nd";
1570         case 3:
1571         case 23:
1572             return "rd";
1573         default:
1574             return "th";
1575     }
1576 };
1577
1578 // private
1579 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1580
1581 /**
1582  * An array of textual month names.
1583  * Override these values for international dates, for example...
1584  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1585  * @type Array
1586  * @static
1587  */
1588 Date.monthNames =
1589    ["January",
1590     "February",
1591     "March",
1592     "April",
1593     "May",
1594     "June",
1595     "July",
1596     "August",
1597     "September",
1598     "October",
1599     "November",
1600     "December"];
1601
1602 /**
1603  * An array of textual day names.
1604  * Override these values for international dates, for example...
1605  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1606  * @type Array
1607  * @static
1608  */
1609 Date.dayNames =
1610    ["Sunday",
1611     "Monday",
1612     "Tuesday",
1613     "Wednesday",
1614     "Thursday",
1615     "Friday",
1616     "Saturday"];
1617
1618 // private
1619 Date.y2kYear = 50;
1620 // private
1621 Date.monthNumbers = {
1622     Jan:0,
1623     Feb:1,
1624     Mar:2,
1625     Apr:3,
1626     May:4,
1627     Jun:5,
1628     Jul:6,
1629     Aug:7,
1630     Sep:8,
1631     Oct:9,
1632     Nov:10,
1633     Dec:11};
1634
1635 /**
1636  * Creates and returns a new Date instance with the exact same date value as the called instance.
1637  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1638  * variable will also be changed.  When the intention is to create a new variable that will not
1639  * modify the original instance, you should create a clone.
1640  *
1641  * Example of correctly cloning a date:
1642  * <pre><code>
1643 //wrong way:
1644 var orig = new Date('10/1/2006');
1645 var copy = orig;
1646 copy.setDate(5);
1647 document.write(orig);  //returns 'Thu Oct 05 2006'!
1648
1649 //correct way:
1650 var orig = new Date('10/1/2006');
1651 var copy = orig.clone();
1652 copy.setDate(5);
1653 document.write(orig);  //returns 'Thu Oct 01 2006'
1654 </code></pre>
1655  * @return {Date} The new Date instance
1656  */
1657 Date.prototype.clone = function() {
1658         return new Date(this.getTime());
1659 };
1660
1661 /**
1662  * Clears any time information from this date
1663  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1664  @return {Date} this or the clone
1665  */
1666 Date.prototype.clearTime = function(clone){
1667     if(clone){
1668         return this.clone().clearTime();
1669     }
1670     this.setHours(0);
1671     this.setMinutes(0);
1672     this.setSeconds(0);
1673     this.setMilliseconds(0);
1674     return this;
1675 };
1676
1677 // private
1678 // safari setMonth is broken
1679 if(Roo.isSafari){
1680     Date.brokenSetMonth = Date.prototype.setMonth;
1681         Date.prototype.setMonth = function(num){
1682                 if(num <= -1){
1683                         var n = Math.ceil(-num);
1684                         var back_year = Math.ceil(n/12);
1685                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1686                         this.setFullYear(this.getFullYear() - back_year);
1687                         return Date.brokenSetMonth.call(this, month);
1688                 } else {
1689                         return Date.brokenSetMonth.apply(this, arguments);
1690                 }
1691         };
1692 }
1693
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.MILLI = "ms";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.SECOND = "s";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MINUTE = "mi";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.HOUR = "h";
1710 /** Date interval constant 
1711 * @static 
1712 * @type String */
1713 Date.DAY = "d";
1714 /** Date interval constant 
1715 * @static 
1716 * @type String */
1717 Date.MONTH = "mo";
1718 /** Date interval constant 
1719 * @static 
1720 * @type String */
1721 Date.YEAR = "y";
1722
1723 /**
1724  * Provides a convenient method of performing basic date arithmetic.  This method
1725  * does not modify the Date instance being called - it creates and returns
1726  * a new Date instance containing the resulting date value.
1727  *
1728  * Examples:
1729  * <pre><code>
1730 //Basic usage:
1731 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1732 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1733
1734 //Negative values will subtract correctly:
1735 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1736 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1737
1738 //You can even chain several calls together in one line!
1739 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1740 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1741  </code></pre>
1742  *
1743  * @param {String} interval   A valid date interval enum value
1744  * @param {Number} value      The amount to add to the current date
1745  * @return {Date} The new Date instance
1746  */
1747 Date.prototype.add = function(interval, value){
1748   var d = this.clone();
1749   if (!interval || value === 0) return d;
1750   switch(interval.toLowerCase()){
1751     case Date.MILLI:
1752       d.setMilliseconds(this.getMilliseconds() + value);
1753       break;
1754     case Date.SECOND:
1755       d.setSeconds(this.getSeconds() + value);
1756       break;
1757     case Date.MINUTE:
1758       d.setMinutes(this.getMinutes() + value);
1759       break;
1760     case Date.HOUR:
1761       d.setHours(this.getHours() + value);
1762       break;
1763     case Date.DAY:
1764       d.setDate(this.getDate() + value);
1765       break;
1766     case Date.MONTH:
1767       var day = this.getDate();
1768       if(day > 28){
1769           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1770       }
1771       d.setDate(day);
1772       d.setMonth(this.getMonth() + value);
1773       break;
1774     case Date.YEAR:
1775       d.setFullYear(this.getFullYear() + value);
1776       break;
1777   }
1778   return d;
1779 };
1780 /*
1781  * Based on:
1782  * Ext JS Library 1.1.1
1783  * Copyright(c) 2006-2007, Ext JS, LLC.
1784  *
1785  * Originally Released Under LGPL - original licence link has changed is not relivant.
1786  *
1787  * Fork - LGPL
1788  * <script type="text/javascript">
1789  */
1790
1791 /**
1792  * @class Roo.lib.Dom
1793  * @static
1794  * 
1795  * Dom utils (from YIU afaik)
1796  * 
1797  **/
1798 Roo.lib.Dom = {
1799     /**
1800      * Get the view width
1801      * @param {Boolean} full True will get the full document, otherwise it's the view width
1802      * @return {Number} The width
1803      */
1804      
1805     getViewWidth : function(full) {
1806         return full ? this.getDocumentWidth() : this.getViewportWidth();
1807     },
1808     /**
1809      * Get the view height
1810      * @param {Boolean} full True will get the full document, otherwise it's the view height
1811      * @return {Number} The height
1812      */
1813     getViewHeight : function(full) {
1814         return full ? this.getDocumentHeight() : this.getViewportHeight();
1815     },
1816
1817     getDocumentHeight: function() {
1818         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1819         return Math.max(scrollHeight, this.getViewportHeight());
1820     },
1821
1822     getDocumentWidth: function() {
1823         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1824         return Math.max(scrollWidth, this.getViewportWidth());
1825     },
1826
1827     getViewportHeight: function() {
1828         var height = self.innerHeight;
1829         var mode = document.compatMode;
1830
1831         if ((mode || Roo.isIE) && !Roo.isOpera) {
1832             height = (mode == "CSS1Compat") ?
1833                      document.documentElement.clientHeight :
1834                      document.body.clientHeight;
1835         }
1836
1837         return height;
1838     },
1839
1840     getViewportWidth: function() {
1841         var width = self.innerWidth;
1842         var mode = document.compatMode;
1843
1844         if (mode || Roo.isIE) {
1845             width = (mode == "CSS1Compat") ?
1846                     document.documentElement.clientWidth :
1847                     document.body.clientWidth;
1848         }
1849         return width;
1850     },
1851
1852     isAncestor : function(p, c) {
1853         p = Roo.getDom(p);
1854         c = Roo.getDom(c);
1855         if (!p || !c) {
1856             return false;
1857         }
1858
1859         if (p.contains && !Roo.isSafari) {
1860             return p.contains(c);
1861         } else if (p.compareDocumentPosition) {
1862             return !!(p.compareDocumentPosition(c) & 16);
1863         } else {
1864             var parent = c.parentNode;
1865             while (parent) {
1866                 if (parent == p) {
1867                     return true;
1868                 }
1869                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1870                     return false;
1871                 }
1872                 parent = parent.parentNode;
1873             }
1874             return false;
1875         }
1876     },
1877
1878     getRegion : function(el) {
1879         return Roo.lib.Region.getRegion(el);
1880     },
1881
1882     getY : function(el) {
1883         return this.getXY(el)[1];
1884     },
1885
1886     getX : function(el) {
1887         return this.getXY(el)[0];
1888     },
1889
1890     getXY : function(el) {
1891         var p, pe, b, scroll, bd = document.body;
1892         el = Roo.getDom(el);
1893         var fly = Roo.lib.AnimBase.fly;
1894         if (el.getBoundingClientRect) {
1895             b = el.getBoundingClientRect();
1896             scroll = fly(document).getScroll();
1897             return [b.left + scroll.left, b.top + scroll.top];
1898         }
1899         var x = 0, y = 0;
1900
1901         p = el;
1902
1903         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1904
1905         while (p) {
1906
1907             x += p.offsetLeft;
1908             y += p.offsetTop;
1909
1910             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1911                 hasAbsolute = true;
1912             }
1913
1914             if (Roo.isGecko) {
1915                 pe = fly(p);
1916
1917                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1918                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1919
1920
1921                 x += bl;
1922                 y += bt;
1923
1924
1925                 if (p != el && pe.getStyle('overflow') != 'visible') {
1926                     x += bl;
1927                     y += bt;
1928                 }
1929             }
1930             p = p.offsetParent;
1931         }
1932
1933         if (Roo.isSafari && hasAbsolute) {
1934             x -= bd.offsetLeft;
1935             y -= bd.offsetTop;
1936         }
1937
1938         if (Roo.isGecko && !hasAbsolute) {
1939             var dbd = fly(bd);
1940             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1941             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1942         }
1943
1944         p = el.parentNode;
1945         while (p && p != bd) {
1946             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1947                 x -= p.scrollLeft;
1948                 y -= p.scrollTop;
1949             }
1950             p = p.parentNode;
1951         }
1952         return [x, y];
1953     },
1954  
1955   
1956
1957
1958     setXY : function(el, xy) {
1959         el = Roo.fly(el, '_setXY');
1960         el.position();
1961         var pts = el.translatePoints(xy);
1962         if (xy[0] !== false) {
1963             el.dom.style.left = pts.left + "px";
1964         }
1965         if (xy[1] !== false) {
1966             el.dom.style.top = pts.top + "px";
1967         }
1968     },
1969
1970     setX : function(el, x) {
1971         this.setXY(el, [x, false]);
1972     },
1973
1974     setY : function(el, y) {
1975         this.setXY(el, [false, y]);
1976     }
1977 };
1978 /*
1979  * Portions of this file are based on pieces of Yahoo User Interface Library
1980  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1981  * YUI licensed under the BSD License:
1982  * http://developer.yahoo.net/yui/license.txt
1983  * <script type="text/javascript">
1984  *
1985  */
1986
1987 Roo.lib.Event = function() {
1988     var loadComplete = false;
1989     var listeners = [];
1990     var unloadListeners = [];
1991     var retryCount = 0;
1992     var onAvailStack = [];
1993     var counter = 0;
1994     var lastError = null;
1995
1996     return {
1997         POLL_RETRYS: 200,
1998         POLL_INTERVAL: 20,
1999         EL: 0,
2000         TYPE: 1,
2001         FN: 2,
2002         WFN: 3,
2003         OBJ: 3,
2004         ADJ_SCOPE: 4,
2005         _interval: null,
2006
2007         startInterval: function() {
2008             if (!this._interval) {
2009                 var self = this;
2010                 var callback = function() {
2011                     self._tryPreloadAttach();
2012                 };
2013                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2014
2015             }
2016         },
2017
2018         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2019             onAvailStack.push({ id:         p_id,
2020                 fn:         p_fn,
2021                 obj:        p_obj,
2022                 override:   p_override,
2023                 checkReady: false    });
2024
2025             retryCount = this.POLL_RETRYS;
2026             this.startInterval();
2027         },
2028
2029
2030         addListener: function(el, eventName, fn) {
2031             el = Roo.getDom(el);
2032             if (!el || !fn) {
2033                 return false;
2034             }
2035
2036             if ("unload" == eventName) {
2037                 unloadListeners[unloadListeners.length] =
2038                 [el, eventName, fn];
2039                 return true;
2040             }
2041
2042             var wrappedFn = function(e) {
2043                 return fn(Roo.lib.Event.getEvent(e));
2044             };
2045
2046             var li = [el, eventName, fn, wrappedFn];
2047
2048             var index = listeners.length;
2049             listeners[index] = li;
2050
2051             this.doAdd(el, eventName, wrappedFn, false);
2052             return true;
2053
2054         },
2055
2056
2057         removeListener: function(el, eventName, fn) {
2058             var i, len;
2059
2060             el = Roo.getDom(el);
2061
2062             if(!fn) {
2063                 return this.purgeElement(el, false, eventName);
2064             }
2065
2066
2067             if ("unload" == eventName) {
2068
2069                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2070                     var li = unloadListeners[i];
2071                     if (li &&
2072                         li[0] == el &&
2073                         li[1] == eventName &&
2074                         li[2] == fn) {
2075                         unloadListeners.splice(i, 1);
2076                         return true;
2077                     }
2078                 }
2079
2080                 return false;
2081             }
2082
2083             var cacheItem = null;
2084
2085
2086             var index = arguments[3];
2087
2088             if ("undefined" == typeof index) {
2089                 index = this._getCacheIndex(el, eventName, fn);
2090             }
2091
2092             if (index >= 0) {
2093                 cacheItem = listeners[index];
2094             }
2095
2096             if (!el || !cacheItem) {
2097                 return false;
2098             }
2099
2100             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2101
2102             delete listeners[index][this.WFN];
2103             delete listeners[index][this.FN];
2104             listeners.splice(index, 1);
2105
2106             return true;
2107
2108         },
2109
2110
2111         getTarget: function(ev, resolveTextNode) {
2112             ev = ev.browserEvent || ev;
2113             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2114             var t = ev.target || ev.srcElement;
2115             return this.resolveTextNode(t);
2116         },
2117
2118
2119         resolveTextNode: function(node) {
2120             if (Roo.isSafari && node && 3 == node.nodeType) {
2121                 return node.parentNode;
2122             } else {
2123                 return node;
2124             }
2125         },
2126
2127
2128         getPageX: function(ev) {
2129             ev = ev.browserEvent || ev;
2130             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2131             var x = ev.pageX;
2132             if (!x && 0 !== x) {
2133                 x = ev.clientX || 0;
2134
2135                 if (Roo.isIE) {
2136                     x += this.getScroll()[1];
2137                 }
2138             }
2139
2140             return x;
2141         },
2142
2143
2144         getPageY: function(ev) {
2145             ev = ev.browserEvent || ev;
2146             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2147             var y = ev.pageY;
2148             if (!y && 0 !== y) {
2149                 y = ev.clientY || 0;
2150
2151                 if (Roo.isIE) {
2152                     y += this.getScroll()[0];
2153                 }
2154             }
2155
2156
2157             return y;
2158         },
2159
2160
2161         getXY: function(ev) {
2162             ev = ev.browserEvent || ev;
2163             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2164             return [this.getPageX(ev), this.getPageY(ev)];
2165         },
2166
2167
2168         getRelatedTarget: function(ev) {
2169             ev = ev.browserEvent || ev;
2170             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2171             var t = ev.relatedTarget;
2172             if (!t) {
2173                 if (ev.type == "mouseout") {
2174                     t = ev.toElement;
2175                 } else if (ev.type == "mouseover") {
2176                     t = ev.fromElement;
2177                 }
2178             }
2179
2180             return this.resolveTextNode(t);
2181         },
2182
2183
2184         getTime: function(ev) {
2185             ev = ev.browserEvent || ev;
2186             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2187             if (!ev.time) {
2188                 var t = new Date().getTime();
2189                 try {
2190                     ev.time = t;
2191                 } catch(ex) {
2192                     this.lastError = ex;
2193                     return t;
2194                 }
2195             }
2196
2197             return ev.time;
2198         },
2199
2200
2201         stopEvent: function(ev) {
2202             this.stopPropagation(ev);
2203             this.preventDefault(ev);
2204         },
2205
2206
2207         stopPropagation: function(ev) {
2208             ev = ev.browserEvent || ev;
2209             if (ev.stopPropagation) {
2210                 ev.stopPropagation();
2211             } else {
2212                 ev.cancelBubble = true;
2213             }
2214         },
2215
2216
2217         preventDefault: function(ev) {
2218             ev = ev.browserEvent || ev;
2219             if(ev.preventDefault) {
2220                 ev.preventDefault();
2221             } else {
2222                 ev.returnValue = false;
2223             }
2224         },
2225
2226
2227         getEvent: function(e) {
2228             var ev = e || window.event;
2229             if (!ev) {
2230                 var c = this.getEvent.caller;
2231                 while (c) {
2232                     ev = c.arguments[0];
2233                     if (ev && Event == ev.constructor) {
2234                         break;
2235                     }
2236                     c = c.caller;
2237                 }
2238             }
2239             return ev;
2240         },
2241
2242
2243         getCharCode: function(ev) {
2244             ev = ev.browserEvent || ev;
2245             return ev.charCode || ev.keyCode || 0;
2246         },
2247
2248
2249         _getCacheIndex: function(el, eventName, fn) {
2250             for (var i = 0,len = listeners.length; i < len; ++i) {
2251                 var li = listeners[i];
2252                 if (li &&
2253                     li[this.FN] == fn &&
2254                     li[this.EL] == el &&
2255                     li[this.TYPE] == eventName) {
2256                     return i;
2257                 }
2258             }
2259
2260             return -1;
2261         },
2262
2263
2264         elCache: {},
2265
2266
2267         getEl: function(id) {
2268             return document.getElementById(id);
2269         },
2270
2271
2272         clearCache: function() {
2273         },
2274
2275
2276         _load: function(e) {
2277             loadComplete = true;
2278             var EU = Roo.lib.Event;
2279
2280
2281             if (Roo.isIE) {
2282                 EU.doRemove(window, "load", EU._load);
2283             }
2284         },
2285
2286
2287         _tryPreloadAttach: function() {
2288
2289             if (this.locked) {
2290                 return false;
2291             }
2292
2293             this.locked = true;
2294
2295
2296             var tryAgain = !loadComplete;
2297             if (!tryAgain) {
2298                 tryAgain = (retryCount > 0);
2299             }
2300
2301
2302             var notAvail = [];
2303             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2304                 var item = onAvailStack[i];
2305                 if (item) {
2306                     var el = this.getEl(item.id);
2307
2308                     if (el) {
2309                         if (!item.checkReady ||
2310                             loadComplete ||
2311                             el.nextSibling ||
2312                             (document && document.body)) {
2313
2314                             var scope = el;
2315                             if (item.override) {
2316                                 if (item.override === true) {
2317                                     scope = item.obj;
2318                                 } else {
2319                                     scope = item.override;
2320                                 }
2321                             }
2322                             item.fn.call(scope, item.obj);
2323                             onAvailStack[i] = null;
2324                         }
2325                     } else {
2326                         notAvail.push(item);
2327                     }
2328                 }
2329             }
2330
2331             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2332
2333             if (tryAgain) {
2334
2335                 this.startInterval();
2336             } else {
2337                 clearInterval(this._interval);
2338                 this._interval = null;
2339             }
2340
2341             this.locked = false;
2342
2343             return true;
2344
2345         },
2346
2347
2348         purgeElement: function(el, recurse, eventName) {
2349             var elListeners = this.getListeners(el, eventName);
2350             if (elListeners) {
2351                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2352                     var l = elListeners[i];
2353                     this.removeListener(el, l.type, l.fn);
2354                 }
2355             }
2356
2357             if (recurse && el && el.childNodes) {
2358                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2359                     this.purgeElement(el.childNodes[i], recurse, eventName);
2360                 }
2361             }
2362         },
2363
2364
2365         getListeners: function(el, eventName) {
2366             var results = [], searchLists;
2367             if (!eventName) {
2368                 searchLists = [listeners, unloadListeners];
2369             } else if (eventName == "unload") {
2370                 searchLists = [unloadListeners];
2371             } else {
2372                 searchLists = [listeners];
2373             }
2374
2375             for (var j = 0; j < searchLists.length; ++j) {
2376                 var searchList = searchLists[j];
2377                 if (searchList && searchList.length > 0) {
2378                     for (var i = 0,len = searchList.length; i < len; ++i) {
2379                         var l = searchList[i];
2380                         if (l && l[this.EL] === el &&
2381                             (!eventName || eventName === l[this.TYPE])) {
2382                             results.push({
2383                                 type:   l[this.TYPE],
2384                                 fn:     l[this.FN],
2385                                 obj:    l[this.OBJ],
2386                                 adjust: l[this.ADJ_SCOPE],
2387                                 index:  i
2388                             });
2389                         }
2390                     }
2391                 }
2392             }
2393
2394             return (results.length) ? results : null;
2395         },
2396
2397
2398         _unload: function(e) {
2399
2400             var EU = Roo.lib.Event, i, j, l, len, index;
2401
2402             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2403                 l = unloadListeners[i];
2404                 if (l) {
2405                     var scope = window;
2406                     if (l[EU.ADJ_SCOPE]) {
2407                         if (l[EU.ADJ_SCOPE] === true) {
2408                             scope = l[EU.OBJ];
2409                         } else {
2410                             scope = l[EU.ADJ_SCOPE];
2411                         }
2412                     }
2413                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2414                     unloadListeners[i] = null;
2415                     l = null;
2416                     scope = null;
2417                 }
2418             }
2419
2420             unloadListeners = null;
2421
2422             if (listeners && listeners.length > 0) {
2423                 j = listeners.length;
2424                 while (j) {
2425                     index = j - 1;
2426                     l = listeners[index];
2427                     if (l) {
2428                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2429                                 l[EU.FN], index);
2430                     }
2431                     j = j - 1;
2432                 }
2433                 l = null;
2434
2435                 EU.clearCache();
2436             }
2437
2438             EU.doRemove(window, "unload", EU._unload);
2439
2440         },
2441
2442
2443         getScroll: function() {
2444             var dd = document.documentElement, db = document.body;
2445             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2446                 return [dd.scrollTop, dd.scrollLeft];
2447             } else if (db) {
2448                 return [db.scrollTop, db.scrollLeft];
2449             } else {
2450                 return [0, 0];
2451             }
2452         },
2453
2454
2455         doAdd: function () {
2456             if (window.addEventListener) {
2457                 return function(el, eventName, fn, capture) {
2458                     el.addEventListener(eventName, fn, (capture));
2459                 };
2460             } else if (window.attachEvent) {
2461                 return function(el, eventName, fn, capture) {
2462                     el.attachEvent("on" + eventName, fn);
2463                 };
2464             } else {
2465                 return function() {
2466                 };
2467             }
2468         }(),
2469
2470
2471         doRemove: function() {
2472             if (window.removeEventListener) {
2473                 return function (el, eventName, fn, capture) {
2474                     el.removeEventListener(eventName, fn, (capture));
2475                 };
2476             } else if (window.detachEvent) {
2477                 return function (el, eventName, fn) {
2478                     el.detachEvent("on" + eventName, fn);
2479                 };
2480             } else {
2481                 return function() {
2482                 };
2483             }
2484         }()
2485     };
2486     
2487 }();
2488 (function() {     
2489    
2490     var E = Roo.lib.Event;
2491     E.on = E.addListener;
2492     E.un = E.removeListener;
2493
2494     if (document && document.body) {
2495         E._load();
2496     } else {
2497         E.doAdd(window, "load", E._load);
2498     }
2499     E.doAdd(window, "unload", E._unload);
2500     E._tryPreloadAttach();
2501 })();
2502
2503 /*
2504  * Portions of this file are based on pieces of Yahoo User Interface Library
2505  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2506  * YUI licensed under the BSD License:
2507  * http://developer.yahoo.net/yui/license.txt
2508  * <script type="text/javascript">
2509  *
2510  */
2511
2512 (function() {
2513     /**
2514      * @class Roo.lib.Ajax
2515      *
2516      */
2517     Roo.lib.Ajax = {
2518         /**
2519          * @static 
2520          */
2521         request : function(method, uri, cb, data, options) {
2522             if(options){
2523                 var hs = options.headers;
2524                 if(hs){
2525                     for(var h in hs){
2526                         if(hs.hasOwnProperty(h)){
2527                             this.initHeader(h, hs[h], false);
2528                         }
2529                     }
2530                 }
2531                 if(options.xmlData){
2532                     this.initHeader('Content-Type', 'text/xml', false);
2533                     method = 'POST';
2534                     data = options.xmlData;
2535                 }
2536             }
2537
2538             return this.asyncRequest(method, uri, cb, data);
2539         },
2540
2541         serializeForm : function(form) {
2542             if(typeof form == 'string') {
2543                 form = (document.getElementById(form) || document.forms[form]);
2544             }
2545
2546             var el, name, val, disabled, data = '', hasSubmit = false;
2547             for (var i = 0; i < form.elements.length; i++) {
2548                 el = form.elements[i];
2549                 disabled = form.elements[i].disabled;
2550                 name = form.elements[i].name;
2551                 val = form.elements[i].value;
2552
2553                 if (!disabled && name){
2554                     switch (el.type)
2555                             {
2556                         case 'select-one':
2557                         case 'select-multiple':
2558                             for (var j = 0; j < el.options.length; j++) {
2559                                 if (el.options[j].selected) {
2560                                     if (Roo.isIE) {
2561                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2562                                     }
2563                                     else {
2564                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2565                                     }
2566                                 }
2567                             }
2568                             break;
2569                         case 'radio':
2570                         case 'checkbox':
2571                             if (el.checked) {
2572                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2573                             }
2574                             break;
2575                         case 'file':
2576
2577                         case undefined:
2578
2579                         case 'reset':
2580
2581                         case 'button':
2582
2583                             break;
2584                         case 'submit':
2585                             if(hasSubmit == false) {
2586                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2587                                 hasSubmit = true;
2588                             }
2589                             break;
2590                         default:
2591                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2592                             break;
2593                     }
2594                 }
2595             }
2596             data = data.substr(0, data.length - 1);
2597             return data;
2598         },
2599
2600         headers:{},
2601
2602         hasHeaders:false,
2603
2604         useDefaultHeader:true,
2605
2606         defaultPostHeader:'application/x-www-form-urlencoded',
2607
2608         useDefaultXhrHeader:true,
2609
2610         defaultXhrHeader:'XMLHttpRequest',
2611
2612         hasDefaultHeaders:true,
2613
2614         defaultHeaders:{},
2615
2616         poll:{},
2617
2618         timeout:{},
2619
2620         pollInterval:50,
2621
2622         transactionId:0,
2623
2624         setProgId:function(id)
2625         {
2626             this.activeX.unshift(id);
2627         },
2628
2629         setDefaultPostHeader:function(b)
2630         {
2631             this.useDefaultHeader = b;
2632         },
2633
2634         setDefaultXhrHeader:function(b)
2635         {
2636             this.useDefaultXhrHeader = b;
2637         },
2638
2639         setPollingInterval:function(i)
2640         {
2641             if (typeof i == 'number' && isFinite(i)) {
2642                 this.pollInterval = i;
2643             }
2644         },
2645
2646         createXhrObject:function(transactionId)
2647         {
2648             var obj,http;
2649             try
2650             {
2651
2652                 http = new XMLHttpRequest();
2653
2654                 obj = { conn:http, tId:transactionId };
2655             }
2656             catch(e)
2657             {
2658                 for (var i = 0; i < this.activeX.length; ++i) {
2659                     try
2660                     {
2661
2662                         http = new ActiveXObject(this.activeX[i]);
2663
2664                         obj = { conn:http, tId:transactionId };
2665                         break;
2666                     }
2667                     catch(e) {
2668                     }
2669                 }
2670             }
2671             finally
2672             {
2673                 return obj;
2674             }
2675         },
2676
2677         getConnectionObject:function()
2678         {
2679             var o;
2680             var tId = this.transactionId;
2681
2682             try
2683             {
2684                 o = this.createXhrObject(tId);
2685                 if (o) {
2686                     this.transactionId++;
2687                 }
2688             }
2689             catch(e) {
2690             }
2691             finally
2692             {
2693                 return o;
2694             }
2695         },
2696
2697         asyncRequest:function(method, uri, callback, postData)
2698         {
2699             var o = this.getConnectionObject();
2700
2701             if (!o) {
2702                 return null;
2703             }
2704             else {
2705                 o.conn.open(method, uri, true);
2706
2707                 if (this.useDefaultXhrHeader) {
2708                     if (!this.defaultHeaders['X-Requested-With']) {
2709                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2710                     }
2711                 }
2712
2713                 if(postData && this.useDefaultHeader){
2714                     this.initHeader('Content-Type', this.defaultPostHeader);
2715                 }
2716
2717                  if (this.hasDefaultHeaders || this.hasHeaders) {
2718                     this.setHeader(o);
2719                 }
2720
2721                 this.handleReadyState(o, callback);
2722                 o.conn.send(postData || null);
2723
2724                 return o;
2725             }
2726         },
2727
2728         handleReadyState:function(o, callback)
2729         {
2730             var oConn = this;
2731
2732             if (callback && callback.timeout) {
2733                 
2734                 this.timeout[o.tId] = window.setTimeout(function() {
2735                     oConn.abort(o, callback, true);
2736                 }, callback.timeout);
2737             }
2738
2739             this.poll[o.tId] = window.setInterval(
2740                     function() {
2741                         if (o.conn && o.conn.readyState == 4) {
2742                             window.clearInterval(oConn.poll[o.tId]);
2743                             delete oConn.poll[o.tId];
2744
2745                             if(callback && callback.timeout) {
2746                                 window.clearTimeout(oConn.timeout[o.tId]);
2747                                 delete oConn.timeout[o.tId];
2748                             }
2749
2750                             oConn.handleTransactionResponse(o, callback);
2751                         }
2752                     }
2753                     , this.pollInterval);
2754         },
2755
2756         handleTransactionResponse:function(o, callback, isAbort)
2757         {
2758
2759             if (!callback) {
2760                 this.releaseObject(o);
2761                 return;
2762             }
2763
2764             var httpStatus, responseObject;
2765
2766             try
2767             {
2768                 if (o.conn.status !== undefined && o.conn.status != 0) {
2769                     httpStatus = o.conn.status;
2770                 }
2771                 else {
2772                     httpStatus = 13030;
2773                 }
2774             }
2775             catch(e) {
2776
2777
2778                 httpStatus = 13030;
2779             }
2780
2781             if (httpStatus >= 200 && httpStatus < 300) {
2782                 responseObject = this.createResponseObject(o, callback.argument);
2783                 if (callback.success) {
2784                     if (!callback.scope) {
2785                         callback.success(responseObject);
2786                     }
2787                     else {
2788
2789
2790                         callback.success.apply(callback.scope, [responseObject]);
2791                     }
2792                 }
2793             }
2794             else {
2795                 switch (httpStatus) {
2796
2797                     case 12002:
2798                     case 12029:
2799                     case 12030:
2800                     case 12031:
2801                     case 12152:
2802                     case 13030:
2803                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2804                         if (callback.failure) {
2805                             if (!callback.scope) {
2806                                 callback.failure(responseObject);
2807                             }
2808                             else {
2809                                 callback.failure.apply(callback.scope, [responseObject]);
2810                             }
2811                         }
2812                         break;
2813                     default:
2814                         responseObject = this.createResponseObject(o, callback.argument);
2815                         if (callback.failure) {
2816                             if (!callback.scope) {
2817                                 callback.failure(responseObject);
2818                             }
2819                             else {
2820                                 callback.failure.apply(callback.scope, [responseObject]);
2821                             }
2822                         }
2823                 }
2824             }
2825
2826             this.releaseObject(o);
2827             responseObject = null;
2828         },
2829
2830         createResponseObject:function(o, callbackArg)
2831         {
2832             var obj = {};
2833             var headerObj = {};
2834
2835             try
2836             {
2837                 var headerStr = o.conn.getAllResponseHeaders();
2838                 var header = headerStr.split('\n');
2839                 for (var i = 0; i < header.length; i++) {
2840                     var delimitPos = header[i].indexOf(':');
2841                     if (delimitPos != -1) {
2842                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2843                     }
2844                 }
2845             }
2846             catch(e) {
2847             }
2848
2849             obj.tId = o.tId;
2850             obj.status = o.conn.status;
2851             obj.statusText = o.conn.statusText;
2852             obj.getResponseHeader = headerObj;
2853             obj.getAllResponseHeaders = headerStr;
2854             obj.responseText = o.conn.responseText;
2855             obj.responseXML = o.conn.responseXML;
2856
2857             if (typeof callbackArg !== undefined) {
2858                 obj.argument = callbackArg;
2859             }
2860
2861             return obj;
2862         },
2863
2864         createExceptionObject:function(tId, callbackArg, isAbort)
2865         {
2866             var COMM_CODE = 0;
2867             var COMM_ERROR = 'communication failure';
2868             var ABORT_CODE = -1;
2869             var ABORT_ERROR = 'transaction aborted';
2870
2871             var obj = {};
2872
2873             obj.tId = tId;
2874             if (isAbort) {
2875                 obj.status = ABORT_CODE;
2876                 obj.statusText = ABORT_ERROR;
2877             }
2878             else {
2879                 obj.status = COMM_CODE;
2880                 obj.statusText = COMM_ERROR;
2881             }
2882
2883             if (callbackArg) {
2884                 obj.argument = callbackArg;
2885             }
2886
2887             return obj;
2888         },
2889
2890         initHeader:function(label, value, isDefault)
2891         {
2892             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2893
2894             if (headerObj[label] === undefined) {
2895                 headerObj[label] = value;
2896             }
2897             else {
2898
2899
2900                 headerObj[label] = value + "," + headerObj[label];
2901             }
2902
2903             if (isDefault) {
2904                 this.hasDefaultHeaders = true;
2905             }
2906             else {
2907                 this.hasHeaders = true;
2908             }
2909         },
2910
2911
2912         setHeader:function(o)
2913         {
2914             if (this.hasDefaultHeaders) {
2915                 for (var prop in this.defaultHeaders) {
2916                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2917                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2918                     }
2919                 }
2920             }
2921
2922             if (this.hasHeaders) {
2923                 for (var prop in this.headers) {
2924                     if (this.headers.hasOwnProperty(prop)) {
2925                         o.conn.setRequestHeader(prop, this.headers[prop]);
2926                     }
2927                 }
2928                 this.headers = {};
2929                 this.hasHeaders = false;
2930             }
2931         },
2932
2933         resetDefaultHeaders:function() {
2934             delete this.defaultHeaders;
2935             this.defaultHeaders = {};
2936             this.hasDefaultHeaders = false;
2937         },
2938
2939         abort:function(o, callback, isTimeout)
2940         {
2941             if(this.isCallInProgress(o)) {
2942                 o.conn.abort();
2943                 window.clearInterval(this.poll[o.tId]);
2944                 delete this.poll[o.tId];
2945                 if (isTimeout) {
2946                     delete this.timeout[o.tId];
2947                 }
2948
2949                 this.handleTransactionResponse(o, callback, true);
2950
2951                 return true;
2952             }
2953             else {
2954                 return false;
2955             }
2956         },
2957
2958
2959         isCallInProgress:function(o)
2960         {
2961             if (o && o.conn) {
2962                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2963             }
2964             else {
2965
2966                 return false;
2967             }
2968         },
2969
2970
2971         releaseObject:function(o)
2972         {
2973
2974             o.conn = null;
2975
2976             o = null;
2977         },
2978
2979         activeX:[
2980         'MSXML2.XMLHTTP.3.0',
2981         'MSXML2.XMLHTTP',
2982         'Microsoft.XMLHTTP'
2983         ]
2984
2985
2986     };
2987 })();/*
2988  * Portions of this file are based on pieces of Yahoo User Interface Library
2989  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2990  * YUI licensed under the BSD License:
2991  * http://developer.yahoo.net/yui/license.txt
2992  * <script type="text/javascript">
2993  *
2994  */
2995
2996 Roo.lib.Region = function(t, r, b, l) {
2997     this.top = t;
2998     this[1] = t;
2999     this.right = r;
3000     this.bottom = b;
3001     this.left = l;
3002     this[0] = l;
3003 };
3004
3005
3006 Roo.lib.Region.prototype = {
3007     contains : function(region) {
3008         return ( region.left >= this.left &&
3009                  region.right <= this.right &&
3010                  region.top >= this.top &&
3011                  region.bottom <= this.bottom    );
3012
3013     },
3014
3015     getArea : function() {
3016         return ( (this.bottom - this.top) * (this.right - this.left) );
3017     },
3018
3019     intersect : function(region) {
3020         var t = Math.max(this.top, region.top);
3021         var r = Math.min(this.right, region.right);
3022         var b = Math.min(this.bottom, region.bottom);
3023         var l = Math.max(this.left, region.left);
3024
3025         if (b >= t && r >= l) {
3026             return new Roo.lib.Region(t, r, b, l);
3027         } else {
3028             return null;
3029         }
3030     },
3031     union : function(region) {
3032         var t = Math.min(this.top, region.top);
3033         var r = Math.max(this.right, region.right);
3034         var b = Math.max(this.bottom, region.bottom);
3035         var l = Math.min(this.left, region.left);
3036
3037         return new Roo.lib.Region(t, r, b, l);
3038     },
3039
3040     adjust : function(t, l, b, r) {
3041         this.top += t;
3042         this.left += l;
3043         this.right += r;
3044         this.bottom += b;
3045         return this;
3046     }
3047 };
3048
3049 Roo.lib.Region.getRegion = function(el) {
3050     var p = Roo.lib.Dom.getXY(el);
3051
3052     var t = p[1];
3053     var r = p[0] + el.offsetWidth;
3054     var b = p[1] + el.offsetHeight;
3055     var l = p[0];
3056
3057     return new Roo.lib.Region(t, r, b, l);
3058 };
3059 /*
3060  * Portions of this file are based on pieces of Yahoo User Interface Library
3061  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3062  * YUI licensed under the BSD License:
3063  * http://developer.yahoo.net/yui/license.txt
3064  * <script type="text/javascript">
3065  *
3066  */
3067 //@@dep Roo.lib.Region
3068
3069
3070 Roo.lib.Point = function(x, y) {
3071     if (x instanceof Array) {
3072         y = x[1];
3073         x = x[0];
3074     }
3075     this.x = this.right = this.left = this[0] = x;
3076     this.y = this.top = this.bottom = this[1] = y;
3077 };
3078
3079 Roo.lib.Point.prototype = new Roo.lib.Region();
3080 /*
3081  * Portions of this file are based on pieces of Yahoo User Interface Library
3082  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3083  * YUI licensed under the BSD License:
3084  * http://developer.yahoo.net/yui/license.txt
3085  * <script type="text/javascript">
3086  *
3087  */
3088  
3089 (function() {   
3090
3091     Roo.lib.Anim = {
3092         scroll : function(el, args, duration, easing, cb, scope) {
3093             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3094         },
3095
3096         motion : function(el, args, duration, easing, cb, scope) {
3097             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3098         },
3099
3100         color : function(el, args, duration, easing, cb, scope) {
3101             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3102         },
3103
3104         run : function(el, args, duration, easing, cb, scope, type) {
3105             type = type || Roo.lib.AnimBase;
3106             if (typeof easing == "string") {
3107                 easing = Roo.lib.Easing[easing];
3108             }
3109             var anim = new type(el, args, duration, easing);
3110             anim.animateX(function() {
3111                 Roo.callback(cb, scope);
3112             });
3113             return anim;
3114         }
3115     };
3116 })();/*
3117  * Portions of this file are based on pieces of Yahoo User Interface Library
3118  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3119  * YUI licensed under the BSD License:
3120  * http://developer.yahoo.net/yui/license.txt
3121  * <script type="text/javascript">
3122  *
3123  */
3124
3125 (function() {    
3126     var libFlyweight;
3127     
3128     function fly(el) {
3129         if (!libFlyweight) {
3130             libFlyweight = new Roo.Element.Flyweight();
3131         }
3132         libFlyweight.dom = el;
3133         return libFlyweight;
3134     }
3135
3136     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3137     
3138    
3139     
3140     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3141         if (el) {
3142             this.init(el, attributes, duration, method);
3143         }
3144     };
3145
3146     Roo.lib.AnimBase.fly = fly;
3147     
3148     
3149     
3150     Roo.lib.AnimBase.prototype = {
3151
3152         toString: function() {
3153             var el = this.getEl();
3154             var id = el.id || el.tagName;
3155             return ("Anim " + id);
3156         },
3157
3158         patterns: {
3159             noNegatives:        /width|height|opacity|padding/i,
3160             offsetAttribute:  /^((width|height)|(top|left))$/,
3161             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3162             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3163         },
3164
3165
3166         doMethod: function(attr, start, end) {
3167             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3168         },
3169
3170
3171         setAttribute: function(attr, val, unit) {
3172             if (this.patterns.noNegatives.test(attr)) {
3173                 val = (val > 0) ? val : 0;
3174             }
3175
3176             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3177         },
3178
3179
3180         getAttribute: function(attr) {
3181             var el = this.getEl();
3182             var val = fly(el).getStyle(attr);
3183
3184             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3185                 return parseFloat(val);
3186             }
3187
3188             var a = this.patterns.offsetAttribute.exec(attr) || [];
3189             var pos = !!( a[3] );
3190             var box = !!( a[2] );
3191
3192
3193             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3194                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3195             } else {
3196                 val = 0;
3197             }
3198
3199             return val;
3200         },
3201
3202
3203         getDefaultUnit: function(attr) {
3204             if (this.patterns.defaultUnit.test(attr)) {
3205                 return 'px';
3206             }
3207
3208             return '';
3209         },
3210
3211         animateX : function(callback, scope) {
3212             var f = function() {
3213                 this.onComplete.removeListener(f);
3214                 if (typeof callback == "function") {
3215                     callback.call(scope || this, this);
3216                 }
3217             };
3218             this.onComplete.addListener(f, this);
3219             this.animate();
3220         },
3221
3222
3223         setRuntimeAttribute: function(attr) {
3224             var start;
3225             var end;
3226             var attributes = this.attributes;
3227
3228             this.runtimeAttributes[attr] = {};
3229
3230             var isset = function(prop) {
3231                 return (typeof prop !== 'undefined');
3232             };
3233
3234             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3235                 return false;
3236             }
3237
3238             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3239
3240
3241             if (isset(attributes[attr]['to'])) {
3242                 end = attributes[attr]['to'];
3243             } else if (isset(attributes[attr]['by'])) {
3244                 if (start.constructor == Array) {
3245                     end = [];
3246                     for (var i = 0, len = start.length; i < len; ++i) {
3247                         end[i] = start[i] + attributes[attr]['by'][i];
3248                     }
3249                 } else {
3250                     end = start + attributes[attr]['by'];
3251                 }
3252             }
3253
3254             this.runtimeAttributes[attr].start = start;
3255             this.runtimeAttributes[attr].end = end;
3256
3257
3258             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3259         },
3260
3261
3262         init: function(el, attributes, duration, method) {
3263
3264             var isAnimated = false;
3265
3266
3267             var startTime = null;
3268
3269
3270             var actualFrames = 0;
3271
3272
3273             el = Roo.getDom(el);
3274
3275
3276             this.attributes = attributes || {};
3277
3278
3279             this.duration = duration || 1;
3280
3281
3282             this.method = method || Roo.lib.Easing.easeNone;
3283
3284
3285             this.useSeconds = true;
3286
3287
3288             this.currentFrame = 0;
3289
3290
3291             this.totalFrames = Roo.lib.AnimMgr.fps;
3292
3293
3294             this.getEl = function() {
3295                 return el;
3296             };
3297
3298
3299             this.isAnimated = function() {
3300                 return isAnimated;
3301             };
3302
3303
3304             this.getStartTime = function() {
3305                 return startTime;
3306             };
3307
3308             this.runtimeAttributes = {};
3309
3310
3311             this.animate = function() {
3312                 if (this.isAnimated()) {
3313                     return false;
3314                 }
3315
3316                 this.currentFrame = 0;
3317
3318                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3319
3320                 Roo.lib.AnimMgr.registerElement(this);
3321             };
3322
3323
3324             this.stop = function(finish) {
3325                 if (finish) {
3326                     this.currentFrame = this.totalFrames;
3327                     this._onTween.fire();
3328                 }
3329                 Roo.lib.AnimMgr.stop(this);
3330             };
3331
3332             var onStart = function() {
3333                 this.onStart.fire();
3334
3335                 this.runtimeAttributes = {};
3336                 for (var attr in this.attributes) {
3337                     this.setRuntimeAttribute(attr);
3338                 }
3339
3340                 isAnimated = true;
3341                 actualFrames = 0;
3342                 startTime = new Date();
3343             };
3344
3345
3346             var onTween = function() {
3347                 var data = {
3348                     duration: new Date() - this.getStartTime(),
3349                     currentFrame: this.currentFrame
3350                 };
3351
3352                 data.toString = function() {
3353                     return (
3354                             'duration: ' + data.duration +
3355                             ', currentFrame: ' + data.currentFrame
3356                             );
3357                 };
3358
3359                 this.onTween.fire(data);
3360
3361                 var runtimeAttributes = this.runtimeAttributes;
3362
3363                 for (var attr in runtimeAttributes) {
3364                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3365                 }
3366
3367                 actualFrames += 1;
3368             };
3369
3370             var onComplete = function() {
3371                 var actual_duration = (new Date() - startTime) / 1000 ;
3372
3373                 var data = {
3374                     duration: actual_duration,
3375                     frames: actualFrames,
3376                     fps: actualFrames / actual_duration
3377                 };
3378
3379                 data.toString = function() {
3380                     return (
3381                             'duration: ' + data.duration +
3382                             ', frames: ' + data.frames +
3383                             ', fps: ' + data.fps
3384                             );
3385                 };
3386
3387                 isAnimated = false;
3388                 actualFrames = 0;
3389                 this.onComplete.fire(data);
3390             };
3391
3392
3393             this._onStart = new Roo.util.Event(this);
3394             this.onStart = new Roo.util.Event(this);
3395             this.onTween = new Roo.util.Event(this);
3396             this._onTween = new Roo.util.Event(this);
3397             this.onComplete = new Roo.util.Event(this);
3398             this._onComplete = new Roo.util.Event(this);
3399             this._onStart.addListener(onStart);
3400             this._onTween.addListener(onTween);
3401             this._onComplete.addListener(onComplete);
3402         }
3403     };
3404 })();
3405 /*
3406  * Portions of this file are based on pieces of Yahoo User Interface Library
3407  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3408  * YUI licensed under the BSD License:
3409  * http://developer.yahoo.net/yui/license.txt
3410  * <script type="text/javascript">
3411  *
3412  */
3413
3414 Roo.lib.AnimMgr = new function() {
3415
3416     var thread = null;
3417
3418
3419     var queue = [];
3420
3421
3422     var tweenCount = 0;
3423
3424
3425     this.fps = 1000;
3426
3427
3428     this.delay = 1;
3429
3430
3431     this.registerElement = function(tween) {
3432         queue[queue.length] = tween;
3433         tweenCount += 1;
3434         tween._onStart.fire();
3435         this.start();
3436     };
3437
3438
3439     this.unRegister = function(tween, index) {
3440         tween._onComplete.fire();
3441         index = index || getIndex(tween);
3442         if (index != -1) {
3443             queue.splice(index, 1);
3444         }
3445
3446         tweenCount -= 1;
3447         if (tweenCount <= 0) {
3448             this.stop();
3449         }
3450     };
3451
3452
3453     this.start = function() {
3454         if (thread === null) {
3455             thread = setInterval(this.run, this.delay);
3456         }
3457     };
3458
3459
3460     this.stop = function(tween) {
3461         if (!tween) {
3462             clearInterval(thread);
3463
3464             for (var i = 0, len = queue.length; i < len; ++i) {
3465                 if (queue[0].isAnimated()) {
3466                     this.unRegister(queue[0], 0);
3467                 }
3468             }
3469
3470             queue = [];
3471             thread = null;
3472             tweenCount = 0;
3473         }
3474         else {
3475             this.unRegister(tween);
3476         }
3477     };
3478
3479
3480     this.run = function() {
3481         for (var i = 0, len = queue.length; i < len; ++i) {
3482             var tween = queue[i];
3483             if (!tween || !tween.isAnimated()) {
3484                 continue;
3485             }
3486
3487             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3488             {
3489                 tween.currentFrame += 1;
3490
3491                 if (tween.useSeconds) {
3492                     correctFrame(tween);
3493                 }
3494                 tween._onTween.fire();
3495             }
3496             else {
3497                 Roo.lib.AnimMgr.stop(tween, i);
3498             }
3499         }
3500     };
3501
3502     var getIndex = function(anim) {
3503         for (var i = 0, len = queue.length; i < len; ++i) {
3504             if (queue[i] == anim) {
3505                 return i;
3506             }
3507         }
3508         return -1;
3509     };
3510
3511
3512     var correctFrame = function(tween) {
3513         var frames = tween.totalFrames;
3514         var frame = tween.currentFrame;
3515         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3516         var elapsed = (new Date() - tween.getStartTime());
3517         var tweak = 0;
3518
3519         if (elapsed < tween.duration * 1000) {
3520             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3521         } else {
3522             tweak = frames - (frame + 1);
3523         }
3524         if (tweak > 0 && isFinite(tweak)) {
3525             if (tween.currentFrame + tweak >= frames) {
3526                 tweak = frames - (frame + 1);
3527             }
3528
3529             tween.currentFrame += tweak;
3530         }
3531     };
3532 };
3533
3534     /*
3535  * Portions of this file are based on pieces of Yahoo User Interface Library
3536  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3537  * YUI licensed under the BSD License:
3538  * http://developer.yahoo.net/yui/license.txt
3539  * <script type="text/javascript">
3540  *
3541  */
3542 Roo.lib.Bezier = new function() {
3543
3544         this.getPosition = function(points, t) {
3545             var n = points.length;
3546             var tmp = [];
3547
3548             for (var i = 0; i < n; ++i) {
3549                 tmp[i] = [points[i][0], points[i][1]];
3550             }
3551
3552             for (var j = 1; j < n; ++j) {
3553                 for (i = 0; i < n - j; ++i) {
3554                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3555                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3556                 }
3557             }
3558
3559             return [ tmp[0][0], tmp[0][1] ];
3560
3561         };
3562     };/*
3563  * Portions of this file are based on pieces of Yahoo User Interface Library
3564  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3565  * YUI licensed under the BSD License:
3566  * http://developer.yahoo.net/yui/license.txt
3567  * <script type="text/javascript">
3568  *
3569  */
3570 (function() {
3571
3572     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3573         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3574     };
3575
3576     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3577
3578     var fly = Roo.lib.AnimBase.fly;
3579     var Y = Roo.lib;
3580     var superclass = Y.ColorAnim.superclass;
3581     var proto = Y.ColorAnim.prototype;
3582
3583     proto.toString = function() {
3584         var el = this.getEl();
3585         var id = el.id || el.tagName;
3586         return ("ColorAnim " + id);
3587     };
3588
3589     proto.patterns.color = /color$/i;
3590     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3591     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3592     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3593     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3594
3595
3596     proto.parseColor = function(s) {
3597         if (s.length == 3) {
3598             return s;
3599         }
3600
3601         var c = this.patterns.hex.exec(s);
3602         if (c && c.length == 4) {
3603             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3604         }
3605
3606         c = this.patterns.rgb.exec(s);
3607         if (c && c.length == 4) {
3608             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3609         }
3610
3611         c = this.patterns.hex3.exec(s);
3612         if (c && c.length == 4) {
3613             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3614         }
3615
3616         return null;
3617     };
3618     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3619     proto.getAttribute = function(attr) {
3620         var el = this.getEl();
3621         if (this.patterns.color.test(attr)) {
3622             var val = fly(el).getStyle(attr);
3623
3624             if (this.patterns.transparent.test(val)) {
3625                 var parent = el.parentNode;
3626                 val = fly(parent).getStyle(attr);
3627
3628                 while (parent && this.patterns.transparent.test(val)) {
3629                     parent = parent.parentNode;
3630                     val = fly(parent).getStyle(attr);
3631                     if (parent.tagName.toUpperCase() == 'HTML') {
3632                         val = '#fff';
3633                     }
3634                 }
3635             }
3636         } else {
3637             val = superclass.getAttribute.call(this, attr);
3638         }
3639
3640         return val;
3641     };
3642     proto.getAttribute = function(attr) {
3643         var el = this.getEl();
3644         if (this.patterns.color.test(attr)) {
3645             var val = fly(el).getStyle(attr);
3646
3647             if (this.patterns.transparent.test(val)) {
3648                 var parent = el.parentNode;
3649                 val = fly(parent).getStyle(attr);
3650
3651                 while (parent && this.patterns.transparent.test(val)) {
3652                     parent = parent.parentNode;
3653                     val = fly(parent).getStyle(attr);
3654                     if (parent.tagName.toUpperCase() == 'HTML') {
3655                         val = '#fff';
3656                     }
3657                 }
3658             }
3659         } else {
3660             val = superclass.getAttribute.call(this, attr);
3661         }
3662
3663         return val;
3664     };
3665
3666     proto.doMethod = function(attr, start, end) {
3667         var val;
3668
3669         if (this.patterns.color.test(attr)) {
3670             val = [];
3671             for (var i = 0, len = start.length; i < len; ++i) {
3672                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3673             }
3674
3675             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3676         }
3677         else {
3678             val = superclass.doMethod.call(this, attr, start, end);
3679         }
3680
3681         return val;
3682     };
3683
3684     proto.setRuntimeAttribute = function(attr) {
3685         superclass.setRuntimeAttribute.call(this, attr);
3686
3687         if (this.patterns.color.test(attr)) {
3688             var attributes = this.attributes;
3689             var start = this.parseColor(this.runtimeAttributes[attr].start);
3690             var end = this.parseColor(this.runtimeAttributes[attr].end);
3691
3692             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3693                 end = this.parseColor(attributes[attr].by);
3694
3695                 for (var i = 0, len = start.length; i < len; ++i) {
3696                     end[i] = start[i] + end[i];
3697                 }
3698             }
3699
3700             this.runtimeAttributes[attr].start = start;
3701             this.runtimeAttributes[attr].end = end;
3702         }
3703     };
3704 })();
3705
3706 /*
3707  * Portions of this file are based on pieces of Yahoo User Interface Library
3708  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3709  * YUI licensed under the BSD License:
3710  * http://developer.yahoo.net/yui/license.txt
3711  * <script type="text/javascript">
3712  *
3713  */
3714 Roo.lib.Easing = {
3715
3716
3717     easeNone: function (t, b, c, d) {
3718         return c * t / d + b;
3719     },
3720
3721
3722     easeIn: function (t, b, c, d) {
3723         return c * (t /= d) * t + b;
3724     },
3725
3726
3727     easeOut: function (t, b, c, d) {
3728         return -c * (t /= d) * (t - 2) + b;
3729     },
3730
3731
3732     easeBoth: function (t, b, c, d) {
3733         if ((t /= d / 2) < 1) {
3734             return c / 2 * t * t + b;
3735         }
3736
3737         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3738     },
3739
3740
3741     easeInStrong: function (t, b, c, d) {
3742         return c * (t /= d) * t * t * t + b;
3743     },
3744
3745
3746     easeOutStrong: function (t, b, c, d) {
3747         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3748     },
3749
3750
3751     easeBothStrong: function (t, b, c, d) {
3752         if ((t /= d / 2) < 1) {
3753             return c / 2 * t * t * t * t + b;
3754         }
3755
3756         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3757     },
3758
3759
3760
3761     elasticIn: function (t, b, c, d, a, p) {
3762         if (t == 0) {
3763             return b;
3764         }
3765         if ((t /= d) == 1) {
3766             return b + c;
3767         }
3768         if (!p) {
3769             p = d * .3;
3770         }
3771
3772         if (!a || a < Math.abs(c)) {
3773             a = c;
3774             var s = p / 4;
3775         }
3776         else {
3777             var s = p / (2 * Math.PI) * Math.asin(c / a);
3778         }
3779
3780         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3781     },
3782
3783
3784     elasticOut: function (t, b, c, d, a, p) {
3785         if (t == 0) {
3786             return b;
3787         }
3788         if ((t /= d) == 1) {
3789             return b + c;
3790         }
3791         if (!p) {
3792             p = d * .3;
3793         }
3794
3795         if (!a || a < Math.abs(c)) {
3796             a = c;
3797             var s = p / 4;
3798         }
3799         else {
3800             var s = p / (2 * Math.PI) * Math.asin(c / a);
3801         }
3802
3803         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3804     },
3805
3806
3807     elasticBoth: function (t, b, c, d, a, p) {
3808         if (t == 0) {
3809             return b;
3810         }
3811
3812         if ((t /= d / 2) == 2) {
3813             return b + c;
3814         }
3815
3816         if (!p) {
3817             p = d * (.3 * 1.5);
3818         }
3819
3820         if (!a || a < Math.abs(c)) {
3821             a = c;
3822             var s = p / 4;
3823         }
3824         else {
3825             var s = p / (2 * Math.PI) * Math.asin(c / a);
3826         }
3827
3828         if (t < 1) {
3829             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3830                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3831         }
3832         return a * Math.pow(2, -10 * (t -= 1)) *
3833                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3834     },
3835
3836
3837
3838     backIn: function (t, b, c, d, s) {
3839         if (typeof s == 'undefined') {
3840             s = 1.70158;
3841         }
3842         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3843     },
3844
3845
3846     backOut: function (t, b, c, d, s) {
3847         if (typeof s == 'undefined') {
3848             s = 1.70158;
3849         }
3850         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3851     },
3852
3853
3854     backBoth: function (t, b, c, d, s) {
3855         if (typeof s == 'undefined') {
3856             s = 1.70158;
3857         }
3858
3859         if ((t /= d / 2 ) < 1) {
3860             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3861         }
3862         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3863     },
3864
3865
3866     bounceIn: function (t, b, c, d) {
3867         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3868     },
3869
3870
3871     bounceOut: function (t, b, c, d) {
3872         if ((t /= d) < (1 / 2.75)) {
3873             return c * (7.5625 * t * t) + b;
3874         } else if (t < (2 / 2.75)) {
3875             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3876         } else if (t < (2.5 / 2.75)) {
3877             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3878         }
3879         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3880     },
3881
3882
3883     bounceBoth: function (t, b, c, d) {
3884         if (t < d / 2) {
3885             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3886         }
3887         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3888     }
3889 };/*
3890  * Portions of this file are based on pieces of Yahoo User Interface Library
3891  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3892  * YUI licensed under the BSD License:
3893  * http://developer.yahoo.net/yui/license.txt
3894  * <script type="text/javascript">
3895  *
3896  */
3897     (function() {
3898         Roo.lib.Motion = function(el, attributes, duration, method) {
3899             if (el) {
3900                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3901             }
3902         };
3903
3904         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3905
3906
3907         var Y = Roo.lib;
3908         var superclass = Y.Motion.superclass;
3909         var proto = Y.Motion.prototype;
3910
3911         proto.toString = function() {
3912             var el = this.getEl();
3913             var id = el.id || el.tagName;
3914             return ("Motion " + id);
3915         };
3916
3917         proto.patterns.points = /^points$/i;
3918
3919         proto.setAttribute = function(attr, val, unit) {
3920             if (this.patterns.points.test(attr)) {
3921                 unit = unit || 'px';
3922                 superclass.setAttribute.call(this, 'left', val[0], unit);
3923                 superclass.setAttribute.call(this, 'top', val[1], unit);
3924             } else {
3925                 superclass.setAttribute.call(this, attr, val, unit);
3926             }
3927         };
3928
3929         proto.getAttribute = function(attr) {
3930             if (this.patterns.points.test(attr)) {
3931                 var val = [
3932                         superclass.getAttribute.call(this, 'left'),
3933                         superclass.getAttribute.call(this, 'top')
3934                         ];
3935             } else {
3936                 val = superclass.getAttribute.call(this, attr);
3937             }
3938
3939             return val;
3940         };
3941
3942         proto.doMethod = function(attr, start, end) {
3943             var val = null;
3944
3945             if (this.patterns.points.test(attr)) {
3946                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3947                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3948             } else {
3949                 val = superclass.doMethod.call(this, attr, start, end);
3950             }
3951             return val;
3952         };
3953
3954         proto.setRuntimeAttribute = function(attr) {
3955             if (this.patterns.points.test(attr)) {
3956                 var el = this.getEl();
3957                 var attributes = this.attributes;
3958                 var start;
3959                 var control = attributes['points']['control'] || [];
3960                 var end;
3961                 var i, len;
3962
3963                 if (control.length > 0 && !(control[0] instanceof Array)) {
3964                     control = [control];
3965                 } else {
3966                     var tmp = [];
3967                     for (i = 0,len = control.length; i < len; ++i) {
3968                         tmp[i] = control[i];
3969                     }
3970                     control = tmp;
3971                 }
3972
3973                 Roo.fly(el).position();
3974
3975                 if (isset(attributes['points']['from'])) {
3976                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3977                 }
3978                 else {
3979                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3980                 }
3981
3982                 start = this.getAttribute('points');
3983
3984
3985                 if (isset(attributes['points']['to'])) {
3986                     end = translateValues.call(this, attributes['points']['to'], start);
3987
3988                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3989                     for (i = 0,len = control.length; i < len; ++i) {
3990                         control[i] = translateValues.call(this, control[i], start);
3991                     }
3992
3993
3994                 } else if (isset(attributes['points']['by'])) {
3995                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3996
3997                     for (i = 0,len = control.length; i < len; ++i) {
3998                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3999                     }
4000                 }
4001
4002                 this.runtimeAttributes[attr] = [start];
4003
4004                 if (control.length > 0) {
4005                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4006                 }
4007
4008                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4009             }
4010             else {
4011                 superclass.setRuntimeAttribute.call(this, attr);
4012             }
4013         };
4014
4015         var translateValues = function(val, start) {
4016             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4017             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4018
4019             return val;
4020         };
4021
4022         var isset = function(prop) {
4023             return (typeof prop !== 'undefined');
4024         };
4025     })();
4026 /*
4027  * Portions of this file are based on pieces of Yahoo User Interface Library
4028  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4029  * YUI licensed under the BSD License:
4030  * http://developer.yahoo.net/yui/license.txt
4031  * <script type="text/javascript">
4032  *
4033  */
4034     (function() {
4035         Roo.lib.Scroll = function(el, attributes, duration, method) {
4036             if (el) {
4037                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4038             }
4039         };
4040
4041         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4042
4043
4044         var Y = Roo.lib;
4045         var superclass = Y.Scroll.superclass;
4046         var proto = Y.Scroll.prototype;
4047
4048         proto.toString = function() {
4049             var el = this.getEl();
4050             var id = el.id || el.tagName;
4051             return ("Scroll " + id);
4052         };
4053
4054         proto.doMethod = function(attr, start, end) {
4055             var val = null;
4056
4057             if (attr == 'scroll') {
4058                 val = [
4059                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4060                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4061                         ];
4062
4063             } else {
4064                 val = superclass.doMethod.call(this, attr, start, end);
4065             }
4066             return val;
4067         };
4068
4069         proto.getAttribute = function(attr) {
4070             var val = null;
4071             var el = this.getEl();
4072
4073             if (attr == 'scroll') {
4074                 val = [ el.scrollLeft, el.scrollTop ];
4075             } else {
4076                 val = superclass.getAttribute.call(this, attr);
4077             }
4078
4079             return val;
4080         };
4081
4082         proto.setAttribute = function(attr, val, unit) {
4083             var el = this.getEl();
4084
4085             if (attr == 'scroll') {
4086                 el.scrollLeft = val[0];
4087                 el.scrollTop = val[1];
4088             } else {
4089                 superclass.setAttribute.call(this, attr, val, unit);
4090             }
4091         };
4092     })();
4093 /*
4094  * Based on:
4095  * Ext JS Library 1.1.1
4096  * Copyright(c) 2006-2007, Ext JS, LLC.
4097  *
4098  * Originally Released Under LGPL - original licence link has changed is not relivant.
4099  *
4100  * Fork - LGPL
4101  * <script type="text/javascript">
4102  */
4103
4104
4105 // nasty IE9 hack - what a pile of crap that is..
4106
4107  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4108     Range.prototype.createContextualFragment = function (html) {
4109         var doc = window.document;
4110         var container = doc.createElement("div");
4111         container.innerHTML = html;
4112         var frag = doc.createDocumentFragment(), n;
4113         while ((n = container.firstChild)) {
4114             frag.appendChild(n);
4115         }
4116         return frag;
4117     };
4118 }
4119
4120 /**
4121  * @class Roo.DomHelper
4122  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4123  * 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>.
4124  * @singleton
4125  */
4126 Roo.DomHelper = function(){
4127     var tempTableEl = null;
4128     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4129     var tableRe = /^table|tbody|tr|td$/i;
4130     var xmlns = {};
4131     // build as innerHTML where available
4132     /** @ignore */
4133     var createHtml = function(o){
4134         if(typeof o == 'string'){
4135             return o;
4136         }
4137         var b = "";
4138         if(!o.tag){
4139             o.tag = "div";
4140         }
4141         b += "<" + o.tag;
4142         for(var attr in o){
4143             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4144             if(attr == "style"){
4145                 var s = o["style"];
4146                 if(typeof s == "function"){
4147                     s = s.call();
4148                 }
4149                 if(typeof s == "string"){
4150                     b += ' style="' + s + '"';
4151                 }else if(typeof s == "object"){
4152                     b += ' style="';
4153                     for(var key in s){
4154                         if(typeof s[key] != "function"){
4155                             b += key + ":" + s[key] + ";";
4156                         }
4157                     }
4158                     b += '"';
4159                 }
4160             }else{
4161                 if(attr == "cls"){
4162                     b += ' class="' + o["cls"] + '"';
4163                 }else if(attr == "htmlFor"){
4164                     b += ' for="' + o["htmlFor"] + '"';
4165                 }else{
4166                     b += " " + attr + '="' + o[attr] + '"';
4167                 }
4168             }
4169         }
4170         if(emptyTags.test(o.tag)){
4171             b += "/>";
4172         }else{
4173             b += ">";
4174             var cn = o.children || o.cn;
4175             if(cn){
4176                 //http://bugs.kde.org/show_bug.cgi?id=71506
4177                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4178                     for(var i = 0, len = cn.length; i < len; i++) {
4179                         b += createHtml(cn[i], b);
4180                     }
4181                 }else{
4182                     b += createHtml(cn, b);
4183                 }
4184             }
4185             if(o.html){
4186                 b += o.html;
4187             }
4188             b += "</" + o.tag + ">";
4189         }
4190         return b;
4191     };
4192
4193     // build as dom
4194     /** @ignore */
4195     var createDom = function(o, parentNode){
4196          
4197         // defininition craeted..
4198         var ns = false;
4199         if (o.ns && o.ns != 'html') {
4200                
4201             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4202                 xmlns[o.ns] = o.xmlns;
4203                 ns = o.xmlns;
4204             }
4205             if (typeof(xmlns[o.ns]) == 'undefined') {
4206                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4207             }
4208             ns = xmlns[o.ns];
4209         }
4210         
4211         
4212         if (typeof(o) == 'string') {
4213             return parentNode.appendChild(document.createTextNode(o));
4214         }
4215         o.tag = o.tag || div;
4216         if (o.ns && Roo.isIE) {
4217             ns = false;
4218             o.tag = o.ns + ':' + o.tag;
4219             
4220         }
4221         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4222         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4223         for(var attr in o){
4224             
4225             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4226                     attr == "style" || typeof o[attr] == "function") continue;
4227                     
4228             if(attr=="cls" && Roo.isIE){
4229                 el.className = o["cls"];
4230             }else{
4231                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4232                 else el[attr] = o[attr];
4233             }
4234         }
4235         Roo.DomHelper.applyStyles(el, o.style);
4236         var cn = o.children || o.cn;
4237         if(cn){
4238             //http://bugs.kde.org/show_bug.cgi?id=71506
4239              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4240                 for(var i = 0, len = cn.length; i < len; i++) {
4241                     createDom(cn[i], el);
4242                 }
4243             }else{
4244                 createDom(cn, el);
4245             }
4246         }
4247         if(o.html){
4248             el.innerHTML = o.html;
4249         }
4250         if(parentNode){
4251            parentNode.appendChild(el);
4252         }
4253         return el;
4254     };
4255
4256     var ieTable = function(depth, s, h, e){
4257         tempTableEl.innerHTML = [s, h, e].join('');
4258         var i = -1, el = tempTableEl;
4259         while(++i < depth){
4260             el = el.firstChild;
4261         }
4262         return el;
4263     };
4264
4265     // kill repeat to save bytes
4266     var ts = '<table>',
4267         te = '</table>',
4268         tbs = ts+'<tbody>',
4269         tbe = '</tbody>'+te,
4270         trs = tbs + '<tr>',
4271         tre = '</tr>'+tbe;
4272
4273     /**
4274      * @ignore
4275      * Nasty code for IE's broken table implementation
4276      */
4277     var insertIntoTable = function(tag, where, el, html){
4278         if(!tempTableEl){
4279             tempTableEl = document.createElement('div');
4280         }
4281         var node;
4282         var before = null;
4283         if(tag == 'td'){
4284             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4285                 return;
4286             }
4287             if(where == 'beforebegin'){
4288                 before = el;
4289                 el = el.parentNode;
4290             } else{
4291                 before = el.nextSibling;
4292                 el = el.parentNode;
4293             }
4294             node = ieTable(4, trs, html, tre);
4295         }
4296         else if(tag == 'tr'){
4297             if(where == 'beforebegin'){
4298                 before = el;
4299                 el = el.parentNode;
4300                 node = ieTable(3, tbs, html, tbe);
4301             } else if(where == 'afterend'){
4302                 before = el.nextSibling;
4303                 el = el.parentNode;
4304                 node = ieTable(3, tbs, html, tbe);
4305             } else{ // INTO a TR
4306                 if(where == 'afterbegin'){
4307                     before = el.firstChild;
4308                 }
4309                 node = ieTable(4, trs, html, tre);
4310             }
4311         } else if(tag == 'tbody'){
4312             if(where == 'beforebegin'){
4313                 before = el;
4314                 el = el.parentNode;
4315                 node = ieTable(2, ts, html, te);
4316             } else if(where == 'afterend'){
4317                 before = el.nextSibling;
4318                 el = el.parentNode;
4319                 node = ieTable(2, ts, html, te);
4320             } else{
4321                 if(where == 'afterbegin'){
4322                     before = el.firstChild;
4323                 }
4324                 node = ieTable(3, tbs, html, tbe);
4325             }
4326         } else{ // TABLE
4327             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4328                 return;
4329             }
4330             if(where == 'afterbegin'){
4331                 before = el.firstChild;
4332             }
4333             node = ieTable(2, ts, html, te);
4334         }
4335         el.insertBefore(node, before);
4336         return node;
4337     };
4338
4339     return {
4340     /** True to force the use of DOM instead of html fragments @type Boolean */
4341     useDom : false,
4342
4343     /**
4344      * Returns the markup for the passed Element(s) config
4345      * @param {Object} o The Dom object spec (and children)
4346      * @return {String}
4347      */
4348     markup : function(o){
4349         return createHtml(o);
4350     },
4351
4352     /**
4353      * Applies a style specification to an element
4354      * @param {String/HTMLElement} el The element to apply styles to
4355      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4356      * a function which returns such a specification.
4357      */
4358     applyStyles : function(el, styles){
4359         if(styles){
4360            el = Roo.fly(el);
4361            if(typeof styles == "string"){
4362                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4363                var matches;
4364                while ((matches = re.exec(styles)) != null){
4365                    el.setStyle(matches[1], matches[2]);
4366                }
4367            }else if (typeof styles == "object"){
4368                for (var style in styles){
4369                   el.setStyle(style, styles[style]);
4370                }
4371            }else if (typeof styles == "function"){
4372                 Roo.DomHelper.applyStyles(el, styles.call());
4373            }
4374         }
4375     },
4376
4377     /**
4378      * Inserts an HTML fragment into the Dom
4379      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4380      * @param {HTMLElement} el The context element
4381      * @param {String} html The HTML fragmenet
4382      * @return {HTMLElement} The new node
4383      */
4384     insertHtml : function(where, el, html){
4385         where = where.toLowerCase();
4386         Roo.log(where);
4387         Roo.log(el);
4388         Roo.log(html);
4389         if(el.insertAdjacentHTML){
4390             if(tableRe.test(el.tagName)){
4391                 var rs;
4392                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4393                     return rs;
4394                 }
4395             }
4396             switch(where){
4397                 case "beforebegin":
4398                     el.insertAdjacentHTML('BeforeBegin', html);
4399                     return el.previousSibling;
4400                 case "afterbegin":
4401                     el.insertAdjacentHTML('AfterBegin', html);
4402                     return el.firstChild;
4403                 case "beforeend":
4404                     el.insertAdjacentHTML('BeforeEnd', html);
4405                     return el.lastChild;
4406                 case "afterend":
4407                     el.insertAdjacentHTML('AfterEnd', html);
4408                     return el.nextSibling;
4409             }
4410             throw 'Illegal insertion point -> "' + where + '"';
4411         }
4412         var range = el.ownerDocument.createRange();
4413         var frag;
4414         switch(where){
4415              case "beforebegin":
4416                 range.setStartBefore(el);
4417                 frag = range.createContextualFragment(html);
4418                 el.parentNode.insertBefore(frag, el);
4419                 return el.previousSibling;
4420              case "afterbegin":
4421                 if(el.firstChild){
4422                     range.setStartBefore(el.firstChild);
4423                     frag = range.createContextualFragment(html);
4424                     el.insertBefore(frag, el.firstChild);
4425                     return el.firstChild;
4426                 }else{
4427                     el.innerHTML = html;
4428                     return el.firstChild;
4429                 }
4430             case "beforeend":
4431                 if(el.lastChild){
4432                     range.setStartAfter(el.lastChild);
4433                     frag = range.createContextualFragment(html);
4434                     el.appendChild(frag);
4435                     return el.lastChild;
4436                 }else{
4437                     el.innerHTML = html;
4438                     return el.lastChild;
4439                 }
4440             case "afterend":
4441                 range.setStartAfter(el);
4442                 frag = range.createContextualFragment(html);
4443                 el.parentNode.insertBefore(frag, el.nextSibling);
4444                 return el.nextSibling;
4445             }
4446             throw 'Illegal insertion point -> "' + where + '"';
4447     },
4448
4449     /**
4450      * Creates new Dom element(s) and inserts them before el
4451      * @param {String/HTMLElement/Element} el The context element
4452      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4453      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4454      * @return {HTMLElement/Roo.Element} The new node
4455      */
4456     insertBefore : function(el, o, returnElement){
4457         return this.doInsert(el, o, returnElement, "beforeBegin");
4458     },
4459
4460     /**
4461      * Creates new Dom element(s) and inserts them after el
4462      * @param {String/HTMLElement/Element} el The context element
4463      * @param {Object} o The Dom object spec (and children)
4464      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4465      * @return {HTMLElement/Roo.Element} The new node
4466      */
4467     insertAfter : function(el, o, returnElement){
4468         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4469     },
4470
4471     /**
4472      * Creates new Dom element(s) and inserts them as the first child of el
4473      * @param {String/HTMLElement/Element} el The context element
4474      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4475      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4476      * @return {HTMLElement/Roo.Element} The new node
4477      */
4478     insertFirst : function(el, o, returnElement){
4479         return this.doInsert(el, o, returnElement, "afterBegin");
4480     },
4481
4482     // private
4483     doInsert : function(el, o, returnElement, pos, sibling){
4484         el = Roo.getDom(el);
4485         var newNode;
4486         if(this.useDom || o.ns){
4487             newNode = createDom(o, null);
4488             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4489         }else{
4490             var html = createHtml(o);
4491             newNode = this.insertHtml(pos, el, html);
4492         }
4493         return returnElement ? Roo.get(newNode, true) : newNode;
4494     },
4495
4496     /**
4497      * Creates new Dom element(s) and appends them to el
4498      * @param {String/HTMLElement/Element} el The context element
4499      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4500      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4501      * @return {HTMLElement/Roo.Element} The new node
4502      */
4503     append : function(el, o, returnElement){
4504         el = Roo.getDom(el);
4505         var newNode;
4506         if(this.useDom || o.ns){
4507             newNode = createDom(o, null);
4508             el.appendChild(newNode);
4509         }else{
4510             var html = createHtml(o);
4511             newNode = this.insertHtml("beforeEnd", el, html);
4512         }
4513         return returnElement ? Roo.get(newNode, true) : newNode;
4514     },
4515
4516     /**
4517      * Creates new Dom element(s) and overwrites the contents of el with them
4518      * @param {String/HTMLElement/Element} el The context element
4519      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4520      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4521      * @return {HTMLElement/Roo.Element} The new node
4522      */
4523     overwrite : function(el, o, returnElement){
4524         el = Roo.getDom(el);
4525         if (o.ns) {
4526           
4527             while (el.childNodes.length) {
4528                 el.removeChild(el.firstChild);
4529             }
4530             createDom(o, el);
4531         } else {
4532             el.innerHTML = createHtml(o);   
4533         }
4534         
4535         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4536     },
4537
4538     /**
4539      * Creates a new Roo.DomHelper.Template from the Dom object spec
4540      * @param {Object} o The Dom object spec (and children)
4541      * @return {Roo.DomHelper.Template} The new template
4542      */
4543     createTemplate : function(o){
4544         var html = createHtml(o);
4545         return new Roo.Template(html);
4546     }
4547     };
4548 }();
4549 /*
4550  * Based on:
4551  * Ext JS Library 1.1.1
4552  * Copyright(c) 2006-2007, Ext JS, LLC.
4553  *
4554  * Originally Released Under LGPL - original licence link has changed is not relivant.
4555  *
4556  * Fork - LGPL
4557  * <script type="text/javascript">
4558  */
4559  
4560 /**
4561 * @class Roo.Template
4562 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4563 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4564 * Usage:
4565 <pre><code>
4566 var t = new Roo.Template({
4567     html :  '&lt;div name="{id}"&gt;' + 
4568         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4569         '&lt;/div&gt;',
4570     myformat: function (value, allValues) {
4571         return 'XX' + value;
4572     }
4573 });
4574 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4575 </code></pre>
4576 * For more information see this blog post with examples:
4577 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4578      - Create Elements using DOM, HTML fragments and Templates</a>. 
4579 * @constructor
4580 * @param {Object} cfg - Configuration object.
4581 */
4582 Roo.Template = function(cfg){
4583     // BC!
4584     if(cfg instanceof Array){
4585         cfg = cfg.join("");
4586     }else if(arguments.length > 1){
4587         cfg = Array.prototype.join.call(arguments, "");
4588     }
4589     
4590     
4591     if (typeof(cfg) == 'object') {
4592         Roo.apply(this,cfg)
4593     } else {
4594         // bc
4595         this.html = cfg;
4596     }
4597     if (this.url) {
4598         this.load();
4599     }
4600     
4601 };
4602 Roo.Template.prototype = {
4603     
4604     /**
4605      * @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..
4606      *                    it should be fixed so that template is observable...
4607      */
4608     url : false,
4609     /**
4610      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4611      */
4612     html : '',
4613     /**
4614      * Returns an HTML fragment of this template with the specified values applied.
4615      * @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'})
4616      * @return {String} The HTML fragment
4617      */
4618     applyTemplate : function(values){
4619         try {
4620            
4621             if(this.compiled){
4622                 return this.compiled(values);
4623             }
4624             var useF = this.disableFormats !== true;
4625             var fm = Roo.util.Format, tpl = this;
4626             var fn = function(m, name, format, args){
4627                 if(format && useF){
4628                     if(format.substr(0, 5) == "this."){
4629                         return tpl.call(format.substr(5), values[name], values);
4630                     }else{
4631                         if(args){
4632                             // quoted values are required for strings in compiled templates, 
4633                             // but for non compiled we need to strip them
4634                             // quoted reversed for jsmin
4635                             var re = /^\s*['"](.*)["']\s*$/;
4636                             args = args.split(',');
4637                             for(var i = 0, len = args.length; i < len; i++){
4638                                 args[i] = args[i].replace(re, "$1");
4639                             }
4640                             args = [values[name]].concat(args);
4641                         }else{
4642                             args = [values[name]];
4643                         }
4644                         return fm[format].apply(fm, args);
4645                     }
4646                 }else{
4647                     return values[name] !== undefined ? values[name] : "";
4648                 }
4649             };
4650             return this.html.replace(this.re, fn);
4651         } catch (e) {
4652             Roo.log(e);
4653             throw e;
4654         }
4655          
4656     },
4657     
4658     loading : false,
4659       
4660     load : function ()
4661     {
4662          
4663         if (this.loading) {
4664             return;
4665         }
4666         var _t = this;
4667         
4668         this.loading = true;
4669         this.compiled = false;
4670         
4671         var cx = new Roo.data.Connection();
4672         cx.request({
4673             url : this.url,
4674             method : 'GET',
4675             success : function (response) {
4676                 _t.loading = false;
4677                 _t.html = response.responseText;
4678                 _t.url = false;
4679                 _t.compile();
4680              },
4681             failure : function(response) {
4682                 Roo.log("Template failed to load from " + _t.url);
4683                 _t.loading = false;
4684             }
4685         });
4686     },
4687
4688     /**
4689      * Sets the HTML used as the template and optionally compiles it.
4690      * @param {String} html
4691      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4692      * @return {Roo.Template} this
4693      */
4694     set : function(html, compile){
4695         this.html = html;
4696         this.compiled = null;
4697         if(compile){
4698             this.compile();
4699         }
4700         return this;
4701     },
4702     
4703     /**
4704      * True to disable format functions (defaults to false)
4705      * @type Boolean
4706      */
4707     disableFormats : false,
4708     
4709     /**
4710     * The regular expression used to match template variables 
4711     * @type RegExp
4712     * @property 
4713     */
4714     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4715     
4716     /**
4717      * Compiles the template into an internal function, eliminating the RegEx overhead.
4718      * @return {Roo.Template} this
4719      */
4720     compile : function(){
4721         var fm = Roo.util.Format;
4722         var useF = this.disableFormats !== true;
4723         var sep = Roo.isGecko ? "+" : ",";
4724         var fn = function(m, name, format, args){
4725             if(format && useF){
4726                 args = args ? ',' + args : "";
4727                 if(format.substr(0, 5) != "this."){
4728                     format = "fm." + format + '(';
4729                 }else{
4730                     format = 'this.call("'+ format.substr(5) + '", ';
4731                     args = ", values";
4732                 }
4733             }else{
4734                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4735             }
4736             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4737         };
4738         var body;
4739         // branched to use + in gecko and [].join() in others
4740         if(Roo.isGecko){
4741             body = "this.compiled = function(values){ return '" +
4742                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4743                     "';};";
4744         }else{
4745             body = ["this.compiled = function(values){ return ['"];
4746             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4747             body.push("'].join('');};");
4748             body = body.join('');
4749         }
4750         /**
4751          * eval:var:values
4752          * eval:var:fm
4753          */
4754         eval(body);
4755         return this;
4756     },
4757     
4758     // private function used to call members
4759     call : function(fnName, value, allValues){
4760         return this[fnName](value, allValues);
4761     },
4762     
4763     /**
4764      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4765      * @param {String/HTMLElement/Roo.Element} el The context element
4766      * @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'})
4767      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4768      * @return {HTMLElement/Roo.Element} The new node or Element
4769      */
4770     insertFirst: function(el, values, returnElement){
4771         return this.doInsert('afterBegin', el, values, returnElement);
4772     },
4773
4774     /**
4775      * Applies the supplied values to the template and inserts the new node(s) before el.
4776      * @param {String/HTMLElement/Roo.Element} el The context element
4777      * @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'})
4778      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4779      * @return {HTMLElement/Roo.Element} The new node or Element
4780      */
4781     insertBefore: function(el, values, returnElement){
4782         return this.doInsert('beforeBegin', el, values, returnElement);
4783     },
4784
4785     /**
4786      * Applies the supplied values to the template and inserts the new node(s) after el.
4787      * @param {String/HTMLElement/Roo.Element} el The context element
4788      * @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'})
4789      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4790      * @return {HTMLElement/Roo.Element} The new node or Element
4791      */
4792     insertAfter : function(el, values, returnElement){
4793         return this.doInsert('afterEnd', el, values, returnElement);
4794     },
4795     
4796     /**
4797      * Applies the supplied values to the template and appends the new node(s) to el.
4798      * @param {String/HTMLElement/Roo.Element} el The context element
4799      * @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'})
4800      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4801      * @return {HTMLElement/Roo.Element} The new node or Element
4802      */
4803     append : function(el, values, returnElement){
4804         return this.doInsert('beforeEnd', el, values, returnElement);
4805     },
4806
4807     doInsert : function(where, el, values, returnEl){
4808         el = Roo.getDom(el);
4809         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4810         return returnEl ? Roo.get(newNode, true) : newNode;
4811     },
4812
4813     /**
4814      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4815      * @param {String/HTMLElement/Roo.Element} el The context element
4816      * @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'})
4817      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4818      * @return {HTMLElement/Roo.Element} The new node or Element
4819      */
4820     overwrite : function(el, values, returnElement){
4821         el = Roo.getDom(el);
4822         el.innerHTML = this.applyTemplate(values);
4823         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4824     }
4825 };
4826 /**
4827  * Alias for {@link #applyTemplate}
4828  * @method
4829  */
4830 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4831
4832 // backwards compat
4833 Roo.DomHelper.Template = Roo.Template;
4834
4835 /**
4836  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4837  * @param {String/HTMLElement} el A DOM element or its id
4838  * @returns {Roo.Template} The created template
4839  * @static
4840  */
4841 Roo.Template.from = function(el){
4842     el = Roo.getDom(el);
4843     return new Roo.Template(el.value || el.innerHTML);
4844 };/*
4845  * Based on:
4846  * Ext JS Library 1.1.1
4847  * Copyright(c) 2006-2007, Ext JS, LLC.
4848  *
4849  * Originally Released Under LGPL - original licence link has changed is not relivant.
4850  *
4851  * Fork - LGPL
4852  * <script type="text/javascript">
4853  */
4854  
4855
4856 /*
4857  * This is code is also distributed under MIT license for use
4858  * with jQuery and prototype JavaScript libraries.
4859  */
4860 /**
4861  * @class Roo.DomQuery
4862 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).
4863 <p>
4864 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>
4865
4866 <p>
4867 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.
4868 </p>
4869 <h4>Element Selectors:</h4>
4870 <ul class="list">
4871     <li> <b>*</b> any element</li>
4872     <li> <b>E</b> an element with the tag E</li>
4873     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4874     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4875     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4876     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4877 </ul>
4878 <h4>Attribute Selectors:</h4>
4879 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4880 <ul class="list">
4881     <li> <b>E[foo]</b> has an attribute "foo"</li>
4882     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4883     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4884     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4885     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4886     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4887     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4888 </ul>
4889 <h4>Pseudo Classes:</h4>
4890 <ul class="list">
4891     <li> <b>E:first-child</b> E is the first child of its parent</li>
4892     <li> <b>E:last-child</b> E is the last child of its parent</li>
4893     <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>
4894     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4895     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4896     <li> <b>E:only-child</b> E is the only child of its parent</li>
4897     <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>
4898     <li> <b>E:first</b> the first E in the resultset</li>
4899     <li> <b>E:last</b> the last E in the resultset</li>
4900     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4901     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4902     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4903     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4904     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4905     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4906     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4907     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4908     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4909 </ul>
4910 <h4>CSS Value Selectors:</h4>
4911 <ul class="list">
4912     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4913     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4914     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4915     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4916     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4917     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4918 </ul>
4919  * @singleton
4920  */
4921 Roo.DomQuery = function(){
4922     var cache = {}, simpleCache = {}, valueCache = {};
4923     var nonSpace = /\S/;
4924     var trimRe = /^\s+|\s+$/g;
4925     var tplRe = /\{(\d+)\}/g;
4926     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4927     var tagTokenRe = /^(#)?([\w-\*]+)/;
4928     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4929
4930     function child(p, index){
4931         var i = 0;
4932         var n = p.firstChild;
4933         while(n){
4934             if(n.nodeType == 1){
4935                if(++i == index){
4936                    return n;
4937                }
4938             }
4939             n = n.nextSibling;
4940         }
4941         return null;
4942     };
4943
4944     function next(n){
4945         while((n = n.nextSibling) && n.nodeType != 1);
4946         return n;
4947     };
4948
4949     function prev(n){
4950         while((n = n.previousSibling) && n.nodeType != 1);
4951         return n;
4952     };
4953
4954     function children(d){
4955         var n = d.firstChild, ni = -1;
4956             while(n){
4957                 var nx = n.nextSibling;
4958                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4959                     d.removeChild(n);
4960                 }else{
4961                     n.nodeIndex = ++ni;
4962                 }
4963                 n = nx;
4964             }
4965             return this;
4966         };
4967
4968     function byClassName(c, a, v){
4969         if(!v){
4970             return c;
4971         }
4972         var r = [], ri = -1, cn;
4973         for(var i = 0, ci; ci = c[i]; i++){
4974             if((' '+ci.className+' ').indexOf(v) != -1){
4975                 r[++ri] = ci;
4976             }
4977         }
4978         return r;
4979     };
4980
4981     function attrValue(n, attr){
4982         if(!n.tagName && typeof n.length != "undefined"){
4983             n = n[0];
4984         }
4985         if(!n){
4986             return null;
4987         }
4988         if(attr == "for"){
4989             return n.htmlFor;
4990         }
4991         if(attr == "class" || attr == "className"){
4992             return n.className;
4993         }
4994         return n.getAttribute(attr) || n[attr];
4995
4996     };
4997
4998     function getNodes(ns, mode, tagName){
4999         var result = [], ri = -1, cs;
5000         if(!ns){
5001             return result;
5002         }
5003         tagName = tagName || "*";
5004         if(typeof ns.getElementsByTagName != "undefined"){
5005             ns = [ns];
5006         }
5007         if(!mode){
5008             for(var i = 0, ni; ni = ns[i]; i++){
5009                 cs = ni.getElementsByTagName(tagName);
5010                 for(var j = 0, ci; ci = cs[j]; j++){
5011                     result[++ri] = ci;
5012                 }
5013             }
5014         }else if(mode == "/" || mode == ">"){
5015             var utag = tagName.toUpperCase();
5016             for(var i = 0, ni, cn; ni = ns[i]; i++){
5017                 cn = ni.children || ni.childNodes;
5018                 for(var j = 0, cj; cj = cn[j]; j++){
5019                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5020                         result[++ri] = cj;
5021                     }
5022                 }
5023             }
5024         }else if(mode == "+"){
5025             var utag = tagName.toUpperCase();
5026             for(var i = 0, n; n = ns[i]; i++){
5027                 while((n = n.nextSibling) && n.nodeType != 1);
5028                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5029                     result[++ri] = n;
5030                 }
5031             }
5032         }else if(mode == "~"){
5033             for(var i = 0, n; n = ns[i]; i++){
5034                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5035                 if(n){
5036                     result[++ri] = n;
5037                 }
5038             }
5039         }
5040         return result;
5041     };
5042
5043     function concat(a, b){
5044         if(b.slice){
5045             return a.concat(b);
5046         }
5047         for(var i = 0, l = b.length; i < l; i++){
5048             a[a.length] = b[i];
5049         }
5050         return a;
5051     }
5052
5053     function byTag(cs, tagName){
5054         if(cs.tagName || cs == document){
5055             cs = [cs];
5056         }
5057         if(!tagName){
5058             return cs;
5059         }
5060         var r = [], ri = -1;
5061         tagName = tagName.toLowerCase();
5062         for(var i = 0, ci; ci = cs[i]; i++){
5063             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5064                 r[++ri] = ci;
5065             }
5066         }
5067         return r;
5068     };
5069
5070     function byId(cs, attr, id){
5071         if(cs.tagName || cs == document){
5072             cs = [cs];
5073         }
5074         if(!id){
5075             return cs;
5076         }
5077         var r = [], ri = -1;
5078         for(var i = 0,ci; ci = cs[i]; i++){
5079             if(ci && ci.id == id){
5080                 r[++ri] = ci;
5081                 return r;
5082             }
5083         }
5084         return r;
5085     };
5086
5087     function byAttribute(cs, attr, value, op, custom){
5088         var r = [], ri = -1, st = custom=="{";
5089         var f = Roo.DomQuery.operators[op];
5090         for(var i = 0, ci; ci = cs[i]; i++){
5091             var a;
5092             if(st){
5093                 a = Roo.DomQuery.getStyle(ci, attr);
5094             }
5095             else if(attr == "class" || attr == "className"){
5096                 a = ci.className;
5097             }else if(attr == "for"){
5098                 a = ci.htmlFor;
5099             }else if(attr == "href"){
5100                 a = ci.getAttribute("href", 2);
5101             }else{
5102                 a = ci.getAttribute(attr);
5103             }
5104             if((f && f(a, value)) || (!f && a)){
5105                 r[++ri] = ci;
5106             }
5107         }
5108         return r;
5109     };
5110
5111     function byPseudo(cs, name, value){
5112         return Roo.DomQuery.pseudos[name](cs, value);
5113     };
5114
5115     // This is for IE MSXML which does not support expandos.
5116     // IE runs the same speed using setAttribute, however FF slows way down
5117     // and Safari completely fails so they need to continue to use expandos.
5118     var isIE = window.ActiveXObject ? true : false;
5119
5120     // this eval is stop the compressor from
5121     // renaming the variable to something shorter
5122     
5123     /** eval:var:batch */
5124     var batch = 30803; 
5125
5126     var key = 30803;
5127
5128     function nodupIEXml(cs){
5129         var d = ++key;
5130         cs[0].setAttribute("_nodup", d);
5131         var r = [cs[0]];
5132         for(var i = 1, len = cs.length; i < len; i++){
5133             var c = cs[i];
5134             if(!c.getAttribute("_nodup") != d){
5135                 c.setAttribute("_nodup", d);
5136                 r[r.length] = c;
5137             }
5138         }
5139         for(var i = 0, len = cs.length; i < len; i++){
5140             cs[i].removeAttribute("_nodup");
5141         }
5142         return r;
5143     }
5144
5145     function nodup(cs){
5146         if(!cs){
5147             return [];
5148         }
5149         var len = cs.length, c, i, r = cs, cj, ri = -1;
5150         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5151             return cs;
5152         }
5153         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5154             return nodupIEXml(cs);
5155         }
5156         var d = ++key;
5157         cs[0]._nodup = d;
5158         for(i = 1; c = cs[i]; i++){
5159             if(c._nodup != d){
5160                 c._nodup = d;
5161             }else{
5162                 r = [];
5163                 for(var j = 0; j < i; j++){
5164                     r[++ri] = cs[j];
5165                 }
5166                 for(j = i+1; cj = cs[j]; j++){
5167                     if(cj._nodup != d){
5168                         cj._nodup = d;
5169                         r[++ri] = cj;
5170                     }
5171                 }
5172                 return r;
5173             }
5174         }
5175         return r;
5176     }
5177
5178     function quickDiffIEXml(c1, c2){
5179         var d = ++key;
5180         for(var i = 0, len = c1.length; i < len; i++){
5181             c1[i].setAttribute("_qdiff", d);
5182         }
5183         var r = [];
5184         for(var i = 0, len = c2.length; i < len; i++){
5185             if(c2[i].getAttribute("_qdiff") != d){
5186                 r[r.length] = c2[i];
5187             }
5188         }
5189         for(var i = 0, len = c1.length; i < len; i++){
5190            c1[i].removeAttribute("_qdiff");
5191         }
5192         return r;
5193     }
5194
5195     function quickDiff(c1, c2){
5196         var len1 = c1.length;
5197         if(!len1){
5198             return c2;
5199         }
5200         if(isIE && c1[0].selectSingleNode){
5201             return quickDiffIEXml(c1, c2);
5202         }
5203         var d = ++key;
5204         for(var i = 0; i < len1; i++){
5205             c1[i]._qdiff = d;
5206         }
5207         var r = [];
5208         for(var i = 0, len = c2.length; i < len; i++){
5209             if(c2[i]._qdiff != d){
5210                 r[r.length] = c2[i];
5211             }
5212         }
5213         return r;
5214     }
5215
5216     function quickId(ns, mode, root, id){
5217         if(ns == root){
5218            var d = root.ownerDocument || root;
5219            return d.getElementById(id);
5220         }
5221         ns = getNodes(ns, mode, "*");
5222         return byId(ns, null, id);
5223     }
5224
5225     return {
5226         getStyle : function(el, name){
5227             return Roo.fly(el).getStyle(name);
5228         },
5229         /**
5230          * Compiles a selector/xpath query into a reusable function. The returned function
5231          * takes one parameter "root" (optional), which is the context node from where the query should start.
5232          * @param {String} selector The selector/xpath query
5233          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5234          * @return {Function}
5235          */
5236         compile : function(path, type){
5237             type = type || "select";
5238             
5239             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5240             var q = path, mode, lq;
5241             var tk = Roo.DomQuery.matchers;
5242             var tklen = tk.length;
5243             var mm;
5244
5245             // accept leading mode switch
5246             var lmode = q.match(modeRe);
5247             if(lmode && lmode[1]){
5248                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5249                 q = q.replace(lmode[1], "");
5250             }
5251             // strip leading slashes
5252             while(path.substr(0, 1)=="/"){
5253                 path = path.substr(1);
5254             }
5255
5256             while(q && lq != q){
5257                 lq = q;
5258                 var tm = q.match(tagTokenRe);
5259                 if(type == "select"){
5260                     if(tm){
5261                         if(tm[1] == "#"){
5262                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5263                         }else{
5264                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5265                         }
5266                         q = q.replace(tm[0], "");
5267                     }else if(q.substr(0, 1) != '@'){
5268                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5269                     }
5270                 }else{
5271                     if(tm){
5272                         if(tm[1] == "#"){
5273                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5274                         }else{
5275                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5276                         }
5277                         q = q.replace(tm[0], "");
5278                     }
5279                 }
5280                 while(!(mm = q.match(modeRe))){
5281                     var matched = false;
5282                     for(var j = 0; j < tklen; j++){
5283                         var t = tk[j];
5284                         var m = q.match(t.re);
5285                         if(m){
5286                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5287                                                     return m[i];
5288                                                 });
5289                             q = q.replace(m[0], "");
5290                             matched = true;
5291                             break;
5292                         }
5293                     }
5294                     // prevent infinite loop on bad selector
5295                     if(!matched){
5296                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5297                     }
5298                 }
5299                 if(mm[1]){
5300                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5301                     q = q.replace(mm[1], "");
5302                 }
5303             }
5304             fn[fn.length] = "return nodup(n);\n}";
5305             
5306              /** 
5307               * list of variables that need from compression as they are used by eval.
5308              *  eval:var:batch 
5309              *  eval:var:nodup
5310              *  eval:var:byTag
5311              *  eval:var:ById
5312              *  eval:var:getNodes
5313              *  eval:var:quickId
5314              *  eval:var:mode
5315              *  eval:var:root
5316              *  eval:var:n
5317              *  eval:var:byClassName
5318              *  eval:var:byPseudo
5319              *  eval:var:byAttribute
5320              *  eval:var:attrValue
5321              * 
5322              **/ 
5323             eval(fn.join(""));
5324             return f;
5325         },
5326
5327         /**
5328          * Selects a group of elements.
5329          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5330          * @param {Node} root (optional) The start of the query (defaults to document).
5331          * @return {Array}
5332          */
5333         select : function(path, root, type){
5334             if(!root || root == document){
5335                 root = document;
5336             }
5337             if(typeof root == "string"){
5338                 root = document.getElementById(root);
5339             }
5340             var paths = path.split(",");
5341             var results = [];
5342             for(var i = 0, len = paths.length; i < len; i++){
5343                 var p = paths[i].replace(trimRe, "");
5344                 if(!cache[p]){
5345                     cache[p] = Roo.DomQuery.compile(p);
5346                     if(!cache[p]){
5347                         throw p + " is not a valid selector";
5348                     }
5349                 }
5350                 var result = cache[p](root);
5351                 if(result && result != document){
5352                     results = results.concat(result);
5353                 }
5354             }
5355             if(paths.length > 1){
5356                 return nodup(results);
5357             }
5358             return results;
5359         },
5360
5361         /**
5362          * Selects a single element.
5363          * @param {String} selector The selector/xpath query
5364          * @param {Node} root (optional) The start of the query (defaults to document).
5365          * @return {Element}
5366          */
5367         selectNode : function(path, root){
5368             return Roo.DomQuery.select(path, root)[0];
5369         },
5370
5371         /**
5372          * Selects the value of a node, optionally replacing null with the defaultValue.
5373          * @param {String} selector The selector/xpath query
5374          * @param {Node} root (optional) The start of the query (defaults to document).
5375          * @param {String} defaultValue
5376          */
5377         selectValue : function(path, root, defaultValue){
5378             path = path.replace(trimRe, "");
5379             if(!valueCache[path]){
5380                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5381             }
5382             var n = valueCache[path](root);
5383             n = n[0] ? n[0] : n;
5384             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5385             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5386         },
5387
5388         /**
5389          * Selects the value of a node, parsing integers and floats.
5390          * @param {String} selector The selector/xpath query
5391          * @param {Node} root (optional) The start of the query (defaults to document).
5392          * @param {Number} defaultValue
5393          * @return {Number}
5394          */
5395         selectNumber : function(path, root, defaultValue){
5396             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5397             return parseFloat(v);
5398         },
5399
5400         /**
5401          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5402          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5403          * @param {String} selector The simple selector to test
5404          * @return {Boolean}
5405          */
5406         is : function(el, ss){
5407             if(typeof el == "string"){
5408                 el = document.getElementById(el);
5409             }
5410             var isArray = (el instanceof Array);
5411             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5412             return isArray ? (result.length == el.length) : (result.length > 0);
5413         },
5414
5415         /**
5416          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5417          * @param {Array} el An array of elements to filter
5418          * @param {String} selector The simple selector to test
5419          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5420          * the selector instead of the ones that match
5421          * @return {Array}
5422          */
5423         filter : function(els, ss, nonMatches){
5424             ss = ss.replace(trimRe, "");
5425             if(!simpleCache[ss]){
5426                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5427             }
5428             var result = simpleCache[ss](els);
5429             return nonMatches ? quickDiff(result, els) : result;
5430         },
5431
5432         /**
5433          * Collection of matching regular expressions and code snippets.
5434          */
5435         matchers : [{
5436                 re: /^\.([\w-]+)/,
5437                 select: 'n = byClassName(n, null, " {1} ");'
5438             }, {
5439                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5440                 select: 'n = byPseudo(n, "{1}", "{2}");'
5441             },{
5442                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5443                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5444             }, {
5445                 re: /^#([\w-]+)/,
5446                 select: 'n = byId(n, null, "{1}");'
5447             },{
5448                 re: /^@([\w-]+)/,
5449                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5450             }
5451         ],
5452
5453         /**
5454          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5455          * 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;.
5456          */
5457         operators : {
5458             "=" : function(a, v){
5459                 return a == v;
5460             },
5461             "!=" : function(a, v){
5462                 return a != v;
5463             },
5464             "^=" : function(a, v){
5465                 return a && a.substr(0, v.length) == v;
5466             },
5467             "$=" : function(a, v){
5468                 return a && a.substr(a.length-v.length) == v;
5469             },
5470             "*=" : function(a, v){
5471                 return a && a.indexOf(v) !== -1;
5472             },
5473             "%=" : function(a, v){
5474                 return (a % v) == 0;
5475             },
5476             "|=" : function(a, v){
5477                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5478             },
5479             "~=" : function(a, v){
5480                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5481             }
5482         },
5483
5484         /**
5485          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5486          * and the argument (if any) supplied in the selector.
5487          */
5488         pseudos : {
5489             "first-child" : function(c){
5490                 var r = [], ri = -1, n;
5491                 for(var i = 0, ci; ci = n = c[i]; i++){
5492                     while((n = n.previousSibling) && n.nodeType != 1);
5493                     if(!n){
5494                         r[++ri] = ci;
5495                     }
5496                 }
5497                 return r;
5498             },
5499
5500             "last-child" : function(c){
5501                 var r = [], ri = -1, n;
5502                 for(var i = 0, ci; ci = n = c[i]; i++){
5503                     while((n = n.nextSibling) && n.nodeType != 1);
5504                     if(!n){
5505                         r[++ri] = ci;
5506                     }
5507                 }
5508                 return r;
5509             },
5510
5511             "nth-child" : function(c, a) {
5512                 var r = [], ri = -1;
5513                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5514                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5515                 for(var i = 0, n; n = c[i]; i++){
5516                     var pn = n.parentNode;
5517                     if (batch != pn._batch) {
5518                         var j = 0;
5519                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5520                             if(cn.nodeType == 1){
5521                                cn.nodeIndex = ++j;
5522                             }
5523                         }
5524                         pn._batch = batch;
5525                     }
5526                     if (f == 1) {
5527                         if (l == 0 || n.nodeIndex == l){
5528                             r[++ri] = n;
5529                         }
5530                     } else if ((n.nodeIndex + l) % f == 0){
5531                         r[++ri] = n;
5532                     }
5533                 }
5534
5535                 return r;
5536             },
5537
5538             "only-child" : function(c){
5539                 var r = [], ri = -1;;
5540                 for(var i = 0, ci; ci = c[i]; i++){
5541                     if(!prev(ci) && !next(ci)){
5542                         r[++ri] = ci;
5543                     }
5544                 }
5545                 return r;
5546             },
5547
5548             "empty" : function(c){
5549                 var r = [], ri = -1;
5550                 for(var i = 0, ci; ci = c[i]; i++){
5551                     var cns = ci.childNodes, j = 0, cn, empty = true;
5552                     while(cn = cns[j]){
5553                         ++j;
5554                         if(cn.nodeType == 1 || cn.nodeType == 3){
5555                             empty = false;
5556                             break;
5557                         }
5558                     }
5559                     if(empty){
5560                         r[++ri] = ci;
5561                     }
5562                 }
5563                 return r;
5564             },
5565
5566             "contains" : function(c, v){
5567                 var r = [], ri = -1;
5568                 for(var i = 0, ci; ci = c[i]; i++){
5569                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5570                         r[++ri] = ci;
5571                     }
5572                 }
5573                 return r;
5574             },
5575
5576             "nodeValue" : function(c, v){
5577                 var r = [], ri = -1;
5578                 for(var i = 0, ci; ci = c[i]; i++){
5579                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5580                         r[++ri] = ci;
5581                     }
5582                 }
5583                 return r;
5584             },
5585
5586             "checked" : function(c){
5587                 var r = [], ri = -1;
5588                 for(var i = 0, ci; ci = c[i]; i++){
5589                     if(ci.checked == true){
5590                         r[++ri] = ci;
5591                     }
5592                 }
5593                 return r;
5594             },
5595
5596             "not" : function(c, ss){
5597                 return Roo.DomQuery.filter(c, ss, true);
5598             },
5599
5600             "odd" : function(c){
5601                 return this["nth-child"](c, "odd");
5602             },
5603
5604             "even" : function(c){
5605                 return this["nth-child"](c, "even");
5606             },
5607
5608             "nth" : function(c, a){
5609                 return c[a-1] || [];
5610             },
5611
5612             "first" : function(c){
5613                 return c[0] || [];
5614             },
5615
5616             "last" : function(c){
5617                 return c[c.length-1] || [];
5618             },
5619
5620             "has" : function(c, ss){
5621                 var s = Roo.DomQuery.select;
5622                 var r = [], ri = -1;
5623                 for(var i = 0, ci; ci = c[i]; i++){
5624                     if(s(ss, ci).length > 0){
5625                         r[++ri] = ci;
5626                     }
5627                 }
5628                 return r;
5629             },
5630
5631             "next" : function(c, ss){
5632                 var is = Roo.DomQuery.is;
5633                 var r = [], ri = -1;
5634                 for(var i = 0, ci; ci = c[i]; i++){
5635                     var n = next(ci);
5636                     if(n && is(n, ss)){
5637                         r[++ri] = ci;
5638                     }
5639                 }
5640                 return r;
5641             },
5642
5643             "prev" : function(c, ss){
5644                 var is = Roo.DomQuery.is;
5645                 var r = [], ri = -1;
5646                 for(var i = 0, ci; ci = c[i]; i++){
5647                     var n = prev(ci);
5648                     if(n && is(n, ss)){
5649                         r[++ri] = ci;
5650                     }
5651                 }
5652                 return r;
5653             }
5654         }
5655     };
5656 }();
5657
5658 /**
5659  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5660  * @param {String} path The selector/xpath query
5661  * @param {Node} root (optional) The start of the query (defaults to document).
5662  * @return {Array}
5663  * @member Roo
5664  * @method query
5665  */
5666 Roo.query = Roo.DomQuery.select;
5667 /*
5668  * Based on:
5669  * Ext JS Library 1.1.1
5670  * Copyright(c) 2006-2007, Ext JS, LLC.
5671  *
5672  * Originally Released Under LGPL - original licence link has changed is not relivant.
5673  *
5674  * Fork - LGPL
5675  * <script type="text/javascript">
5676  */
5677
5678 /**
5679  * @class Roo.util.Observable
5680  * Base class that provides a common interface for publishing events. Subclasses are expected to
5681  * to have a property "events" with all the events defined.<br>
5682  * For example:
5683  * <pre><code>
5684  Employee = function(name){
5685     this.name = name;
5686     this.addEvents({
5687         "fired" : true,
5688         "quit" : true
5689     });
5690  }
5691  Roo.extend(Employee, Roo.util.Observable);
5692 </code></pre>
5693  * @param {Object} config properties to use (incuding events / listeners)
5694  */
5695
5696 Roo.util.Observable = function(cfg){
5697     
5698     cfg = cfg|| {};
5699     this.addEvents(cfg.events || {});
5700     if (cfg.events) {
5701         delete cfg.events; // make sure
5702     }
5703      
5704     Roo.apply(this, cfg);
5705     
5706     if(this.listeners){
5707         this.on(this.listeners);
5708         delete this.listeners;
5709     }
5710 };
5711 Roo.util.Observable.prototype = {
5712     /** 
5713  * @cfg {Object} listeners  list of events and functions to call for this object, 
5714  * For example :
5715  * <pre><code>
5716     listeners :  { 
5717        'click' : function(e) {
5718            ..... 
5719         } ,
5720         .... 
5721     } 
5722   </code></pre>
5723  */
5724     
5725     
5726     /**
5727      * Fires the specified event with the passed parameters (minus the event name).
5728      * @param {String} eventName
5729      * @param {Object...} args Variable number of parameters are passed to handlers
5730      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5731      */
5732     fireEvent : function(){
5733         var ce = this.events[arguments[0].toLowerCase()];
5734         if(typeof ce == "object"){
5735             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5736         }else{
5737             return true;
5738         }
5739     },
5740
5741     // private
5742     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5743
5744     /**
5745      * Appends an event handler to this component
5746      * @param {String}   eventName The type of event to listen for
5747      * @param {Function} handler The method the event invokes
5748      * @param {Object}   scope (optional) The scope in which to execute the handler
5749      * function. The handler function's "this" context.
5750      * @param {Object}   options (optional) An object containing handler configuration
5751      * properties. This may contain any of the following properties:<ul>
5752      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5753      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5754      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5755      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5756      * by the specified number of milliseconds. If the event fires again within that time, the original
5757      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5758      * </ul><br>
5759      * <p>
5760      * <b>Combining Options</b><br>
5761      * Using the options argument, it is possible to combine different types of listeners:<br>
5762      * <br>
5763      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5764                 <pre><code>
5765                 el.on('click', this.onClick, this, {
5766                         single: true,
5767                 delay: 100,
5768                 forumId: 4
5769                 });
5770                 </code></pre>
5771      * <p>
5772      * <b>Attaching multiple handlers in 1 call</b><br>
5773      * The method also allows for a single argument to be passed which is a config object containing properties
5774      * which specify multiple handlers.
5775      * <pre><code>
5776                 el.on({
5777                         'click': {
5778                         fn: this.onClick,
5779                         scope: this,
5780                         delay: 100
5781                 }, 
5782                 'mouseover': {
5783                         fn: this.onMouseOver,
5784                         scope: this
5785                 },
5786                 'mouseout': {
5787                         fn: this.onMouseOut,
5788                         scope: this
5789                 }
5790                 });
5791                 </code></pre>
5792      * <p>
5793      * Or a shorthand syntax which passes the same scope object to all handlers:
5794         <pre><code>
5795                 el.on({
5796                         'click': this.onClick,
5797                 'mouseover': this.onMouseOver,
5798                 'mouseout': this.onMouseOut,
5799                 scope: this
5800                 });
5801                 </code></pre>
5802      */
5803     addListener : function(eventName, fn, scope, o){
5804         if(typeof eventName == "object"){
5805             o = eventName;
5806             for(var e in o){
5807                 if(this.filterOptRe.test(e)){
5808                     continue;
5809                 }
5810                 if(typeof o[e] == "function"){
5811                     // shared options
5812                     this.addListener(e, o[e], o.scope,  o);
5813                 }else{
5814                     // individual options
5815                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5816                 }
5817             }
5818             return;
5819         }
5820         o = (!o || typeof o == "boolean") ? {} : o;
5821         eventName = eventName.toLowerCase();
5822         var ce = this.events[eventName] || true;
5823         if(typeof ce == "boolean"){
5824             ce = new Roo.util.Event(this, eventName);
5825             this.events[eventName] = ce;
5826         }
5827         ce.addListener(fn, scope, o);
5828     },
5829
5830     /**
5831      * Removes a listener
5832      * @param {String}   eventName     The type of event to listen for
5833      * @param {Function} handler        The handler to remove
5834      * @param {Object}   scope  (optional) The scope (this object) for the handler
5835      */
5836     removeListener : function(eventName, fn, scope){
5837         var ce = this.events[eventName.toLowerCase()];
5838         if(typeof ce == "object"){
5839             ce.removeListener(fn, scope);
5840         }
5841     },
5842
5843     /**
5844      * Removes all listeners for this object
5845      */
5846     purgeListeners : function(){
5847         for(var evt in this.events){
5848             if(typeof this.events[evt] == "object"){
5849                  this.events[evt].clearListeners();
5850             }
5851         }
5852     },
5853
5854     relayEvents : function(o, events){
5855         var createHandler = function(ename){
5856             return function(){
5857                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5858             };
5859         };
5860         for(var i = 0, len = events.length; i < len; i++){
5861             var ename = events[i];
5862             if(!this.events[ename]){ this.events[ename] = true; };
5863             o.on(ename, createHandler(ename), this);
5864         }
5865     },
5866
5867     /**
5868      * Used to define events on this Observable
5869      * @param {Object} object The object with the events defined
5870      */
5871     addEvents : function(o){
5872         if(!this.events){
5873             this.events = {};
5874         }
5875         Roo.applyIf(this.events, o);
5876     },
5877
5878     /**
5879      * Checks to see if this object has any listeners for a specified event
5880      * @param {String} eventName The name of the event to check for
5881      * @return {Boolean} True if the event is being listened for, else false
5882      */
5883     hasListener : function(eventName){
5884         var e = this.events[eventName];
5885         return typeof e == "object" && e.listeners.length > 0;
5886     }
5887 };
5888 /**
5889  * Appends an event handler to this element (shorthand for addListener)
5890  * @param {String}   eventName     The type of event to listen for
5891  * @param {Function} handler        The method the event invokes
5892  * @param {Object}   scope (optional) The scope in which to execute the handler
5893  * function. The handler function's "this" context.
5894  * @param {Object}   options  (optional)
5895  * @method
5896  */
5897 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5898 /**
5899  * Removes a listener (shorthand for removeListener)
5900  * @param {String}   eventName     The type of event to listen for
5901  * @param {Function} handler        The handler to remove
5902  * @param {Object}   scope  (optional) The scope (this object) for the handler
5903  * @method
5904  */
5905 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5906
5907 /**
5908  * Starts capture on the specified Observable. All events will be passed
5909  * to the supplied function with the event name + standard signature of the event
5910  * <b>before</b> the event is fired. If the supplied function returns false,
5911  * the event will not fire.
5912  * @param {Observable} o The Observable to capture
5913  * @param {Function} fn The function to call
5914  * @param {Object} scope (optional) The scope (this object) for the fn
5915  * @static
5916  */
5917 Roo.util.Observable.capture = function(o, fn, scope){
5918     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5919 };
5920
5921 /**
5922  * Removes <b>all</b> added captures from the Observable.
5923  * @param {Observable} o The Observable to release
5924  * @static
5925  */
5926 Roo.util.Observable.releaseCapture = function(o){
5927     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5928 };
5929
5930 (function(){
5931
5932     var createBuffered = function(h, o, scope){
5933         var task = new Roo.util.DelayedTask();
5934         return function(){
5935             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5936         };
5937     };
5938
5939     var createSingle = function(h, e, fn, scope){
5940         return function(){
5941             e.removeListener(fn, scope);
5942             return h.apply(scope, arguments);
5943         };
5944     };
5945
5946     var createDelayed = function(h, o, scope){
5947         return function(){
5948             var args = Array.prototype.slice.call(arguments, 0);
5949             setTimeout(function(){
5950                 h.apply(scope, args);
5951             }, o.delay || 10);
5952         };
5953     };
5954
5955     Roo.util.Event = function(obj, name){
5956         this.name = name;
5957         this.obj = obj;
5958         this.listeners = [];
5959     };
5960
5961     Roo.util.Event.prototype = {
5962         addListener : function(fn, scope, options){
5963             var o = options || {};
5964             scope = scope || this.obj;
5965             if(!this.isListening(fn, scope)){
5966                 var l = {fn: fn, scope: scope, options: o};
5967                 var h = fn;
5968                 if(o.delay){
5969                     h = createDelayed(h, o, scope);
5970                 }
5971                 if(o.single){
5972                     h = createSingle(h, this, fn, scope);
5973                 }
5974                 if(o.buffer){
5975                     h = createBuffered(h, o, scope);
5976                 }
5977                 l.fireFn = h;
5978                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5979                     this.listeners.push(l);
5980                 }else{
5981                     this.listeners = this.listeners.slice(0);
5982                     this.listeners.push(l);
5983                 }
5984             }
5985         },
5986
5987         findListener : function(fn, scope){
5988             scope = scope || this.obj;
5989             var ls = this.listeners;
5990             for(var i = 0, len = ls.length; i < len; i++){
5991                 var l = ls[i];
5992                 if(l.fn == fn && l.scope == scope){
5993                     return i;
5994                 }
5995             }
5996             return -1;
5997         },
5998
5999         isListening : function(fn, scope){
6000             return this.findListener(fn, scope) != -1;
6001         },
6002
6003         removeListener : function(fn, scope){
6004             var index;
6005             if((index = this.findListener(fn, scope)) != -1){
6006                 if(!this.firing){
6007                     this.listeners.splice(index, 1);
6008                 }else{
6009                     this.listeners = this.listeners.slice(0);
6010                     this.listeners.splice(index, 1);
6011                 }
6012                 return true;
6013             }
6014             return false;
6015         },
6016
6017         clearListeners : function(){
6018             this.listeners = [];
6019         },
6020
6021         fire : function(){
6022             var ls = this.listeners, scope, len = ls.length;
6023             if(len > 0){
6024                 this.firing = true;
6025                 var args = Array.prototype.slice.call(arguments, 0);
6026                 for(var i = 0; i < len; i++){
6027                     var l = ls[i];
6028                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6029                         this.firing = false;
6030                         return false;
6031                     }
6032                 }
6033                 this.firing = false;
6034             }
6035             return true;
6036         }
6037     };
6038 })();/*
6039  * Based on:
6040  * Ext JS Library 1.1.1
6041  * Copyright(c) 2006-2007, Ext JS, LLC.
6042  *
6043  * Originally Released Under LGPL - original licence link has changed is not relivant.
6044  *
6045  * Fork - LGPL
6046  * <script type="text/javascript">
6047  */
6048
6049 /**
6050  * @class Roo.EventManager
6051  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6052  * several useful events directly.
6053  * See {@link Roo.EventObject} for more details on normalized event objects.
6054  * @singleton
6055  */
6056 Roo.EventManager = function(){
6057     var docReadyEvent, docReadyProcId, docReadyState = false;
6058     var resizeEvent, resizeTask, textEvent, textSize;
6059     var E = Roo.lib.Event;
6060     var D = Roo.lib.Dom;
6061
6062     
6063     
6064
6065     var fireDocReady = function(){
6066         if(!docReadyState){
6067             docReadyState = true;
6068             Roo.isReady = true;
6069             if(docReadyProcId){
6070                 clearInterval(docReadyProcId);
6071             }
6072             if(Roo.isGecko || Roo.isOpera) {
6073                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6074             }
6075             if(Roo.isIE){
6076                 var defer = document.getElementById("ie-deferred-loader");
6077                 if(defer){
6078                     defer.onreadystatechange = null;
6079                     defer.parentNode.removeChild(defer);
6080                 }
6081             }
6082             if(docReadyEvent){
6083                 docReadyEvent.fire();
6084                 docReadyEvent.clearListeners();
6085             }
6086         }
6087     };
6088     
6089     var initDocReady = function(){
6090         docReadyEvent = new Roo.util.Event();
6091         if(Roo.isGecko || Roo.isOpera) {
6092             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6093         }else if(Roo.isIE){
6094             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6095             var defer = document.getElementById("ie-deferred-loader");
6096             defer.onreadystatechange = function(){
6097                 if(this.readyState == "complete"){
6098                     fireDocReady();
6099                 }
6100             };
6101         }else if(Roo.isSafari){ 
6102             docReadyProcId = setInterval(function(){
6103                 var rs = document.readyState;
6104                 if(rs == "complete") {
6105                     fireDocReady();     
6106                  }
6107             }, 10);
6108         }
6109         // no matter what, make sure it fires on load
6110         E.on(window, "load", fireDocReady);
6111     };
6112
6113     var createBuffered = function(h, o){
6114         var task = new Roo.util.DelayedTask(h);
6115         return function(e){
6116             // create new event object impl so new events don't wipe out properties
6117             e = new Roo.EventObjectImpl(e);
6118             task.delay(o.buffer, h, null, [e]);
6119         };
6120     };
6121
6122     var createSingle = function(h, el, ename, fn){
6123         return function(e){
6124             Roo.EventManager.removeListener(el, ename, fn);
6125             h(e);
6126         };
6127     };
6128
6129     var createDelayed = function(h, o){
6130         return function(e){
6131             // create new event object impl so new events don't wipe out properties
6132             e = new Roo.EventObjectImpl(e);
6133             setTimeout(function(){
6134                 h(e);
6135             }, o.delay || 10);
6136         };
6137     };
6138     var transitionEndVal = false;
6139     
6140     var transitionEnd = function()
6141     {
6142         if (transitionEndVal) {
6143             return transitionEndVal;
6144         }
6145         var el = document.createElement('div');
6146
6147         var transEndEventNames = {
6148             WebkitTransition : 'webkitTransitionEnd',
6149             MozTransition    : 'transitionend',
6150             OTransition      : 'oTransitionEnd otransitionend',
6151             transition       : 'transitionend'
6152         };
6153     
6154         for (var name in transEndEventNames) {
6155             if (el.style[name] !== undefined) {
6156                 transitionEndVal = transEndEventNames[name];
6157                 return  transitionEndVal ;
6158             }
6159         }
6160     }
6161     
6162
6163     var listen = function(element, ename, opt, fn, scope){
6164         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6165         fn = fn || o.fn; scope = scope || o.scope;
6166         var el = Roo.getDom(element);
6167         
6168         
6169         if(!el){
6170             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6171         }
6172         
6173         if (ename == 'transitionend') {
6174             ename = transitionEnd();
6175         }
6176         var h = function(e){
6177             e = Roo.EventObject.setEvent(e);
6178             var t;
6179             if(o.delegate){
6180                 t = e.getTarget(o.delegate, el);
6181                 if(!t){
6182                     return;
6183                 }
6184             }else{
6185                 t = e.target;
6186             }
6187             if(o.stopEvent === true){
6188                 e.stopEvent();
6189             }
6190             if(o.preventDefault === true){
6191                e.preventDefault();
6192             }
6193             if(o.stopPropagation === true){
6194                 e.stopPropagation();
6195             }
6196
6197             if(o.normalized === false){
6198                 e = e.browserEvent;
6199             }
6200
6201             fn.call(scope || el, e, t, o);
6202         };
6203         if(o.delay){
6204             h = createDelayed(h, o);
6205         }
6206         if(o.single){
6207             h = createSingle(h, el, ename, fn);
6208         }
6209         if(o.buffer){
6210             h = createBuffered(h, o);
6211         }
6212         fn._handlers = fn._handlers || [];
6213         
6214         
6215         fn._handlers.push([Roo.id(el), ename, h]);
6216         
6217         
6218          
6219         E.on(el, ename, h);
6220         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6221             el.addEventListener("DOMMouseScroll", h, false);
6222             E.on(window, 'unload', function(){
6223                 el.removeEventListener("DOMMouseScroll", h, false);
6224             });
6225         }
6226         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6227             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6228         }
6229         return h;
6230     };
6231
6232     var stopListening = function(el, ename, fn){
6233         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6234         if(hds){
6235             for(var i = 0, len = hds.length; i < len; i++){
6236                 var h = hds[i];
6237                 if(h[0] == id && h[1] == ename){
6238                     hd = h[2];
6239                     hds.splice(i, 1);
6240                     break;
6241                 }
6242             }
6243         }
6244         E.un(el, ename, hd);
6245         el = Roo.getDom(el);
6246         if(ename == "mousewheel" && el.addEventListener){
6247             el.removeEventListener("DOMMouseScroll", hd, false);
6248         }
6249         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6250             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6251         }
6252     };
6253
6254     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6255     
6256     var pub = {
6257         
6258         
6259         /** 
6260          * Fix for doc tools
6261          * @scope Roo.EventManager
6262          */
6263         
6264         
6265         /** 
6266          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6267          * object with a Roo.EventObject
6268          * @param {Function} fn        The method the event invokes
6269          * @param {Object}   scope    An object that becomes the scope of the handler
6270          * @param {boolean}  override If true, the obj passed in becomes
6271          *                             the execution scope of the listener
6272          * @return {Function} The wrapped function
6273          * @deprecated
6274          */
6275         wrap : function(fn, scope, override){
6276             return function(e){
6277                 Roo.EventObject.setEvent(e);
6278                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6279             };
6280         },
6281         
6282         /**
6283      * Appends an event handler to an element (shorthand for addListener)
6284      * @param {String/HTMLElement}   element        The html element or id to assign the
6285      * @param {String}   eventName The type of event to listen for
6286      * @param {Function} handler The method the event invokes
6287      * @param {Object}   scope (optional) The scope in which to execute the handler
6288      * function. The handler function's "this" context.
6289      * @param {Object}   options (optional) An object containing handler configuration
6290      * properties. This may contain any of the following properties:<ul>
6291      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6292      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6293      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6294      * <li>preventDefault {Boolean} True to prevent the default action</li>
6295      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6296      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6297      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6298      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6299      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6300      * by the specified number of milliseconds. If the event fires again within that time, the original
6301      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6302      * </ul><br>
6303      * <p>
6304      * <b>Combining Options</b><br>
6305      * Using the options argument, it is possible to combine different types of listeners:<br>
6306      * <br>
6307      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6308      * Code:<pre><code>
6309 el.on('click', this.onClick, this, {
6310     single: true,
6311     delay: 100,
6312     stopEvent : true,
6313     forumId: 4
6314 });</code></pre>
6315      * <p>
6316      * <b>Attaching multiple handlers in 1 call</b><br>
6317       * The method also allows for a single argument to be passed which is a config object containing properties
6318      * which specify multiple handlers.
6319      * <p>
6320      * Code:<pre><code>
6321 el.on({
6322     'click' : {
6323         fn: this.onClick
6324         scope: this,
6325         delay: 100
6326     },
6327     'mouseover' : {
6328         fn: this.onMouseOver
6329         scope: this
6330     },
6331     'mouseout' : {
6332         fn: this.onMouseOut
6333         scope: this
6334     }
6335 });</code></pre>
6336      * <p>
6337      * Or a shorthand syntax:<br>
6338      * Code:<pre><code>
6339 el.on({
6340     'click' : this.onClick,
6341     'mouseover' : this.onMouseOver,
6342     'mouseout' : this.onMouseOut
6343     scope: this
6344 });</code></pre>
6345      */
6346         addListener : function(element, eventName, fn, scope, options){
6347             if(typeof eventName == "object"){
6348                 var o = eventName;
6349                 for(var e in o){
6350                     if(propRe.test(e)){
6351                         continue;
6352                     }
6353                     if(typeof o[e] == "function"){
6354                         // shared options
6355                         listen(element, e, o, o[e], o.scope);
6356                     }else{
6357                         // individual options
6358                         listen(element, e, o[e]);
6359                     }
6360                 }
6361                 return;
6362             }
6363             return listen(element, eventName, options, fn, scope);
6364         },
6365         
6366         /**
6367          * Removes an event handler
6368          *
6369          * @param {String/HTMLElement}   element        The id or html element to remove the 
6370          *                             event from
6371          * @param {String}   eventName     The type of event
6372          * @param {Function} fn
6373          * @return {Boolean} True if a listener was actually removed
6374          */
6375         removeListener : function(element, eventName, fn){
6376             return stopListening(element, eventName, fn);
6377         },
6378         
6379         /**
6380          * Fires when the document is ready (before onload and before images are loaded). Can be 
6381          * accessed shorthanded Roo.onReady().
6382          * @param {Function} fn        The method the event invokes
6383          * @param {Object}   scope    An  object that becomes the scope of the handler
6384          * @param {boolean}  options
6385          */
6386         onDocumentReady : function(fn, scope, options){
6387             if(docReadyState){ // if it already fired
6388                 docReadyEvent.addListener(fn, scope, options);
6389                 docReadyEvent.fire();
6390                 docReadyEvent.clearListeners();
6391                 return;
6392             }
6393             if(!docReadyEvent){
6394                 initDocReady();
6395             }
6396             docReadyEvent.addListener(fn, scope, options);
6397         },
6398         
6399         /**
6400          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6401          * @param {Function} fn        The method the event invokes
6402          * @param {Object}   scope    An object that becomes the scope of the handler
6403          * @param {boolean}  options
6404          */
6405         onWindowResize : function(fn, scope, options){
6406             if(!resizeEvent){
6407                 resizeEvent = new Roo.util.Event();
6408                 resizeTask = new Roo.util.DelayedTask(function(){
6409                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6410                 });
6411                 E.on(window, "resize", function(){
6412                     if(Roo.isIE){
6413                         resizeTask.delay(50);
6414                     }else{
6415                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6416                     }
6417                 });
6418             }
6419             resizeEvent.addListener(fn, scope, options);
6420         },
6421
6422         /**
6423          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6424          * @param {Function} fn        The method the event invokes
6425          * @param {Object}   scope    An object that becomes the scope of the handler
6426          * @param {boolean}  options
6427          */
6428         onTextResize : function(fn, scope, options){
6429             if(!textEvent){
6430                 textEvent = new Roo.util.Event();
6431                 var textEl = new Roo.Element(document.createElement('div'));
6432                 textEl.dom.className = 'x-text-resize';
6433                 textEl.dom.innerHTML = 'X';
6434                 textEl.appendTo(document.body);
6435                 textSize = textEl.dom.offsetHeight;
6436                 setInterval(function(){
6437                     if(textEl.dom.offsetHeight != textSize){
6438                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6439                     }
6440                 }, this.textResizeInterval);
6441             }
6442             textEvent.addListener(fn, scope, options);
6443         },
6444
6445         /**
6446          * Removes the passed window resize listener.
6447          * @param {Function} fn        The method the event invokes
6448          * @param {Object}   scope    The scope of handler
6449          */
6450         removeResizeListener : function(fn, scope){
6451             if(resizeEvent){
6452                 resizeEvent.removeListener(fn, scope);
6453             }
6454         },
6455
6456         // private
6457         fireResize : function(){
6458             if(resizeEvent){
6459                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6460             }   
6461         },
6462         /**
6463          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6464          */
6465         ieDeferSrc : false,
6466         /**
6467          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6468          */
6469         textResizeInterval : 50
6470     };
6471     
6472     /**
6473      * Fix for doc tools
6474      * @scopeAlias pub=Roo.EventManager
6475      */
6476     
6477      /**
6478      * Appends an event handler to an element (shorthand for addListener)
6479      * @param {String/HTMLElement}   element        The html element or id to assign the
6480      * @param {String}   eventName The type of event to listen for
6481      * @param {Function} handler The method the event invokes
6482      * @param {Object}   scope (optional) The scope in which to execute the handler
6483      * function. The handler function's "this" context.
6484      * @param {Object}   options (optional) An object containing handler configuration
6485      * properties. This may contain any of the following properties:<ul>
6486      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6487      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6488      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6489      * <li>preventDefault {Boolean} True to prevent the default action</li>
6490      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6491      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6492      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6493      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6494      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6495      * by the specified number of milliseconds. If the event fires again within that time, the original
6496      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6497      * </ul><br>
6498      * <p>
6499      * <b>Combining Options</b><br>
6500      * Using the options argument, it is possible to combine different types of listeners:<br>
6501      * <br>
6502      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6503      * Code:<pre><code>
6504 el.on('click', this.onClick, this, {
6505     single: true,
6506     delay: 100,
6507     stopEvent : true,
6508     forumId: 4
6509 });</code></pre>
6510      * <p>
6511      * <b>Attaching multiple handlers in 1 call</b><br>
6512       * The method also allows for a single argument to be passed which is a config object containing properties
6513      * which specify multiple handlers.
6514      * <p>
6515      * Code:<pre><code>
6516 el.on({
6517     'click' : {
6518         fn: this.onClick
6519         scope: this,
6520         delay: 100
6521     },
6522     'mouseover' : {
6523         fn: this.onMouseOver
6524         scope: this
6525     },
6526     'mouseout' : {
6527         fn: this.onMouseOut
6528         scope: this
6529     }
6530 });</code></pre>
6531      * <p>
6532      * Or a shorthand syntax:<br>
6533      * Code:<pre><code>
6534 el.on({
6535     'click' : this.onClick,
6536     'mouseover' : this.onMouseOver,
6537     'mouseout' : this.onMouseOut
6538     scope: this
6539 });</code></pre>
6540      */
6541     pub.on = pub.addListener;
6542     pub.un = pub.removeListener;
6543
6544     pub.stoppedMouseDownEvent = new Roo.util.Event();
6545     return pub;
6546 }();
6547 /**
6548   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6549   * @param {Function} fn        The method the event invokes
6550   * @param {Object}   scope    An  object that becomes the scope of the handler
6551   * @param {boolean}  override If true, the obj passed in becomes
6552   *                             the execution scope of the listener
6553   * @member Roo
6554   * @method onReady
6555  */
6556 Roo.onReady = Roo.EventManager.onDocumentReady;
6557
6558 Roo.onReady(function(){
6559     var bd = Roo.get(document.body);
6560     if(!bd){ return; }
6561
6562     var cls = [
6563             Roo.isIE ? "roo-ie"
6564             : Roo.isGecko ? "roo-gecko"
6565             : Roo.isOpera ? "roo-opera"
6566             : Roo.isSafari ? "roo-safari" : ""];
6567
6568     if(Roo.isMac){
6569         cls.push("roo-mac");
6570     }
6571     if(Roo.isLinux){
6572         cls.push("roo-linux");
6573     }
6574     if(Roo.isBorderBox){
6575         cls.push('roo-border-box');
6576     }
6577     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6578         var p = bd.dom.parentNode;
6579         if(p){
6580             p.className += ' roo-strict';
6581         }
6582     }
6583     bd.addClass(cls.join(' '));
6584 });
6585
6586 /**
6587  * @class Roo.EventObject
6588  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6589  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6590  * Example:
6591  * <pre><code>
6592  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6593     e.preventDefault();
6594     var target = e.getTarget();
6595     ...
6596  }
6597  var myDiv = Roo.get("myDiv");
6598  myDiv.on("click", handleClick);
6599  //or
6600  Roo.EventManager.on("myDiv", 'click', handleClick);
6601  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6602  </code></pre>
6603  * @singleton
6604  */
6605 Roo.EventObject = function(){
6606     
6607     var E = Roo.lib.Event;
6608     
6609     // safari keypress events for special keys return bad keycodes
6610     var safariKeys = {
6611         63234 : 37, // left
6612         63235 : 39, // right
6613         63232 : 38, // up
6614         63233 : 40, // down
6615         63276 : 33, // page up
6616         63277 : 34, // page down
6617         63272 : 46, // delete
6618         63273 : 36, // home
6619         63275 : 35  // end
6620     };
6621
6622     // normalize button clicks
6623     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6624                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6625
6626     Roo.EventObjectImpl = function(e){
6627         if(e){
6628             this.setEvent(e.browserEvent || e);
6629         }
6630     };
6631     Roo.EventObjectImpl.prototype = {
6632         /**
6633          * Used to fix doc tools.
6634          * @scope Roo.EventObject.prototype
6635          */
6636             
6637
6638         
6639         
6640         /** The normal browser event */
6641         browserEvent : null,
6642         /** The button pressed in a mouse event */
6643         button : -1,
6644         /** True if the shift key was down during the event */
6645         shiftKey : false,
6646         /** True if the control key was down during the event */
6647         ctrlKey : false,
6648         /** True if the alt key was down during the event */
6649         altKey : false,
6650
6651         /** Key constant 
6652         * @type Number */
6653         BACKSPACE : 8,
6654         /** Key constant 
6655         * @type Number */
6656         TAB : 9,
6657         /** Key constant 
6658         * @type Number */
6659         RETURN : 13,
6660         /** Key constant 
6661         * @type Number */
6662         ENTER : 13,
6663         /** Key constant 
6664         * @type Number */
6665         SHIFT : 16,
6666         /** Key constant 
6667         * @type Number */
6668         CONTROL : 17,
6669         /** Key constant 
6670         * @type Number */
6671         ESC : 27,
6672         /** Key constant 
6673         * @type Number */
6674         SPACE : 32,
6675         /** Key constant 
6676         * @type Number */
6677         PAGEUP : 33,
6678         /** Key constant 
6679         * @type Number */
6680         PAGEDOWN : 34,
6681         /** Key constant 
6682         * @type Number */
6683         END : 35,
6684         /** Key constant 
6685         * @type Number */
6686         HOME : 36,
6687         /** Key constant 
6688         * @type Number */
6689         LEFT : 37,
6690         /** Key constant 
6691         * @type Number */
6692         UP : 38,
6693         /** Key constant 
6694         * @type Number */
6695         RIGHT : 39,
6696         /** Key constant 
6697         * @type Number */
6698         DOWN : 40,
6699         /** Key constant 
6700         * @type Number */
6701         DELETE : 46,
6702         /** Key constant 
6703         * @type Number */
6704         F5 : 116,
6705
6706            /** @private */
6707         setEvent : function(e){
6708             if(e == this || (e && e.browserEvent)){ // already wrapped
6709                 return e;
6710             }
6711             this.browserEvent = e;
6712             if(e){
6713                 // normalize buttons
6714                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6715                 if(e.type == 'click' && this.button == -1){
6716                     this.button = 0;
6717                 }
6718                 this.type = e.type;
6719                 this.shiftKey = e.shiftKey;
6720                 // mac metaKey behaves like ctrlKey
6721                 this.ctrlKey = e.ctrlKey || e.metaKey;
6722                 this.altKey = e.altKey;
6723                 // in getKey these will be normalized for the mac
6724                 this.keyCode = e.keyCode;
6725                 // keyup warnings on firefox.
6726                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6727                 // cache the target for the delayed and or buffered events
6728                 this.target = E.getTarget(e);
6729                 // same for XY
6730                 this.xy = E.getXY(e);
6731             }else{
6732                 this.button = -1;
6733                 this.shiftKey = false;
6734                 this.ctrlKey = false;
6735                 this.altKey = false;
6736                 this.keyCode = 0;
6737                 this.charCode =0;
6738                 this.target = null;
6739                 this.xy = [0, 0];
6740             }
6741             return this;
6742         },
6743
6744         /**
6745          * Stop the event (preventDefault and stopPropagation)
6746          */
6747         stopEvent : function(){
6748             if(this.browserEvent){
6749                 if(this.browserEvent.type == 'mousedown'){
6750                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6751                 }
6752                 E.stopEvent(this.browserEvent);
6753             }
6754         },
6755
6756         /**
6757          * Prevents the browsers default handling of the event.
6758          */
6759         preventDefault : function(){
6760             if(this.browserEvent){
6761                 E.preventDefault(this.browserEvent);
6762             }
6763         },
6764
6765         /** @private */
6766         isNavKeyPress : function(){
6767             var k = this.keyCode;
6768             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6769             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6770         },
6771
6772         isSpecialKey : function(){
6773             var k = this.keyCode;
6774             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6775             (k == 16) || (k == 17) ||
6776             (k >= 18 && k <= 20) ||
6777             (k >= 33 && k <= 35) ||
6778             (k >= 36 && k <= 39) ||
6779             (k >= 44 && k <= 45);
6780         },
6781         /**
6782          * Cancels bubbling of the event.
6783          */
6784         stopPropagation : function(){
6785             if(this.browserEvent){
6786                 if(this.type == 'mousedown'){
6787                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6788                 }
6789                 E.stopPropagation(this.browserEvent);
6790             }
6791         },
6792
6793         /**
6794          * Gets the key code for the event.
6795          * @return {Number}
6796          */
6797         getCharCode : function(){
6798             return this.charCode || this.keyCode;
6799         },
6800
6801         /**
6802          * Returns a normalized keyCode for the event.
6803          * @return {Number} The key code
6804          */
6805         getKey : function(){
6806             var k = this.keyCode || this.charCode;
6807             return Roo.isSafari ? (safariKeys[k] || k) : k;
6808         },
6809
6810         /**
6811          * Gets the x coordinate of the event.
6812          * @return {Number}
6813          */
6814         getPageX : function(){
6815             return this.xy[0];
6816         },
6817
6818         /**
6819          * Gets the y coordinate of the event.
6820          * @return {Number}
6821          */
6822         getPageY : function(){
6823             return this.xy[1];
6824         },
6825
6826         /**
6827          * Gets the time of the event.
6828          * @return {Number}
6829          */
6830         getTime : function(){
6831             if(this.browserEvent){
6832                 return E.getTime(this.browserEvent);
6833             }
6834             return null;
6835         },
6836
6837         /**
6838          * Gets the page coordinates of the event.
6839          * @return {Array} The xy values like [x, y]
6840          */
6841         getXY : function(){
6842             return this.xy;
6843         },
6844
6845         /**
6846          * Gets the target for the event.
6847          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6848          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6849                 search as a number or element (defaults to 10 || document.body)
6850          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6851          * @return {HTMLelement}
6852          */
6853         getTarget : function(selector, maxDepth, returnEl){
6854             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6855         },
6856         /**
6857          * Gets the related target.
6858          * @return {HTMLElement}
6859          */
6860         getRelatedTarget : function(){
6861             if(this.browserEvent){
6862                 return E.getRelatedTarget(this.browserEvent);
6863             }
6864             return null;
6865         },
6866
6867         /**
6868          * Normalizes mouse wheel delta across browsers
6869          * @return {Number} The delta
6870          */
6871         getWheelDelta : function(){
6872             var e = this.browserEvent;
6873             var delta = 0;
6874             if(e.wheelDelta){ /* IE/Opera. */
6875                 delta = e.wheelDelta/120;
6876             }else if(e.detail){ /* Mozilla case. */
6877                 delta = -e.detail/3;
6878             }
6879             return delta;
6880         },
6881
6882         /**
6883          * Returns true if the control, meta, shift or alt key was pressed during this event.
6884          * @return {Boolean}
6885          */
6886         hasModifier : function(){
6887             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6888         },
6889
6890         /**
6891          * Returns true if the target of this event equals el or is a child of el
6892          * @param {String/HTMLElement/Element} el
6893          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6894          * @return {Boolean}
6895          */
6896         within : function(el, related){
6897             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6898             return t && Roo.fly(el).contains(t);
6899         },
6900
6901         getPoint : function(){
6902             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6903         }
6904     };
6905
6906     return new Roo.EventObjectImpl();
6907 }();
6908             
6909     /*
6910  * Based on:
6911  * Ext JS Library 1.1.1
6912  * Copyright(c) 2006-2007, Ext JS, LLC.
6913  *
6914  * Originally Released Under LGPL - original licence link has changed is not relivant.
6915  *
6916  * Fork - LGPL
6917  * <script type="text/javascript">
6918  */
6919
6920  
6921 // was in Composite Element!??!?!
6922  
6923 (function(){
6924     var D = Roo.lib.Dom;
6925     var E = Roo.lib.Event;
6926     var A = Roo.lib.Anim;
6927
6928     // local style camelizing for speed
6929     var propCache = {};
6930     var camelRe = /(-[a-z])/gi;
6931     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6932     var view = document.defaultView;
6933
6934 /**
6935  * @class Roo.Element
6936  * Represents an Element in the DOM.<br><br>
6937  * Usage:<br>
6938 <pre><code>
6939 var el = Roo.get("my-div");
6940
6941 // or with getEl
6942 var el = getEl("my-div");
6943
6944 // or with a DOM element
6945 var el = Roo.get(myDivElement);
6946 </code></pre>
6947  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6948  * each call instead of constructing a new one.<br><br>
6949  * <b>Animations</b><br />
6950  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6951  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6952 <pre>
6953 Option    Default   Description
6954 --------- --------  ---------------------------------------------
6955 duration  .35       The duration of the animation in seconds
6956 easing    easeOut   The YUI easing method
6957 callback  none      A function to execute when the anim completes
6958 scope     this      The scope (this) of the callback function
6959 </pre>
6960 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6961 * manipulate the animation. Here's an example:
6962 <pre><code>
6963 var el = Roo.get("my-div");
6964
6965 // no animation
6966 el.setWidth(100);
6967
6968 // default animation
6969 el.setWidth(100, true);
6970
6971 // animation with some options set
6972 el.setWidth(100, {
6973     duration: 1,
6974     callback: this.foo,
6975     scope: this
6976 });
6977
6978 // using the "anim" property to get the Anim object
6979 var opt = {
6980     duration: 1,
6981     callback: this.foo,
6982     scope: this
6983 };
6984 el.setWidth(100, opt);
6985 ...
6986 if(opt.anim.isAnimated()){
6987     opt.anim.stop();
6988 }
6989 </code></pre>
6990 * <b> Composite (Collections of) Elements</b><br />
6991  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6992  * @constructor Create a new Element directly.
6993  * @param {String/HTMLElement} element
6994  * @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).
6995  */
6996     Roo.Element = function(element, forceNew){
6997         var dom = typeof element == "string" ?
6998                 document.getElementById(element) : element;
6999         if(!dom){ // invalid id/element
7000             return null;
7001         }
7002         var id = dom.id;
7003         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7004             return Roo.Element.cache[id];
7005         }
7006
7007         /**
7008          * The DOM element
7009          * @type HTMLElement
7010          */
7011         this.dom = dom;
7012
7013         /**
7014          * The DOM element ID
7015          * @type String
7016          */
7017         this.id = id || Roo.id(dom);
7018     };
7019
7020     var El = Roo.Element;
7021
7022     El.prototype = {
7023         /**
7024          * The element's default display mode  (defaults to "")
7025          * @type String
7026          */
7027         originalDisplay : "",
7028
7029         visibilityMode : 1,
7030         /**
7031          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7032          * @type String
7033          */
7034         defaultUnit : "px",
7035         /**
7036          * Sets the element's visibility mode. When setVisible() is called it
7037          * will use this to determine whether to set the visibility or the display property.
7038          * @param visMode Element.VISIBILITY or Element.DISPLAY
7039          * @return {Roo.Element} this
7040          */
7041         setVisibilityMode : function(visMode){
7042             this.visibilityMode = visMode;
7043             return this;
7044         },
7045         /**
7046          * Convenience method for setVisibilityMode(Element.DISPLAY)
7047          * @param {String} display (optional) What to set display to when visible
7048          * @return {Roo.Element} this
7049          */
7050         enableDisplayMode : function(display){
7051             this.setVisibilityMode(El.DISPLAY);
7052             if(typeof display != "undefined") this.originalDisplay = display;
7053             return this;
7054         },
7055
7056         /**
7057          * 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)
7058          * @param {String} selector The simple selector to test
7059          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7060                 search as a number or element (defaults to 10 || document.body)
7061          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7062          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7063          */
7064         findParent : function(simpleSelector, maxDepth, returnEl){
7065             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7066             maxDepth = maxDepth || 50;
7067             if(typeof maxDepth != "number"){
7068                 stopEl = Roo.getDom(maxDepth);
7069                 maxDepth = 10;
7070             }
7071             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7072                 if(dq.is(p, simpleSelector)){
7073                     return returnEl ? Roo.get(p) : p;
7074                 }
7075                 depth++;
7076                 p = p.parentNode;
7077             }
7078             return null;
7079         },
7080
7081
7082         /**
7083          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7084          * @param {String} selector The simple selector to test
7085          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7086                 search as a number or element (defaults to 10 || document.body)
7087          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7088          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7089          */
7090         findParentNode : function(simpleSelector, maxDepth, returnEl){
7091             var p = Roo.fly(this.dom.parentNode, '_internal');
7092             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7093         },
7094
7095         /**
7096          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7097          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7098          * @param {String} selector The simple selector to test
7099          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7100                 search as a number or element (defaults to 10 || document.body)
7101          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7102          */
7103         up : function(simpleSelector, maxDepth){
7104             return this.findParentNode(simpleSelector, maxDepth, true);
7105         },
7106
7107
7108
7109         /**
7110          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7111          * @param {String} selector The simple selector to test
7112          * @return {Boolean} True if this element matches the selector, else false
7113          */
7114         is : function(simpleSelector){
7115             return Roo.DomQuery.is(this.dom, simpleSelector);
7116         },
7117
7118         /**
7119          * Perform animation on this element.
7120          * @param {Object} args The YUI animation control args
7121          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7122          * @param {Function} onComplete (optional) Function to call when animation completes
7123          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7124          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7125          * @return {Roo.Element} this
7126          */
7127         animate : function(args, duration, onComplete, easing, animType){
7128             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7129             return this;
7130         },
7131
7132         /*
7133          * @private Internal animation call
7134          */
7135         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7136             animType = animType || 'run';
7137             opt = opt || {};
7138             var anim = Roo.lib.Anim[animType](
7139                 this.dom, args,
7140                 (opt.duration || defaultDur) || .35,
7141                 (opt.easing || defaultEase) || 'easeOut',
7142                 function(){
7143                     Roo.callback(cb, this);
7144                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7145                 },
7146                 this
7147             );
7148             opt.anim = anim;
7149             return anim;
7150         },
7151
7152         // private legacy anim prep
7153         preanim : function(a, i){
7154             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7155         },
7156
7157         /**
7158          * Removes worthless text nodes
7159          * @param {Boolean} forceReclean (optional) By default the element
7160          * keeps track if it has been cleaned already so
7161          * you can call this over and over. However, if you update the element and
7162          * need to force a reclean, you can pass true.
7163          */
7164         clean : function(forceReclean){
7165             if(this.isCleaned && forceReclean !== true){
7166                 return this;
7167             }
7168             var ns = /\S/;
7169             var d = this.dom, n = d.firstChild, ni = -1;
7170             while(n){
7171                 var nx = n.nextSibling;
7172                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7173                     d.removeChild(n);
7174                 }else{
7175                     n.nodeIndex = ++ni;
7176                 }
7177                 n = nx;
7178             }
7179             this.isCleaned = true;
7180             return this;
7181         },
7182
7183         // private
7184         calcOffsetsTo : function(el){
7185             el = Roo.get(el);
7186             var d = el.dom;
7187             var restorePos = false;
7188             if(el.getStyle('position') == 'static'){
7189                 el.position('relative');
7190                 restorePos = true;
7191             }
7192             var x = 0, y =0;
7193             var op = this.dom;
7194             while(op && op != d && op.tagName != 'HTML'){
7195                 x+= op.offsetLeft;
7196                 y+= op.offsetTop;
7197                 op = op.offsetParent;
7198             }
7199             if(restorePos){
7200                 el.position('static');
7201             }
7202             return [x, y];
7203         },
7204
7205         /**
7206          * Scrolls this element into view within the passed container.
7207          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7208          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7209          * @return {Roo.Element} this
7210          */
7211         scrollIntoView : function(container, hscroll){
7212             var c = Roo.getDom(container) || document.body;
7213             var el = this.dom;
7214
7215             var o = this.calcOffsetsTo(c),
7216                 l = o[0],
7217                 t = o[1],
7218                 b = t+el.offsetHeight,
7219                 r = l+el.offsetWidth;
7220
7221             var ch = c.clientHeight;
7222             var ct = parseInt(c.scrollTop, 10);
7223             var cl = parseInt(c.scrollLeft, 10);
7224             var cb = ct + ch;
7225             var cr = cl + c.clientWidth;
7226
7227             if(t < ct){
7228                 c.scrollTop = t;
7229             }else if(b > cb){
7230                 c.scrollTop = b-ch;
7231             }
7232
7233             if(hscroll !== false){
7234                 if(l < cl){
7235                     c.scrollLeft = l;
7236                 }else if(r > cr){
7237                     c.scrollLeft = r-c.clientWidth;
7238                 }
7239             }
7240             return this;
7241         },
7242
7243         // private
7244         scrollChildIntoView : function(child, hscroll){
7245             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7246         },
7247
7248         /**
7249          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7250          * the new height may not be available immediately.
7251          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7252          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7253          * @param {Function} onComplete (optional) Function to call when animation completes
7254          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7255          * @return {Roo.Element} this
7256          */
7257         autoHeight : function(animate, duration, onComplete, easing){
7258             var oldHeight = this.getHeight();
7259             this.clip();
7260             this.setHeight(1); // force clipping
7261             setTimeout(function(){
7262                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7263                 if(!animate){
7264                     this.setHeight(height);
7265                     this.unclip();
7266                     if(typeof onComplete == "function"){
7267                         onComplete();
7268                     }
7269                 }else{
7270                     this.setHeight(oldHeight); // restore original height
7271                     this.setHeight(height, animate, duration, function(){
7272                         this.unclip();
7273                         if(typeof onComplete == "function") onComplete();
7274                     }.createDelegate(this), easing);
7275                 }
7276             }.createDelegate(this), 0);
7277             return this;
7278         },
7279
7280         /**
7281          * Returns true if this element is an ancestor of the passed element
7282          * @param {HTMLElement/String} el The element to check
7283          * @return {Boolean} True if this element is an ancestor of el, else false
7284          */
7285         contains : function(el){
7286             if(!el){return false;}
7287             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7288         },
7289
7290         /**
7291          * Checks whether the element is currently visible using both visibility and display properties.
7292          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7293          * @return {Boolean} True if the element is currently visible, else false
7294          */
7295         isVisible : function(deep) {
7296             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7297             if(deep !== true || !vis){
7298                 return vis;
7299             }
7300             var p = this.dom.parentNode;
7301             while(p && p.tagName.toLowerCase() != "body"){
7302                 if(!Roo.fly(p, '_isVisible').isVisible()){
7303                     return false;
7304                 }
7305                 p = p.parentNode;
7306             }
7307             return true;
7308         },
7309
7310         /**
7311          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7312          * @param {String} selector The CSS selector
7313          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7314          * @return {CompositeElement/CompositeElementLite} The composite element
7315          */
7316         select : function(selector, unique){
7317             return El.select(selector, unique, this.dom);
7318         },
7319
7320         /**
7321          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7322          * @param {String} selector The CSS selector
7323          * @return {Array} An array of the matched nodes
7324          */
7325         query : function(selector, unique){
7326             return Roo.DomQuery.select(selector, this.dom);
7327         },
7328
7329         /**
7330          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7331          * @param {String} selector The CSS selector
7332          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7333          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7334          */
7335         child : function(selector, returnDom){
7336             var n = Roo.DomQuery.selectNode(selector, this.dom);
7337             return returnDom ? n : Roo.get(n);
7338         },
7339
7340         /**
7341          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7342          * @param {String} selector The CSS selector
7343          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7344          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7345          */
7346         down : function(selector, returnDom){
7347             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7348             return returnDom ? n : Roo.get(n);
7349         },
7350
7351         /**
7352          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7353          * @param {String} group The group the DD object is member of
7354          * @param {Object} config The DD config object
7355          * @param {Object} overrides An object containing methods to override/implement on the DD object
7356          * @return {Roo.dd.DD} The DD object
7357          */
7358         initDD : function(group, config, overrides){
7359             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7360             return Roo.apply(dd, overrides);
7361         },
7362
7363         /**
7364          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7365          * @param {String} group The group the DDProxy object is member of
7366          * @param {Object} config The DDProxy config object
7367          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7368          * @return {Roo.dd.DDProxy} The DDProxy object
7369          */
7370         initDDProxy : function(group, config, overrides){
7371             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7372             return Roo.apply(dd, overrides);
7373         },
7374
7375         /**
7376          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7377          * @param {String} group The group the DDTarget object is member of
7378          * @param {Object} config The DDTarget config object
7379          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7380          * @return {Roo.dd.DDTarget} The DDTarget object
7381          */
7382         initDDTarget : function(group, config, overrides){
7383             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7384             return Roo.apply(dd, overrides);
7385         },
7386
7387         /**
7388          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7389          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7390          * @param {Boolean} visible Whether the element is visible
7391          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7392          * @return {Roo.Element} this
7393          */
7394          setVisible : function(visible, animate){
7395             if(!animate || !A){
7396                 if(this.visibilityMode == El.DISPLAY){
7397                     this.setDisplayed(visible);
7398                 }else{
7399                     this.fixDisplay();
7400                     this.dom.style.visibility = visible ? "visible" : "hidden";
7401                 }
7402             }else{
7403                 // closure for composites
7404                 var dom = this.dom;
7405                 var visMode = this.visibilityMode;
7406                 if(visible){
7407                     this.setOpacity(.01);
7408                     this.setVisible(true);
7409                 }
7410                 this.anim({opacity: { to: (visible?1:0) }},
7411                       this.preanim(arguments, 1),
7412                       null, .35, 'easeIn', function(){
7413                          if(!visible){
7414                              if(visMode == El.DISPLAY){
7415                                  dom.style.display = "none";
7416                              }else{
7417                                  dom.style.visibility = "hidden";
7418                              }
7419                              Roo.get(dom).setOpacity(1);
7420                          }
7421                      });
7422             }
7423             return this;
7424         },
7425
7426         /**
7427          * Returns true if display is not "none"
7428          * @return {Boolean}
7429          */
7430         isDisplayed : function() {
7431             return this.getStyle("display") != "none";
7432         },
7433
7434         /**
7435          * Toggles the element's visibility or display, depending on visibility mode.
7436          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7437          * @return {Roo.Element} this
7438          */
7439         toggle : function(animate){
7440             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7441             return this;
7442         },
7443
7444         /**
7445          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7446          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7447          * @return {Roo.Element} this
7448          */
7449         setDisplayed : function(value) {
7450             if(typeof value == "boolean"){
7451                value = value ? this.originalDisplay : "none";
7452             }
7453             this.setStyle("display", value);
7454             return this;
7455         },
7456
7457         /**
7458          * Tries to focus the element. Any exceptions are caught and ignored.
7459          * @return {Roo.Element} this
7460          */
7461         focus : function() {
7462             try{
7463                 this.dom.focus();
7464             }catch(e){}
7465             return this;
7466         },
7467
7468         /**
7469          * Tries to blur the element. Any exceptions are caught and ignored.
7470          * @return {Roo.Element} this
7471          */
7472         blur : function() {
7473             try{
7474                 this.dom.blur();
7475             }catch(e){}
7476             return this;
7477         },
7478
7479         /**
7480          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7481          * @param {String/Array} className The CSS class to add, or an array of classes
7482          * @return {Roo.Element} this
7483          */
7484         addClass : function(className){
7485             if(className instanceof Array){
7486                 for(var i = 0, len = className.length; i < len; i++) {
7487                     this.addClass(className[i]);
7488                 }
7489             }else{
7490                 if(className && !this.hasClass(className)){
7491                     this.dom.className = this.dom.className + " " + className;
7492                 }
7493             }
7494             return this;
7495         },
7496
7497         /**
7498          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7499          * @param {String/Array} className The CSS class to add, or an array of classes
7500          * @return {Roo.Element} this
7501          */
7502         radioClass : function(className){
7503             var siblings = this.dom.parentNode.childNodes;
7504             for(var i = 0; i < siblings.length; i++) {
7505                 var s = siblings[i];
7506                 if(s.nodeType == 1){
7507                     Roo.get(s).removeClass(className);
7508                 }
7509             }
7510             this.addClass(className);
7511             return this;
7512         },
7513
7514         /**
7515          * Removes one or more CSS classes from the element.
7516          * @param {String/Array} className The CSS class to remove, or an array of classes
7517          * @return {Roo.Element} this
7518          */
7519         removeClass : function(className){
7520             if(!className || !this.dom.className){
7521                 return this;
7522             }
7523             if(className instanceof Array){
7524                 for(var i = 0, len = className.length; i < len; i++) {
7525                     this.removeClass(className[i]);
7526                 }
7527             }else{
7528                 if(this.hasClass(className)){
7529                     var re = this.classReCache[className];
7530                     if (!re) {
7531                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7532                        this.classReCache[className] = re;
7533                     }
7534                     this.dom.className =
7535                         this.dom.className.replace(re, " ");
7536                 }
7537             }
7538             return this;
7539         },
7540
7541         // private
7542         classReCache: {},
7543
7544         /**
7545          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7546          * @param {String} className The CSS class to toggle
7547          * @return {Roo.Element} this
7548          */
7549         toggleClass : function(className){
7550             if(this.hasClass(className)){
7551                 this.removeClass(className);
7552             }else{
7553                 this.addClass(className);
7554             }
7555             return this;
7556         },
7557
7558         /**
7559          * Checks if the specified CSS class exists on this element's DOM node.
7560          * @param {String} className The CSS class to check for
7561          * @return {Boolean} True if the class exists, else false
7562          */
7563         hasClass : function(className){
7564             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7565         },
7566
7567         /**
7568          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7569          * @param {String} oldClassName The CSS class to replace
7570          * @param {String} newClassName The replacement CSS class
7571          * @return {Roo.Element} this
7572          */
7573         replaceClass : function(oldClassName, newClassName){
7574             this.removeClass(oldClassName);
7575             this.addClass(newClassName);
7576             return this;
7577         },
7578
7579         /**
7580          * Returns an object with properties matching the styles requested.
7581          * For example, el.getStyles('color', 'font-size', 'width') might return
7582          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7583          * @param {String} style1 A style name
7584          * @param {String} style2 A style name
7585          * @param {String} etc.
7586          * @return {Object} The style object
7587          */
7588         getStyles : function(){
7589             var a = arguments, len = a.length, r = {};
7590             for(var i = 0; i < len; i++){
7591                 r[a[i]] = this.getStyle(a[i]);
7592             }
7593             return r;
7594         },
7595
7596         /**
7597          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7598          * @param {String} property The style property whose value is returned.
7599          * @return {String} The current value of the style property for this element.
7600          */
7601         getStyle : function(){
7602             return view && view.getComputedStyle ?
7603                 function(prop){
7604                     var el = this.dom, v, cs, camel;
7605                     if(prop == 'float'){
7606                         prop = "cssFloat";
7607                     }
7608                     if(el.style && (v = el.style[prop])){
7609                         return v;
7610                     }
7611                     if(cs = view.getComputedStyle(el, "")){
7612                         if(!(camel = propCache[prop])){
7613                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7614                         }
7615                         return cs[camel];
7616                     }
7617                     return null;
7618                 } :
7619                 function(prop){
7620                     var el = this.dom, v, cs, camel;
7621                     if(prop == 'opacity'){
7622                         if(typeof el.style.filter == 'string'){
7623                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7624                             if(m){
7625                                 var fv = parseFloat(m[1]);
7626                                 if(!isNaN(fv)){
7627                                     return fv ? fv / 100 : 0;
7628                                 }
7629                             }
7630                         }
7631                         return 1;
7632                     }else if(prop == 'float'){
7633                         prop = "styleFloat";
7634                     }
7635                     if(!(camel = propCache[prop])){
7636                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7637                     }
7638                     if(v = el.style[camel]){
7639                         return v;
7640                     }
7641                     if(cs = el.currentStyle){
7642                         return cs[camel];
7643                     }
7644                     return null;
7645                 };
7646         }(),
7647
7648         /**
7649          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7650          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7651          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7652          * @return {Roo.Element} this
7653          */
7654         setStyle : function(prop, value){
7655             if(typeof prop == "string"){
7656                 
7657                 if (prop == 'float') {
7658                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7659                     return this;
7660                 }
7661                 
7662                 var camel;
7663                 if(!(camel = propCache[prop])){
7664                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7665                 }
7666                 
7667                 if(camel == 'opacity') {
7668                     this.setOpacity(value);
7669                 }else{
7670                     this.dom.style[camel] = value;
7671                 }
7672             }else{
7673                 for(var style in prop){
7674                     if(typeof prop[style] != "function"){
7675                        this.setStyle(style, prop[style]);
7676                     }
7677                 }
7678             }
7679             return this;
7680         },
7681
7682         /**
7683          * More flexible version of {@link #setStyle} for setting style properties.
7684          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7685          * a function which returns such a specification.
7686          * @return {Roo.Element} this
7687          */
7688         applyStyles : function(style){
7689             Roo.DomHelper.applyStyles(this.dom, style);
7690             return this;
7691         },
7692
7693         /**
7694           * 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).
7695           * @return {Number} The X position of the element
7696           */
7697         getX : function(){
7698             return D.getX(this.dom);
7699         },
7700
7701         /**
7702           * 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).
7703           * @return {Number} The Y position of the element
7704           */
7705         getY : function(){
7706             return D.getY(this.dom);
7707         },
7708
7709         /**
7710           * 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).
7711           * @return {Array} The XY position of the element
7712           */
7713         getXY : function(){
7714             return D.getXY(this.dom);
7715         },
7716
7717         /**
7718          * 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).
7719          * @param {Number} The X position of the element
7720          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7721          * @return {Roo.Element} this
7722          */
7723         setX : function(x, animate){
7724             if(!animate || !A){
7725                 D.setX(this.dom, x);
7726             }else{
7727                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7728             }
7729             return this;
7730         },
7731
7732         /**
7733          * 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).
7734          * @param {Number} The Y position of the element
7735          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7736          * @return {Roo.Element} this
7737          */
7738         setY : function(y, animate){
7739             if(!animate || !A){
7740                 D.setY(this.dom, y);
7741             }else{
7742                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7743             }
7744             return this;
7745         },
7746
7747         /**
7748          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7749          * @param {String} left The left CSS property value
7750          * @return {Roo.Element} this
7751          */
7752         setLeft : function(left){
7753             this.setStyle("left", this.addUnits(left));
7754             return this;
7755         },
7756
7757         /**
7758          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7759          * @param {String} top The top CSS property value
7760          * @return {Roo.Element} this
7761          */
7762         setTop : function(top){
7763             this.setStyle("top", this.addUnits(top));
7764             return this;
7765         },
7766
7767         /**
7768          * Sets the element's CSS right style.
7769          * @param {String} right The right CSS property value
7770          * @return {Roo.Element} this
7771          */
7772         setRight : function(right){
7773             this.setStyle("right", this.addUnits(right));
7774             return this;
7775         },
7776
7777         /**
7778          * Sets the element's CSS bottom style.
7779          * @param {String} bottom The bottom CSS property value
7780          * @return {Roo.Element} this
7781          */
7782         setBottom : function(bottom){
7783             this.setStyle("bottom", this.addUnits(bottom));
7784             return this;
7785         },
7786
7787         /**
7788          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7789          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7790          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7791          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7792          * @return {Roo.Element} this
7793          */
7794         setXY : function(pos, animate){
7795             if(!animate || !A){
7796                 D.setXY(this.dom, pos);
7797             }else{
7798                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7799             }
7800             return this;
7801         },
7802
7803         /**
7804          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7805          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7806          * @param {Number} x X value for new position (coordinates are page-based)
7807          * @param {Number} y Y value for new position (coordinates are page-based)
7808          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7809          * @return {Roo.Element} this
7810          */
7811         setLocation : function(x, y, animate){
7812             this.setXY([x, y], this.preanim(arguments, 2));
7813             return this;
7814         },
7815
7816         /**
7817          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7818          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7819          * @param {Number} x X value for new position (coordinates are page-based)
7820          * @param {Number} y Y value for new position (coordinates are page-based)
7821          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7822          * @return {Roo.Element} this
7823          */
7824         moveTo : function(x, y, animate){
7825             this.setXY([x, y], this.preanim(arguments, 2));
7826             return this;
7827         },
7828
7829         /**
7830          * Returns the region of the given element.
7831          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7832          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7833          */
7834         getRegion : function(){
7835             return D.getRegion(this.dom);
7836         },
7837
7838         /**
7839          * Returns the offset height of the element
7840          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7841          * @return {Number} The element's height
7842          */
7843         getHeight : function(contentHeight){
7844             var h = this.dom.offsetHeight || 0;
7845             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7846         },
7847
7848         /**
7849          * Returns the offset width of the element
7850          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7851          * @return {Number} The element's width
7852          */
7853         getWidth : function(contentWidth){
7854             var w = this.dom.offsetWidth || 0;
7855             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7856         },
7857
7858         /**
7859          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7860          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7861          * if a height has not been set using CSS.
7862          * @return {Number}
7863          */
7864         getComputedHeight : function(){
7865             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7866             if(!h){
7867                 h = parseInt(this.getStyle('height'), 10) || 0;
7868                 if(!this.isBorderBox()){
7869                     h += this.getFrameWidth('tb');
7870                 }
7871             }
7872             return h;
7873         },
7874
7875         /**
7876          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7877          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7878          * if a width has not been set using CSS.
7879          * @return {Number}
7880          */
7881         getComputedWidth : function(){
7882             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7883             if(!w){
7884                 w = parseInt(this.getStyle('width'), 10) || 0;
7885                 if(!this.isBorderBox()){
7886                     w += this.getFrameWidth('lr');
7887                 }
7888             }
7889             return w;
7890         },
7891
7892         /**
7893          * Returns the size of the element.
7894          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7895          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7896          */
7897         getSize : function(contentSize){
7898             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7899         },
7900
7901         /**
7902          * Returns the width and height of the viewport.
7903          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7904          */
7905         getViewSize : function(){
7906             var d = this.dom, doc = document, aw = 0, ah = 0;
7907             if(d == doc || d == doc.body){
7908                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7909             }else{
7910                 return {
7911                     width : d.clientWidth,
7912                     height: d.clientHeight
7913                 };
7914             }
7915         },
7916
7917         /**
7918          * Returns the value of the "value" attribute
7919          * @param {Boolean} asNumber true to parse the value as a number
7920          * @return {String/Number}
7921          */
7922         getValue : function(asNumber){
7923             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7924         },
7925
7926         // private
7927         adjustWidth : function(width){
7928             if(typeof width == "number"){
7929                 if(this.autoBoxAdjust && !this.isBorderBox()){
7930                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7931                 }
7932                 if(width < 0){
7933                     width = 0;
7934                 }
7935             }
7936             return width;
7937         },
7938
7939         // private
7940         adjustHeight : function(height){
7941             if(typeof height == "number"){
7942                if(this.autoBoxAdjust && !this.isBorderBox()){
7943                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7944                }
7945                if(height < 0){
7946                    height = 0;
7947                }
7948             }
7949             return height;
7950         },
7951
7952         /**
7953          * Set the width of the element
7954          * @param {Number} width The new width
7955          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7956          * @return {Roo.Element} this
7957          */
7958         setWidth : function(width, animate){
7959             width = this.adjustWidth(width);
7960             if(!animate || !A){
7961                 this.dom.style.width = this.addUnits(width);
7962             }else{
7963                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7964             }
7965             return this;
7966         },
7967
7968         /**
7969          * Set the height of the element
7970          * @param {Number} height The new height
7971          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7972          * @return {Roo.Element} this
7973          */
7974          setHeight : function(height, animate){
7975             height = this.adjustHeight(height);
7976             if(!animate || !A){
7977                 this.dom.style.height = this.addUnits(height);
7978             }else{
7979                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7980             }
7981             return this;
7982         },
7983
7984         /**
7985          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7986          * @param {Number} width The new width
7987          * @param {Number} height The new height
7988          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7989          * @return {Roo.Element} this
7990          */
7991          setSize : function(width, height, animate){
7992             if(typeof width == "object"){ // in case of object from getSize()
7993                 height = width.height; width = width.width;
7994             }
7995             width = this.adjustWidth(width); height = this.adjustHeight(height);
7996             if(!animate || !A){
7997                 this.dom.style.width = this.addUnits(width);
7998                 this.dom.style.height = this.addUnits(height);
7999             }else{
8000                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8001             }
8002             return this;
8003         },
8004
8005         /**
8006          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8007          * @param {Number} x X value for new position (coordinates are page-based)
8008          * @param {Number} y Y value for new position (coordinates are page-based)
8009          * @param {Number} width The new width
8010          * @param {Number} height The new height
8011          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8012          * @return {Roo.Element} this
8013          */
8014         setBounds : function(x, y, width, height, animate){
8015             if(!animate || !A){
8016                 this.setSize(width, height);
8017                 this.setLocation(x, y);
8018             }else{
8019                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8020                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8021                               this.preanim(arguments, 4), 'motion');
8022             }
8023             return this;
8024         },
8025
8026         /**
8027          * 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.
8028          * @param {Roo.lib.Region} region The region to fill
8029          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8030          * @return {Roo.Element} this
8031          */
8032         setRegion : function(region, animate){
8033             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8034             return this;
8035         },
8036
8037         /**
8038          * Appends an event handler
8039          *
8040          * @param {String}   eventName     The type of event to append
8041          * @param {Function} fn        The method the event invokes
8042          * @param {Object} scope       (optional) The scope (this object) of the fn
8043          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8044          */
8045         addListener : function(eventName, fn, scope, options){
8046             if (this.dom) {
8047                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8048             }
8049         },
8050
8051         /**
8052          * Removes an event handler from this element
8053          * @param {String} eventName the type of event to remove
8054          * @param {Function} fn the method the event invokes
8055          * @return {Roo.Element} this
8056          */
8057         removeListener : function(eventName, fn){
8058             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8059             return this;
8060         },
8061
8062         /**
8063          * Removes all previous added listeners from this element
8064          * @return {Roo.Element} this
8065          */
8066         removeAllListeners : function(){
8067             E.purgeElement(this.dom);
8068             return this;
8069         },
8070
8071         relayEvent : function(eventName, observable){
8072             this.on(eventName, function(e){
8073                 observable.fireEvent(eventName, e);
8074             });
8075         },
8076
8077         /**
8078          * Set the opacity of the element
8079          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8080          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8081          * @return {Roo.Element} this
8082          */
8083          setOpacity : function(opacity, animate){
8084             if(!animate || !A){
8085                 var s = this.dom.style;
8086                 if(Roo.isIE){
8087                     s.zoom = 1;
8088                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8089                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8090                 }else{
8091                     s.opacity = opacity;
8092                 }
8093             }else{
8094                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8095             }
8096             return this;
8097         },
8098
8099         /**
8100          * Gets the left X coordinate
8101          * @param {Boolean} local True to get the local css position instead of page coordinate
8102          * @return {Number}
8103          */
8104         getLeft : function(local){
8105             if(!local){
8106                 return this.getX();
8107             }else{
8108                 return parseInt(this.getStyle("left"), 10) || 0;
8109             }
8110         },
8111
8112         /**
8113          * Gets the right X coordinate of the element (element X position + element width)
8114          * @param {Boolean} local True to get the local css position instead of page coordinate
8115          * @return {Number}
8116          */
8117         getRight : function(local){
8118             if(!local){
8119                 return this.getX() + this.getWidth();
8120             }else{
8121                 return (this.getLeft(true) + this.getWidth()) || 0;
8122             }
8123         },
8124
8125         /**
8126          * Gets the top Y coordinate
8127          * @param {Boolean} local True to get the local css position instead of page coordinate
8128          * @return {Number}
8129          */
8130         getTop : function(local) {
8131             if(!local){
8132                 return this.getY();
8133             }else{
8134                 return parseInt(this.getStyle("top"), 10) || 0;
8135             }
8136         },
8137
8138         /**
8139          * Gets the bottom Y coordinate of the element (element Y position + element height)
8140          * @param {Boolean} local True to get the local css position instead of page coordinate
8141          * @return {Number}
8142          */
8143         getBottom : function(local){
8144             if(!local){
8145                 return this.getY() + this.getHeight();
8146             }else{
8147                 return (this.getTop(true) + this.getHeight()) || 0;
8148             }
8149         },
8150
8151         /**
8152         * Initializes positioning on this element. If a desired position is not passed, it will make the
8153         * the element positioned relative IF it is not already positioned.
8154         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8155         * @param {Number} zIndex (optional) The zIndex to apply
8156         * @param {Number} x (optional) Set the page X position
8157         * @param {Number} y (optional) Set the page Y position
8158         */
8159         position : function(pos, zIndex, x, y){
8160             if(!pos){
8161                if(this.getStyle('position') == 'static'){
8162                    this.setStyle('position', 'relative');
8163                }
8164             }else{
8165                 this.setStyle("position", pos);
8166             }
8167             if(zIndex){
8168                 this.setStyle("z-index", zIndex);
8169             }
8170             if(x !== undefined && y !== undefined){
8171                 this.setXY([x, y]);
8172             }else if(x !== undefined){
8173                 this.setX(x);
8174             }else if(y !== undefined){
8175                 this.setY(y);
8176             }
8177         },
8178
8179         /**
8180         * Clear positioning back to the default when the document was loaded
8181         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8182         * @return {Roo.Element} this
8183          */
8184         clearPositioning : function(value){
8185             value = value ||'';
8186             this.setStyle({
8187                 "left": value,
8188                 "right": value,
8189                 "top": value,
8190                 "bottom": value,
8191                 "z-index": "",
8192                 "position" : "static"
8193             });
8194             return this;
8195         },
8196
8197         /**
8198         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8199         * snapshot before performing an update and then restoring the element.
8200         * @return {Object}
8201         */
8202         getPositioning : function(){
8203             var l = this.getStyle("left");
8204             var t = this.getStyle("top");
8205             return {
8206                 "position" : this.getStyle("position"),
8207                 "left" : l,
8208                 "right" : l ? "" : this.getStyle("right"),
8209                 "top" : t,
8210                 "bottom" : t ? "" : this.getStyle("bottom"),
8211                 "z-index" : this.getStyle("z-index")
8212             };
8213         },
8214
8215         /**
8216          * Gets the width of the border(s) for the specified side(s)
8217          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8218          * passing lr would get the border (l)eft width + the border (r)ight width.
8219          * @return {Number} The width of the sides passed added together
8220          */
8221         getBorderWidth : function(side){
8222             return this.addStyles(side, El.borders);
8223         },
8224
8225         /**
8226          * Gets the width of the padding(s) for the specified side(s)
8227          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8228          * passing lr would get the padding (l)eft + the padding (r)ight.
8229          * @return {Number} The padding of the sides passed added together
8230          */
8231         getPadding : function(side){
8232             return this.addStyles(side, El.paddings);
8233         },
8234
8235         /**
8236         * Set positioning with an object returned by getPositioning().
8237         * @param {Object} posCfg
8238         * @return {Roo.Element} this
8239          */
8240         setPositioning : function(pc){
8241             this.applyStyles(pc);
8242             if(pc.right == "auto"){
8243                 this.dom.style.right = "";
8244             }
8245             if(pc.bottom == "auto"){
8246                 this.dom.style.bottom = "";
8247             }
8248             return this;
8249         },
8250
8251         // private
8252         fixDisplay : function(){
8253             if(this.getStyle("display") == "none"){
8254                 this.setStyle("visibility", "hidden");
8255                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8256                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8257                     this.setStyle("display", "block");
8258                 }
8259             }
8260         },
8261
8262         /**
8263          * Quick set left and top adding default units
8264          * @param {String} left The left CSS property value
8265          * @param {String} top The top CSS property value
8266          * @return {Roo.Element} this
8267          */
8268          setLeftTop : function(left, top){
8269             this.dom.style.left = this.addUnits(left);
8270             this.dom.style.top = this.addUnits(top);
8271             return this;
8272         },
8273
8274         /**
8275          * Move this element relative to its current position.
8276          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8277          * @param {Number} distance How far to move the element in pixels
8278          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8279          * @return {Roo.Element} this
8280          */
8281          move : function(direction, distance, animate){
8282             var xy = this.getXY();
8283             direction = direction.toLowerCase();
8284             switch(direction){
8285                 case "l":
8286                 case "left":
8287                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8288                     break;
8289                case "r":
8290                case "right":
8291                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8292                     break;
8293                case "t":
8294                case "top":
8295                case "up":
8296                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8297                     break;
8298                case "b":
8299                case "bottom":
8300                case "down":
8301                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8302                     break;
8303             }
8304             return this;
8305         },
8306
8307         /**
8308          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8309          * @return {Roo.Element} this
8310          */
8311         clip : function(){
8312             if(!this.isClipped){
8313                this.isClipped = true;
8314                this.originalClip = {
8315                    "o": this.getStyle("overflow"),
8316                    "x": this.getStyle("overflow-x"),
8317                    "y": this.getStyle("overflow-y")
8318                };
8319                this.setStyle("overflow", "hidden");
8320                this.setStyle("overflow-x", "hidden");
8321                this.setStyle("overflow-y", "hidden");
8322             }
8323             return this;
8324         },
8325
8326         /**
8327          *  Return clipping (overflow) to original clipping before clip() was called
8328          * @return {Roo.Element} this
8329          */
8330         unclip : function(){
8331             if(this.isClipped){
8332                 this.isClipped = false;
8333                 var o = this.originalClip;
8334                 if(o.o){this.setStyle("overflow", o.o);}
8335                 if(o.x){this.setStyle("overflow-x", o.x);}
8336                 if(o.y){this.setStyle("overflow-y", o.y);}
8337             }
8338             return this;
8339         },
8340
8341
8342         /**
8343          * Gets the x,y coordinates specified by the anchor position on the element.
8344          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8345          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8346          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8347          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8348          * @return {Array} [x, y] An array containing the element's x and y coordinates
8349          */
8350         getAnchorXY : function(anchor, local, s){
8351             //Passing a different size is useful for pre-calculating anchors,
8352             //especially for anchored animations that change the el size.
8353
8354             var w, h, vp = false;
8355             if(!s){
8356                 var d = this.dom;
8357                 if(d == document.body || d == document){
8358                     vp = true;
8359                     w = D.getViewWidth(); h = D.getViewHeight();
8360                 }else{
8361                     w = this.getWidth(); h = this.getHeight();
8362                 }
8363             }else{
8364                 w = s.width;  h = s.height;
8365             }
8366             var x = 0, y = 0, r = Math.round;
8367             switch((anchor || "tl").toLowerCase()){
8368                 case "c":
8369                     x = r(w*.5);
8370                     y = r(h*.5);
8371                 break;
8372                 case "t":
8373                     x = r(w*.5);
8374                     y = 0;
8375                 break;
8376                 case "l":
8377                     x = 0;
8378                     y = r(h*.5);
8379                 break;
8380                 case "r":
8381                     x = w;
8382                     y = r(h*.5);
8383                 break;
8384                 case "b":
8385                     x = r(w*.5);
8386                     y = h;
8387                 break;
8388                 case "tl":
8389                     x = 0;
8390                     y = 0;
8391                 break;
8392                 case "bl":
8393                     x = 0;
8394                     y = h;
8395                 break;
8396                 case "br":
8397                     x = w;
8398                     y = h;
8399                 break;
8400                 case "tr":
8401                     x = w;
8402                     y = 0;
8403                 break;
8404             }
8405             if(local === true){
8406                 return [x, y];
8407             }
8408             if(vp){
8409                 var sc = this.getScroll();
8410                 return [x + sc.left, y + sc.top];
8411             }
8412             //Add the element's offset xy
8413             var o = this.getXY();
8414             return [x+o[0], y+o[1]];
8415         },
8416
8417         /**
8418          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8419          * supported position values.
8420          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8421          * @param {String} position The position to align to.
8422          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8423          * @return {Array} [x, y]
8424          */
8425         getAlignToXY : function(el, p, o){
8426             el = Roo.get(el);
8427             var d = this.dom;
8428             if(!el.dom){
8429                 throw "Element.alignTo with an element that doesn't exist";
8430             }
8431             var c = false; //constrain to viewport
8432             var p1 = "", p2 = "";
8433             o = o || [0,0];
8434
8435             if(!p){
8436                 p = "tl-bl";
8437             }else if(p == "?"){
8438                 p = "tl-bl?";
8439             }else if(p.indexOf("-") == -1){
8440                 p = "tl-" + p;
8441             }
8442             p = p.toLowerCase();
8443             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8444             if(!m){
8445                throw "Element.alignTo with an invalid alignment " + p;
8446             }
8447             p1 = m[1]; p2 = m[2]; c = !!m[3];
8448
8449             //Subtract the aligned el's internal xy from the target's offset xy
8450             //plus custom offset to get the aligned el's new offset xy
8451             var a1 = this.getAnchorXY(p1, true);
8452             var a2 = el.getAnchorXY(p2, false);
8453             var x = a2[0] - a1[0] + o[0];
8454             var y = a2[1] - a1[1] + o[1];
8455             if(c){
8456                 //constrain the aligned el to viewport if necessary
8457                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8458                 // 5px of margin for ie
8459                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8460
8461                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8462                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8463                 //otherwise swap the aligned el to the opposite border of the target.
8464                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8465                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8466                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8467                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8468
8469                var doc = document;
8470                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8471                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8472
8473                if((x+w) > dw + scrollX){
8474                     x = swapX ? r.left-w : dw+scrollX-w;
8475                 }
8476                if(x < scrollX){
8477                    x = swapX ? r.right : scrollX;
8478                }
8479                if((y+h) > dh + scrollY){
8480                     y = swapY ? r.top-h : dh+scrollY-h;
8481                 }
8482                if (y < scrollY){
8483                    y = swapY ? r.bottom : scrollY;
8484                }
8485             }
8486             return [x,y];
8487         },
8488
8489         // private
8490         getConstrainToXY : function(){
8491             var os = {top:0, left:0, bottom:0, right: 0};
8492
8493             return function(el, local, offsets, proposedXY){
8494                 el = Roo.get(el);
8495                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8496
8497                 var vw, vh, vx = 0, vy = 0;
8498                 if(el.dom == document.body || el.dom == document){
8499                     vw = Roo.lib.Dom.getViewWidth();
8500                     vh = Roo.lib.Dom.getViewHeight();
8501                 }else{
8502                     vw = el.dom.clientWidth;
8503                     vh = el.dom.clientHeight;
8504                     if(!local){
8505                         var vxy = el.getXY();
8506                         vx = vxy[0];
8507                         vy = vxy[1];
8508                     }
8509                 }
8510
8511                 var s = el.getScroll();
8512
8513                 vx += offsets.left + s.left;
8514                 vy += offsets.top + s.top;
8515
8516                 vw -= offsets.right;
8517                 vh -= offsets.bottom;
8518
8519                 var vr = vx+vw;
8520                 var vb = vy+vh;
8521
8522                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8523                 var x = xy[0], y = xy[1];
8524                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8525
8526                 // only move it if it needs it
8527                 var moved = false;
8528
8529                 // first validate right/bottom
8530                 if((x + w) > vr){
8531                     x = vr - w;
8532                     moved = true;
8533                 }
8534                 if((y + h) > vb){
8535                     y = vb - h;
8536                     moved = true;
8537                 }
8538                 // then make sure top/left isn't negative
8539                 if(x < vx){
8540                     x = vx;
8541                     moved = true;
8542                 }
8543                 if(y < vy){
8544                     y = vy;
8545                     moved = true;
8546                 }
8547                 return moved ? [x, y] : false;
8548             };
8549         }(),
8550
8551         // private
8552         adjustForConstraints : function(xy, parent, offsets){
8553             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8554         },
8555
8556         /**
8557          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8558          * document it aligns it to the viewport.
8559          * The position parameter is optional, and can be specified in any one of the following formats:
8560          * <ul>
8561          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8562          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8563          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8564          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8565          *   <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
8566          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8567          * </ul>
8568          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8569          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8570          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8571          * that specified in order to enforce the viewport constraints.
8572          * Following are all of the supported anchor positions:
8573     <pre>
8574     Value  Description
8575     -----  -----------------------------
8576     tl     The top left corner (default)
8577     t      The center of the top edge
8578     tr     The top right corner
8579     l      The center of the left edge
8580     c      In the center of the element
8581     r      The center of the right edge
8582     bl     The bottom left corner
8583     b      The center of the bottom edge
8584     br     The bottom right corner
8585     </pre>
8586     Example Usage:
8587     <pre><code>
8588     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8589     el.alignTo("other-el");
8590
8591     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8592     el.alignTo("other-el", "tr?");
8593
8594     // align the bottom right corner of el with the center left edge of other-el
8595     el.alignTo("other-el", "br-l?");
8596
8597     // align the center of el with the bottom left corner of other-el and
8598     // adjust the x position by -6 pixels (and the y position by 0)
8599     el.alignTo("other-el", "c-bl", [-6, 0]);
8600     </code></pre>
8601          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8602          * @param {String} position The position to align to.
8603          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8604          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8605          * @return {Roo.Element} this
8606          */
8607         alignTo : function(element, position, offsets, animate){
8608             var xy = this.getAlignToXY(element, position, offsets);
8609             this.setXY(xy, this.preanim(arguments, 3));
8610             return this;
8611         },
8612
8613         /**
8614          * Anchors an element to another element and realigns it when the window is resized.
8615          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8616          * @param {String} position The position to align to.
8617          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8618          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8619          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8620          * is a number, it is used as the buffer delay (defaults to 50ms).
8621          * @param {Function} callback The function to call after the animation finishes
8622          * @return {Roo.Element} this
8623          */
8624         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8625             var action = function(){
8626                 this.alignTo(el, alignment, offsets, animate);
8627                 Roo.callback(callback, this);
8628             };
8629             Roo.EventManager.onWindowResize(action, this);
8630             var tm = typeof monitorScroll;
8631             if(tm != 'undefined'){
8632                 Roo.EventManager.on(window, 'scroll', action, this,
8633                     {buffer: tm == 'number' ? monitorScroll : 50});
8634             }
8635             action.call(this); // align immediately
8636             return this;
8637         },
8638         /**
8639          * Clears any opacity settings from this element. Required in some cases for IE.
8640          * @return {Roo.Element} this
8641          */
8642         clearOpacity : function(){
8643             if (window.ActiveXObject) {
8644                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8645                     this.dom.style.filter = "";
8646                 }
8647             } else {
8648                 this.dom.style.opacity = "";
8649                 this.dom.style["-moz-opacity"] = "";
8650                 this.dom.style["-khtml-opacity"] = "";
8651             }
8652             return this;
8653         },
8654
8655         /**
8656          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8657          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8658          * @return {Roo.Element} this
8659          */
8660         hide : function(animate){
8661             this.setVisible(false, this.preanim(arguments, 0));
8662             return this;
8663         },
8664
8665         /**
8666         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8667         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8668          * @return {Roo.Element} this
8669          */
8670         show : function(animate){
8671             this.setVisible(true, this.preanim(arguments, 0));
8672             return this;
8673         },
8674
8675         /**
8676          * @private Test if size has a unit, otherwise appends the default
8677          */
8678         addUnits : function(size){
8679             return Roo.Element.addUnits(size, this.defaultUnit);
8680         },
8681
8682         /**
8683          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8684          * @return {Roo.Element} this
8685          */
8686         beginMeasure : function(){
8687             var el = this.dom;
8688             if(el.offsetWidth || el.offsetHeight){
8689                 return this; // offsets work already
8690             }
8691             var changed = [];
8692             var p = this.dom, b = document.body; // start with this element
8693             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8694                 var pe = Roo.get(p);
8695                 if(pe.getStyle('display') == 'none'){
8696                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8697                     p.style.visibility = "hidden";
8698                     p.style.display = "block";
8699                 }
8700                 p = p.parentNode;
8701             }
8702             this._measureChanged = changed;
8703             return this;
8704
8705         },
8706
8707         /**
8708          * Restores displays to before beginMeasure was called
8709          * @return {Roo.Element} this
8710          */
8711         endMeasure : function(){
8712             var changed = this._measureChanged;
8713             if(changed){
8714                 for(var i = 0, len = changed.length; i < len; i++) {
8715                     var r = changed[i];
8716                     r.el.style.visibility = r.visibility;
8717                     r.el.style.display = "none";
8718                 }
8719                 this._measureChanged = null;
8720             }
8721             return this;
8722         },
8723
8724         /**
8725         * Update the innerHTML of this element, optionally searching for and processing scripts
8726         * @param {String} html The new HTML
8727         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8728         * @param {Function} callback For async script loading you can be noticed when the update completes
8729         * @return {Roo.Element} this
8730          */
8731         update : function(html, loadScripts, callback){
8732             if(typeof html == "undefined"){
8733                 html = "";
8734             }
8735             if(loadScripts !== true){
8736                 this.dom.innerHTML = html;
8737                 if(typeof callback == "function"){
8738                     callback();
8739                 }
8740                 return this;
8741             }
8742             var id = Roo.id();
8743             var dom = this.dom;
8744
8745             html += '<span id="' + id + '"></span>';
8746
8747             E.onAvailable(id, function(){
8748                 var hd = document.getElementsByTagName("head")[0];
8749                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8750                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8751                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8752
8753                 var match;
8754                 while(match = re.exec(html)){
8755                     var attrs = match[1];
8756                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8757                     if(srcMatch && srcMatch[2]){
8758                        var s = document.createElement("script");
8759                        s.src = srcMatch[2];
8760                        var typeMatch = attrs.match(typeRe);
8761                        if(typeMatch && typeMatch[2]){
8762                            s.type = typeMatch[2];
8763                        }
8764                        hd.appendChild(s);
8765                     }else if(match[2] && match[2].length > 0){
8766                         if(window.execScript) {
8767                            window.execScript(match[2]);
8768                         } else {
8769                             /**
8770                              * eval:var:id
8771                              * eval:var:dom
8772                              * eval:var:html
8773                              * 
8774                              */
8775                            window.eval(match[2]);
8776                         }
8777                     }
8778                 }
8779                 var el = document.getElementById(id);
8780                 if(el){el.parentNode.removeChild(el);}
8781                 if(typeof callback == "function"){
8782                     callback();
8783                 }
8784             });
8785             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8786             return this;
8787         },
8788
8789         /**
8790          * Direct access to the UpdateManager update() method (takes the same parameters).
8791          * @param {String/Function} url The url for this request or a function to call to get the url
8792          * @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}
8793          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8794          * @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.
8795          * @return {Roo.Element} this
8796          */
8797         load : function(){
8798             var um = this.getUpdateManager();
8799             um.update.apply(um, arguments);
8800             return this;
8801         },
8802
8803         /**
8804         * Gets this element's UpdateManager
8805         * @return {Roo.UpdateManager} The UpdateManager
8806         */
8807         getUpdateManager : function(){
8808             if(!this.updateManager){
8809                 this.updateManager = new Roo.UpdateManager(this);
8810             }
8811             return this.updateManager;
8812         },
8813
8814         /**
8815          * Disables text selection for this element (normalized across browsers)
8816          * @return {Roo.Element} this
8817          */
8818         unselectable : function(){
8819             this.dom.unselectable = "on";
8820             this.swallowEvent("selectstart", true);
8821             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8822             this.addClass("x-unselectable");
8823             return this;
8824         },
8825
8826         /**
8827         * Calculates the x, y to center this element on the screen
8828         * @return {Array} The x, y values [x, y]
8829         */
8830         getCenterXY : function(){
8831             return this.getAlignToXY(document, 'c-c');
8832         },
8833
8834         /**
8835         * Centers the Element in either the viewport, or another Element.
8836         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8837         */
8838         center : function(centerIn){
8839             this.alignTo(centerIn || document, 'c-c');
8840             return this;
8841         },
8842
8843         /**
8844          * Tests various css rules/browsers to determine if this element uses a border box
8845          * @return {Boolean}
8846          */
8847         isBorderBox : function(){
8848             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8849         },
8850
8851         /**
8852          * Return a box {x, y, width, height} that can be used to set another elements
8853          * size/location to match this element.
8854          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8855          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8856          * @return {Object} box An object in the format {x, y, width, height}
8857          */
8858         getBox : function(contentBox, local){
8859             var xy;
8860             if(!local){
8861                 xy = this.getXY();
8862             }else{
8863                 var left = parseInt(this.getStyle("left"), 10) || 0;
8864                 var top = parseInt(this.getStyle("top"), 10) || 0;
8865                 xy = [left, top];
8866             }
8867             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8868             if(!contentBox){
8869                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8870             }else{
8871                 var l = this.getBorderWidth("l")+this.getPadding("l");
8872                 var r = this.getBorderWidth("r")+this.getPadding("r");
8873                 var t = this.getBorderWidth("t")+this.getPadding("t");
8874                 var b = this.getBorderWidth("b")+this.getPadding("b");
8875                 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)};
8876             }
8877             bx.right = bx.x + bx.width;
8878             bx.bottom = bx.y + bx.height;
8879             return bx;
8880         },
8881
8882         /**
8883          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8884          for more information about the sides.
8885          * @param {String} sides
8886          * @return {Number}
8887          */
8888         getFrameWidth : function(sides, onlyContentBox){
8889             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8890         },
8891
8892         /**
8893          * 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.
8894          * @param {Object} box The box to fill {x, y, width, height}
8895          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8896          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8897          * @return {Roo.Element} this
8898          */
8899         setBox : function(box, adjust, animate){
8900             var w = box.width, h = box.height;
8901             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8902                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8903                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8904             }
8905             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8906             return this;
8907         },
8908
8909         /**
8910          * Forces the browser to repaint this element
8911          * @return {Roo.Element} this
8912          */
8913          repaint : function(){
8914             var dom = this.dom;
8915             this.addClass("x-repaint");
8916             setTimeout(function(){
8917                 Roo.get(dom).removeClass("x-repaint");
8918             }, 1);
8919             return this;
8920         },
8921
8922         /**
8923          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8924          * then it returns the calculated width of the sides (see getPadding)
8925          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8926          * @return {Object/Number}
8927          */
8928         getMargins : function(side){
8929             if(!side){
8930                 return {
8931                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8932                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8933                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8934                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8935                 };
8936             }else{
8937                 return this.addStyles(side, El.margins);
8938              }
8939         },
8940
8941         // private
8942         addStyles : function(sides, styles){
8943             var val = 0, v, w;
8944             for(var i = 0, len = sides.length; i < len; i++){
8945                 v = this.getStyle(styles[sides.charAt(i)]);
8946                 if(v){
8947                      w = parseInt(v, 10);
8948                      if(w){ val += w; }
8949                 }
8950             }
8951             return val;
8952         },
8953
8954         /**
8955          * Creates a proxy element of this element
8956          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8957          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8958          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8959          * @return {Roo.Element} The new proxy element
8960          */
8961         createProxy : function(config, renderTo, matchBox){
8962             if(renderTo){
8963                 renderTo = Roo.getDom(renderTo);
8964             }else{
8965                 renderTo = document.body;
8966             }
8967             config = typeof config == "object" ?
8968                 config : {tag : "div", cls: config};
8969             var proxy = Roo.DomHelper.append(renderTo, config, true);
8970             if(matchBox){
8971                proxy.setBox(this.getBox());
8972             }
8973             return proxy;
8974         },
8975
8976         /**
8977          * Puts a mask over this element to disable user interaction. Requires core.css.
8978          * This method can only be applied to elements which accept child nodes.
8979          * @param {String} msg (optional) A message to display in the mask
8980          * @param {String} msgCls (optional) A css class to apply to the msg element
8981          * @return {Element} The mask  element
8982          */
8983         mask : function(msg, msgCls)
8984         {
8985             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8986                 this.setStyle("position", "relative");
8987             }
8988             if(!this._mask){
8989                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8990             }
8991             this.addClass("x-masked");
8992             this._mask.setDisplayed(true);
8993             
8994             // we wander
8995             var z = 0;
8996             var dom = this.dom
8997             while (dom && dom.style) {
8998                 if (!isNaN(parseInt(dom.style.zIndex))) {
8999                     z = Math.max(z, parseInt(dom.style.zIndex));
9000                 }
9001                 dom = dom.parentNode;
9002             }
9003             // if we are masking the body - then it hides everything..
9004             if (this.dom == document.body) {
9005                 z = 1000000;
9006                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9007                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9008             }
9009            
9010             if(typeof msg == 'string'){
9011                 if(!this._maskMsg){
9012                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9013                 }
9014                 var mm = this._maskMsg;
9015                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9016                 if (mm.dom.firstChild) { // weird IE issue?
9017                     mm.dom.firstChild.innerHTML = msg;
9018                 }
9019                 mm.setDisplayed(true);
9020                 mm.center(this);
9021                 mm.setStyle('z-index', z + 102);
9022             }
9023             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9024                 this._mask.setHeight(this.getHeight());
9025             }
9026             this._mask.setStyle('z-index', z + 100);
9027             
9028             return this._mask;
9029         },
9030
9031         /**
9032          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9033          * it is cached for reuse.
9034          */
9035         unmask : function(removeEl){
9036             if(this._mask){
9037                 if(removeEl === true){
9038                     this._mask.remove();
9039                     delete this._mask;
9040                     if(this._maskMsg){
9041                         this._maskMsg.remove();
9042                         delete this._maskMsg;
9043                     }
9044                 }else{
9045                     this._mask.setDisplayed(false);
9046                     if(this._maskMsg){
9047                         this._maskMsg.setDisplayed(false);
9048                     }
9049                 }
9050             }
9051             this.removeClass("x-masked");
9052         },
9053
9054         /**
9055          * Returns true if this element is masked
9056          * @return {Boolean}
9057          */
9058         isMasked : function(){
9059             return this._mask && this._mask.isVisible();
9060         },
9061
9062         /**
9063          * Creates an iframe shim for this element to keep selects and other windowed objects from
9064          * showing through.
9065          * @return {Roo.Element} The new shim element
9066          */
9067         createShim : function(){
9068             var el = document.createElement('iframe');
9069             el.frameBorder = 'no';
9070             el.className = 'roo-shim';
9071             if(Roo.isIE && Roo.isSecure){
9072                 el.src = Roo.SSL_SECURE_URL;
9073             }
9074             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9075             shim.autoBoxAdjust = false;
9076             return shim;
9077         },
9078
9079         /**
9080          * Removes this element from the DOM and deletes it from the cache
9081          */
9082         remove : function(){
9083             if(this.dom.parentNode){
9084                 this.dom.parentNode.removeChild(this.dom);
9085             }
9086             delete El.cache[this.dom.id];
9087         },
9088
9089         /**
9090          * Sets up event handlers to add and remove a css class when the mouse is over this element
9091          * @param {String} className
9092          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9093          * mouseout events for children elements
9094          * @return {Roo.Element} this
9095          */
9096         addClassOnOver : function(className, preventFlicker){
9097             this.on("mouseover", function(){
9098                 Roo.fly(this, '_internal').addClass(className);
9099             }, this.dom);
9100             var removeFn = function(e){
9101                 if(preventFlicker !== true || !e.within(this, true)){
9102                     Roo.fly(this, '_internal').removeClass(className);
9103                 }
9104             };
9105             this.on("mouseout", removeFn, this.dom);
9106             return this;
9107         },
9108
9109         /**
9110          * Sets up event handlers to add and remove a css class when this element has the focus
9111          * @param {String} className
9112          * @return {Roo.Element} this
9113          */
9114         addClassOnFocus : function(className){
9115             this.on("focus", function(){
9116                 Roo.fly(this, '_internal').addClass(className);
9117             }, this.dom);
9118             this.on("blur", function(){
9119                 Roo.fly(this, '_internal').removeClass(className);
9120             }, this.dom);
9121             return this;
9122         },
9123         /**
9124          * 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)
9125          * @param {String} className
9126          * @return {Roo.Element} this
9127          */
9128         addClassOnClick : function(className){
9129             var dom = this.dom;
9130             this.on("mousedown", function(){
9131                 Roo.fly(dom, '_internal').addClass(className);
9132                 var d = Roo.get(document);
9133                 var fn = function(){
9134                     Roo.fly(dom, '_internal').removeClass(className);
9135                     d.removeListener("mouseup", fn);
9136                 };
9137                 d.on("mouseup", fn);
9138             });
9139             return this;
9140         },
9141
9142         /**
9143          * Stops the specified event from bubbling and optionally prevents the default action
9144          * @param {String} eventName
9145          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9146          * @return {Roo.Element} this
9147          */
9148         swallowEvent : function(eventName, preventDefault){
9149             var fn = function(e){
9150                 e.stopPropagation();
9151                 if(preventDefault){
9152                     e.preventDefault();
9153                 }
9154             };
9155             if(eventName instanceof Array){
9156                 for(var i = 0, len = eventName.length; i < len; i++){
9157                      this.on(eventName[i], fn);
9158                 }
9159                 return this;
9160             }
9161             this.on(eventName, fn);
9162             return this;
9163         },
9164
9165         /**
9166          * @private
9167          */
9168       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9169
9170         /**
9171          * Sizes this element to its parent element's dimensions performing
9172          * neccessary box adjustments.
9173          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9174          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9175          * @return {Roo.Element} this
9176          */
9177         fitToParent : function(monitorResize, targetParent) {
9178           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9179           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9180           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9181             return;
9182           }
9183           var p = Roo.get(targetParent || this.dom.parentNode);
9184           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9185           if (monitorResize === true) {
9186             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9187             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9188           }
9189           return this;
9190         },
9191
9192         /**
9193          * Gets the next sibling, skipping text nodes
9194          * @return {HTMLElement} The next sibling or null
9195          */
9196         getNextSibling : function(){
9197             var n = this.dom.nextSibling;
9198             while(n && n.nodeType != 1){
9199                 n = n.nextSibling;
9200             }
9201             return n;
9202         },
9203
9204         /**
9205          * Gets the previous sibling, skipping text nodes
9206          * @return {HTMLElement} The previous sibling or null
9207          */
9208         getPrevSibling : function(){
9209             var n = this.dom.previousSibling;
9210             while(n && n.nodeType != 1){
9211                 n = n.previousSibling;
9212             }
9213             return n;
9214         },
9215
9216
9217         /**
9218          * Appends the passed element(s) to this element
9219          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9220          * @return {Roo.Element} this
9221          */
9222         appendChild: function(el){
9223             el = Roo.get(el);
9224             el.appendTo(this);
9225             return this;
9226         },
9227
9228         /**
9229          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9230          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9231          * automatically generated with the specified attributes.
9232          * @param {HTMLElement} insertBefore (optional) a child element of this element
9233          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9234          * @return {Roo.Element} The new child element
9235          */
9236         createChild: function(config, insertBefore, returnDom){
9237             config = config || {tag:'div'};
9238             if(insertBefore){
9239                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9240             }
9241             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9242         },
9243
9244         /**
9245          * Appends this element to the passed element
9246          * @param {String/HTMLElement/Element} el The new parent element
9247          * @return {Roo.Element} this
9248          */
9249         appendTo: function(el){
9250             el = Roo.getDom(el);
9251             el.appendChild(this.dom);
9252             return this;
9253         },
9254
9255         /**
9256          * Inserts this element before the passed element in the DOM
9257          * @param {String/HTMLElement/Element} el The element to insert before
9258          * @return {Roo.Element} this
9259          */
9260         insertBefore: function(el){
9261             el = Roo.getDom(el);
9262             el.parentNode.insertBefore(this.dom, el);
9263             return this;
9264         },
9265
9266         /**
9267          * Inserts this element after the passed element in the DOM
9268          * @param {String/HTMLElement/Element} el The element to insert after
9269          * @return {Roo.Element} this
9270          */
9271         insertAfter: function(el){
9272             el = Roo.getDom(el);
9273             el.parentNode.insertBefore(this.dom, el.nextSibling);
9274             return this;
9275         },
9276
9277         /**
9278          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9279          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9280          * @return {Roo.Element} The new child
9281          */
9282         insertFirst: function(el, returnDom){
9283             el = el || {};
9284             if(typeof el == 'object' && !el.nodeType){ // dh config
9285                 return this.createChild(el, this.dom.firstChild, returnDom);
9286             }else{
9287                 el = Roo.getDom(el);
9288                 this.dom.insertBefore(el, this.dom.firstChild);
9289                 return !returnDom ? Roo.get(el) : el;
9290             }
9291         },
9292
9293         /**
9294          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9295          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9296          * @param {String} where (optional) 'before' or 'after' defaults to before
9297          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9298          * @return {Roo.Element} the inserted Element
9299          */
9300         insertSibling: function(el, where, returnDom){
9301             where = where ? where.toLowerCase() : 'before';
9302             el = el || {};
9303             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9304
9305             if(typeof el == 'object' && !el.nodeType){ // dh config
9306                 if(where == 'after' && !this.dom.nextSibling){
9307                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9308                 }else{
9309                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9310                 }
9311
9312             }else{
9313                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9314                             where == 'before' ? this.dom : this.dom.nextSibling);
9315                 if(!returnDom){
9316                     rt = Roo.get(rt);
9317                 }
9318             }
9319             return rt;
9320         },
9321
9322         /**
9323          * Creates and wraps this element with another element
9324          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9325          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9326          * @return {HTMLElement/Element} The newly created wrapper element
9327          */
9328         wrap: function(config, returnDom){
9329             if(!config){
9330                 config = {tag: "div"};
9331             }
9332             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9333             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9334             return newEl;
9335         },
9336
9337         /**
9338          * Replaces the passed element with this element
9339          * @param {String/HTMLElement/Element} el The element to replace
9340          * @return {Roo.Element} this
9341          */
9342         replace: function(el){
9343             el = Roo.get(el);
9344             this.insertBefore(el);
9345             el.remove();
9346             return this;
9347         },
9348
9349         /**
9350          * Inserts an html fragment into this element
9351          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9352          * @param {String} html The HTML fragment
9353          * @param {Boolean} returnEl True to return an Roo.Element
9354          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9355          */
9356         insertHtml : function(where, html, returnEl){
9357             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9358             return returnEl ? Roo.get(el) : el;
9359         },
9360
9361         /**
9362          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9363          * @param {Object} o The object with the attributes
9364          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9365          * @return {Roo.Element} this
9366          */
9367         set : function(o, useSet){
9368             var el = this.dom;
9369             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9370             for(var attr in o){
9371                 if(attr == "style" || typeof o[attr] == "function") continue;
9372                 if(attr=="cls"){
9373                     el.className = o["cls"];
9374                 }else{
9375                     if(useSet) el.setAttribute(attr, o[attr]);
9376                     else el[attr] = o[attr];
9377                 }
9378             }
9379             if(o.style){
9380                 Roo.DomHelper.applyStyles(el, o.style);
9381             }
9382             return this;
9383         },
9384
9385         /**
9386          * Convenience method for constructing a KeyMap
9387          * @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:
9388          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9389          * @param {Function} fn The function to call
9390          * @param {Object} scope (optional) The scope of the function
9391          * @return {Roo.KeyMap} The KeyMap created
9392          */
9393         addKeyListener : function(key, fn, scope){
9394             var config;
9395             if(typeof key != "object" || key instanceof Array){
9396                 config = {
9397                     key: key,
9398                     fn: fn,
9399                     scope: scope
9400                 };
9401             }else{
9402                 config = {
9403                     key : key.key,
9404                     shift : key.shift,
9405                     ctrl : key.ctrl,
9406                     alt : key.alt,
9407                     fn: fn,
9408                     scope: scope
9409                 };
9410             }
9411             return new Roo.KeyMap(this, config);
9412         },
9413
9414         /**
9415          * Creates a KeyMap for this element
9416          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9417          * @return {Roo.KeyMap} The KeyMap created
9418          */
9419         addKeyMap : function(config){
9420             return new Roo.KeyMap(this, config);
9421         },
9422
9423         /**
9424          * Returns true if this element is scrollable.
9425          * @return {Boolean}
9426          */
9427          isScrollable : function(){
9428             var dom = this.dom;
9429             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9430         },
9431
9432         /**
9433          * 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().
9434          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9435          * @param {Number} value The new scroll value
9436          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9437          * @return {Element} this
9438          */
9439
9440         scrollTo : function(side, value, animate){
9441             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9442             if(!animate || !A){
9443                 this.dom[prop] = value;
9444             }else{
9445                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9446                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9447             }
9448             return this;
9449         },
9450
9451         /**
9452          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9453          * within this element's scrollable range.
9454          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9455          * @param {Number} distance How far to scroll the element in pixels
9456          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9457          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9458          * was scrolled as far as it could go.
9459          */
9460          scroll : function(direction, distance, animate){
9461              if(!this.isScrollable()){
9462                  return;
9463              }
9464              var el = this.dom;
9465              var l = el.scrollLeft, t = el.scrollTop;
9466              var w = el.scrollWidth, h = el.scrollHeight;
9467              var cw = el.clientWidth, ch = el.clientHeight;
9468              direction = direction.toLowerCase();
9469              var scrolled = false;
9470              var a = this.preanim(arguments, 2);
9471              switch(direction){
9472                  case "l":
9473                  case "left":
9474                      if(w - l > cw){
9475                          var v = Math.min(l + distance, w-cw);
9476                          this.scrollTo("left", v, a);
9477                          scrolled = true;
9478                      }
9479                      break;
9480                 case "r":
9481                 case "right":
9482                      if(l > 0){
9483                          var v = Math.max(l - distance, 0);
9484                          this.scrollTo("left", v, a);
9485                          scrolled = true;
9486                      }
9487                      break;
9488                 case "t":
9489                 case "top":
9490                 case "up":
9491                      if(t > 0){
9492                          var v = Math.max(t - distance, 0);
9493                          this.scrollTo("top", v, a);
9494                          scrolled = true;
9495                      }
9496                      break;
9497                 case "b":
9498                 case "bottom":
9499                 case "down":
9500                      if(h - t > ch){
9501                          var v = Math.min(t + distance, h-ch);
9502                          this.scrollTo("top", v, a);
9503                          scrolled = true;
9504                      }
9505                      break;
9506              }
9507              return scrolled;
9508         },
9509
9510         /**
9511          * Translates the passed page coordinates into left/top css values for this element
9512          * @param {Number/Array} x The page x or an array containing [x, y]
9513          * @param {Number} y The page y
9514          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9515          */
9516         translatePoints : function(x, y){
9517             if(typeof x == 'object' || x instanceof Array){
9518                 y = x[1]; x = x[0];
9519             }
9520             var p = this.getStyle('position');
9521             var o = this.getXY();
9522
9523             var l = parseInt(this.getStyle('left'), 10);
9524             var t = parseInt(this.getStyle('top'), 10);
9525
9526             if(isNaN(l)){
9527                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9528             }
9529             if(isNaN(t)){
9530                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9531             }
9532
9533             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9534         },
9535
9536         /**
9537          * Returns the current scroll position of the element.
9538          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9539          */
9540         getScroll : function(){
9541             var d = this.dom, doc = document;
9542             if(d == doc || d == doc.body){
9543                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9544                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9545                 return {left: l, top: t};
9546             }else{
9547                 return {left: d.scrollLeft, top: d.scrollTop};
9548             }
9549         },
9550
9551         /**
9552          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9553          * are convert to standard 6 digit hex color.
9554          * @param {String} attr The css attribute
9555          * @param {String} defaultValue The default value to use when a valid color isn't found
9556          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9557          * YUI color anims.
9558          */
9559         getColor : function(attr, defaultValue, prefix){
9560             var v = this.getStyle(attr);
9561             if(!v || v == "transparent" || v == "inherit") {
9562                 return defaultValue;
9563             }
9564             var color = typeof prefix == "undefined" ? "#" : prefix;
9565             if(v.substr(0, 4) == "rgb("){
9566                 var rvs = v.slice(4, v.length -1).split(",");
9567                 for(var i = 0; i < 3; i++){
9568                     var h = parseInt(rvs[i]).toString(16);
9569                     if(h < 16){
9570                         h = "0" + h;
9571                     }
9572                     color += h;
9573                 }
9574             } else {
9575                 if(v.substr(0, 1) == "#"){
9576                     if(v.length == 4) {
9577                         for(var i = 1; i < 4; i++){
9578                             var c = v.charAt(i);
9579                             color +=  c + c;
9580                         }
9581                     }else if(v.length == 7){
9582                         color += v.substr(1);
9583                     }
9584                 }
9585             }
9586             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9587         },
9588
9589         /**
9590          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9591          * gradient background, rounded corners and a 4-way shadow.
9592          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9593          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9594          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9595          * @return {Roo.Element} this
9596          */
9597         boxWrap : function(cls){
9598             cls = cls || 'x-box';
9599             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9600             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9601             return el;
9602         },
9603
9604         /**
9605          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9606          * @param {String} namespace The namespace in which to look for the attribute
9607          * @param {String} name The attribute name
9608          * @return {String} The attribute value
9609          */
9610         getAttributeNS : Roo.isIE ? function(ns, name){
9611             var d = this.dom;
9612             var type = typeof d[ns+":"+name];
9613             if(type != 'undefined' && type != 'unknown'){
9614                 return d[ns+":"+name];
9615             }
9616             return d[name];
9617         } : function(ns, name){
9618             var d = this.dom;
9619             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9620         },
9621         
9622         
9623         /**
9624          * Sets or Returns the value the dom attribute value
9625          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9626          * @param {String} value (optional) The value to set the attribute to
9627          * @return {String} The attribute value
9628          */
9629         attr : function(name){
9630             if (arguments.length > 1) {
9631                 this.dom.setAttribute(name, arguments[1]);
9632                 return arguments[1];
9633             }
9634             if (typeof(name) == 'object') {
9635                 for(var i in name) {
9636                     this.attr(i, name[i]);
9637                 }
9638                 return name;
9639             }
9640             
9641             
9642             if (!this.dom.hasAttribute(name)) {
9643                 return undefined;
9644             }
9645             return this.dom.getAttribute(name);
9646         }
9647         
9648         
9649         
9650     };
9651
9652     var ep = El.prototype;
9653
9654     /**
9655      * Appends an event handler (Shorthand for addListener)
9656      * @param {String}   eventName     The type of event to append
9657      * @param {Function} fn        The method the event invokes
9658      * @param {Object} scope       (optional) The scope (this object) of the fn
9659      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9660      * @method
9661      */
9662     ep.on = ep.addListener;
9663         // backwards compat
9664     ep.mon = ep.addListener;
9665
9666     /**
9667      * Removes an event handler from this element (shorthand for removeListener)
9668      * @param {String} eventName the type of event to remove
9669      * @param {Function} fn the method the event invokes
9670      * @return {Roo.Element} this
9671      * @method
9672      */
9673     ep.un = ep.removeListener;
9674
9675     /**
9676      * true to automatically adjust width and height settings for box-model issues (default to true)
9677      */
9678     ep.autoBoxAdjust = true;
9679
9680     // private
9681     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9682
9683     // private
9684     El.addUnits = function(v, defaultUnit){
9685         if(v === "" || v == "auto"){
9686             return v;
9687         }
9688         if(v === undefined){
9689             return '';
9690         }
9691         if(typeof v == "number" || !El.unitPattern.test(v)){
9692             return v + (defaultUnit || 'px');
9693         }
9694         return v;
9695     };
9696
9697     // special markup used throughout Roo when box wrapping elements
9698     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>';
9699     /**
9700      * Visibility mode constant - Use visibility to hide element
9701      * @static
9702      * @type Number
9703      */
9704     El.VISIBILITY = 1;
9705     /**
9706      * Visibility mode constant - Use display to hide element
9707      * @static
9708      * @type Number
9709      */
9710     El.DISPLAY = 2;
9711
9712     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9713     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9714     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9715
9716
9717
9718     /**
9719      * @private
9720      */
9721     El.cache = {};
9722
9723     var docEl;
9724
9725     /**
9726      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9727      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9728      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9729      * @return {Element} The Element object
9730      * @static
9731      */
9732     El.get = function(el){
9733         var ex, elm, id;
9734         if(!el){ return null; }
9735         if(typeof el == "string"){ // element id
9736             if(!(elm = document.getElementById(el))){
9737                 return null;
9738             }
9739             if(ex = El.cache[el]){
9740                 ex.dom = elm;
9741             }else{
9742                 ex = El.cache[el] = new El(elm);
9743             }
9744             return ex;
9745         }else if(el.tagName){ // dom element
9746             if(!(id = el.id)){
9747                 id = Roo.id(el);
9748             }
9749             if(ex = El.cache[id]){
9750                 ex.dom = el;
9751             }else{
9752                 ex = El.cache[id] = new El(el);
9753             }
9754             return ex;
9755         }else if(el instanceof El){
9756             if(el != docEl){
9757                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9758                                                               // catch case where it hasn't been appended
9759                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9760             }
9761             return el;
9762         }else if(el.isComposite){
9763             return el;
9764         }else if(el instanceof Array){
9765             return El.select(el);
9766         }else if(el == document){
9767             // create a bogus element object representing the document object
9768             if(!docEl){
9769                 var f = function(){};
9770                 f.prototype = El.prototype;
9771                 docEl = new f();
9772                 docEl.dom = document;
9773             }
9774             return docEl;
9775         }
9776         return null;
9777     };
9778
9779     // private
9780     El.uncache = function(el){
9781         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9782             if(a[i]){
9783                 delete El.cache[a[i].id || a[i]];
9784             }
9785         }
9786     };
9787
9788     // private
9789     // Garbage collection - uncache elements/purge listeners on orphaned elements
9790     // so we don't hold a reference and cause the browser to retain them
9791     El.garbageCollect = function(){
9792         if(!Roo.enableGarbageCollector){
9793             clearInterval(El.collectorThread);
9794             return;
9795         }
9796         for(var eid in El.cache){
9797             var el = El.cache[eid], d = el.dom;
9798             // -------------------------------------------------------
9799             // Determining what is garbage:
9800             // -------------------------------------------------------
9801             // !d
9802             // dom node is null, definitely garbage
9803             // -------------------------------------------------------
9804             // !d.parentNode
9805             // no parentNode == direct orphan, definitely garbage
9806             // -------------------------------------------------------
9807             // !d.offsetParent && !document.getElementById(eid)
9808             // display none elements have no offsetParent so we will
9809             // also try to look it up by it's id. However, check
9810             // offsetParent first so we don't do unneeded lookups.
9811             // This enables collection of elements that are not orphans
9812             // directly, but somewhere up the line they have an orphan
9813             // parent.
9814             // -------------------------------------------------------
9815             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9816                 delete El.cache[eid];
9817                 if(d && Roo.enableListenerCollection){
9818                     E.purgeElement(d);
9819                 }
9820             }
9821         }
9822     }
9823     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9824
9825
9826     // dom is optional
9827     El.Flyweight = function(dom){
9828         this.dom = dom;
9829     };
9830     El.Flyweight.prototype = El.prototype;
9831
9832     El._flyweights = {};
9833     /**
9834      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9835      * the dom node can be overwritten by other code.
9836      * @param {String/HTMLElement} el The dom node or id
9837      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9838      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9839      * @static
9840      * @return {Element} The shared Element object
9841      */
9842     El.fly = function(el, named){
9843         named = named || '_global';
9844         el = Roo.getDom(el);
9845         if(!el){
9846             return null;
9847         }
9848         if(!El._flyweights[named]){
9849             El._flyweights[named] = new El.Flyweight();
9850         }
9851         El._flyweights[named].dom = el;
9852         return El._flyweights[named];
9853     };
9854
9855     /**
9856      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9857      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9858      * Shorthand of {@link Roo.Element#get}
9859      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9860      * @return {Element} The Element object
9861      * @member Roo
9862      * @method get
9863      */
9864     Roo.get = El.get;
9865     /**
9866      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9867      * the dom node can be overwritten by other code.
9868      * Shorthand of {@link Roo.Element#fly}
9869      * @param {String/HTMLElement} el The dom node or id
9870      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9871      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9872      * @static
9873      * @return {Element} The shared Element object
9874      * @member Roo
9875      * @method fly
9876      */
9877     Roo.fly = El.fly;
9878
9879     // speedy lookup for elements never to box adjust
9880     var noBoxAdjust = Roo.isStrict ? {
9881         select:1
9882     } : {
9883         input:1, select:1, textarea:1
9884     };
9885     if(Roo.isIE || Roo.isGecko){
9886         noBoxAdjust['button'] = 1;
9887     }
9888
9889
9890     Roo.EventManager.on(window, 'unload', function(){
9891         delete El.cache;
9892         delete El._flyweights;
9893     });
9894 })();
9895
9896
9897
9898
9899 if(Roo.DomQuery){
9900     Roo.Element.selectorFunction = Roo.DomQuery.select;
9901 }
9902
9903 Roo.Element.select = function(selector, unique, root){
9904     var els;
9905     if(typeof selector == "string"){
9906         els = Roo.Element.selectorFunction(selector, root);
9907     }else if(selector.length !== undefined){
9908         els = selector;
9909     }else{
9910         throw "Invalid selector";
9911     }
9912     if(unique === true){
9913         return new Roo.CompositeElement(els);
9914     }else{
9915         return new Roo.CompositeElementLite(els);
9916     }
9917 };
9918 /**
9919  * Selects elements based on the passed CSS selector to enable working on them as 1.
9920  * @param {String/Array} selector The CSS selector or an array of elements
9921  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9922  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9923  * @return {CompositeElementLite/CompositeElement}
9924  * @member Roo
9925  * @method select
9926  */
9927 Roo.select = Roo.Element.select;
9928
9929
9930
9931
9932
9933
9934
9935
9936
9937
9938
9939
9940
9941
9942 /*
9943  * Based on:
9944  * Ext JS Library 1.1.1
9945  * Copyright(c) 2006-2007, Ext JS, LLC.
9946  *
9947  * Originally Released Under LGPL - original licence link has changed is not relivant.
9948  *
9949  * Fork - LGPL
9950  * <script type="text/javascript">
9951  */
9952
9953
9954
9955 //Notifies Element that fx methods are available
9956 Roo.enableFx = true;
9957
9958 /**
9959  * @class Roo.Fx
9960  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9961  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9962  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9963  * Element effects to work.</p><br/>
9964  *
9965  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9966  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9967  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9968  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9969  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9970  * expected results and should be done with care.</p><br/>
9971  *
9972  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9973  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9974 <pre>
9975 Value  Description
9976 -----  -----------------------------
9977 tl     The top left corner
9978 t      The center of the top edge
9979 tr     The top right corner
9980 l      The center of the left edge
9981 r      The center of the right edge
9982 bl     The bottom left corner
9983 b      The center of the bottom edge
9984 br     The bottom right corner
9985 </pre>
9986  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9987  * below are common options that can be passed to any Fx method.</b>
9988  * @cfg {Function} callback A function called when the effect is finished
9989  * @cfg {Object} scope The scope of the effect function
9990  * @cfg {String} easing A valid Easing value for the effect
9991  * @cfg {String} afterCls A css class to apply after the effect
9992  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9993  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9994  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9995  * effects that end with the element being visually hidden, ignored otherwise)
9996  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9997  * a function which returns such a specification that will be applied to the Element after the effect finishes
9998  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9999  * @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
10000  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10001  */
10002 Roo.Fx = {
10003         /**
10004          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10005          * origin for the slide effect.  This function automatically handles wrapping the element with
10006          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10007          * Usage:
10008          *<pre><code>
10009 // default: slide the element in from the top
10010 el.slideIn();
10011
10012 // custom: slide the element in from the right with a 2-second duration
10013 el.slideIn('r', { duration: 2 });
10014
10015 // common config options shown with default values
10016 el.slideIn('t', {
10017     easing: 'easeOut',
10018     duration: .5
10019 });
10020 </code></pre>
10021          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10022          * @param {Object} options (optional) Object literal with any of the Fx config options
10023          * @return {Roo.Element} The Element
10024          */
10025     slideIn : function(anchor, o){
10026         var el = this.getFxEl();
10027         o = o || {};
10028
10029         el.queueFx(o, function(){
10030
10031             anchor = anchor || "t";
10032
10033             // fix display to visibility
10034             this.fixDisplay();
10035
10036             // restore values after effect
10037             var r = this.getFxRestore();
10038             var b = this.getBox();
10039             // fixed size for slide
10040             this.setSize(b);
10041
10042             // wrap if needed
10043             var wrap = this.fxWrap(r.pos, o, "hidden");
10044
10045             var st = this.dom.style;
10046             st.visibility = "visible";
10047             st.position = "absolute";
10048
10049             // clear out temp styles after slide and unwrap
10050             var after = function(){
10051                 el.fxUnwrap(wrap, r.pos, o);
10052                 st.width = r.width;
10053                 st.height = r.height;
10054                 el.afterFx(o);
10055             };
10056             // time to calc the positions
10057             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10058
10059             switch(anchor.toLowerCase()){
10060                 case "t":
10061                     wrap.setSize(b.width, 0);
10062                     st.left = st.bottom = "0";
10063                     a = {height: bh};
10064                 break;
10065                 case "l":
10066                     wrap.setSize(0, b.height);
10067                     st.right = st.top = "0";
10068                     a = {width: bw};
10069                 break;
10070                 case "r":
10071                     wrap.setSize(0, b.height);
10072                     wrap.setX(b.right);
10073                     st.left = st.top = "0";
10074                     a = {width: bw, points: pt};
10075                 break;
10076                 case "b":
10077                     wrap.setSize(b.width, 0);
10078                     wrap.setY(b.bottom);
10079                     st.left = st.top = "0";
10080                     a = {height: bh, points: pt};
10081                 break;
10082                 case "tl":
10083                     wrap.setSize(0, 0);
10084                     st.right = st.bottom = "0";
10085                     a = {width: bw, height: bh};
10086                 break;
10087                 case "bl":
10088                     wrap.setSize(0, 0);
10089                     wrap.setY(b.y+b.height);
10090                     st.right = st.top = "0";
10091                     a = {width: bw, height: bh, points: pt};
10092                 break;
10093                 case "br":
10094                     wrap.setSize(0, 0);
10095                     wrap.setXY([b.right, b.bottom]);
10096                     st.left = st.top = "0";
10097                     a = {width: bw, height: bh, points: pt};
10098                 break;
10099                 case "tr":
10100                     wrap.setSize(0, 0);
10101                     wrap.setX(b.x+b.width);
10102                     st.left = st.bottom = "0";
10103                     a = {width: bw, height: bh, points: pt};
10104                 break;
10105             }
10106             this.dom.style.visibility = "visible";
10107             wrap.show();
10108
10109             arguments.callee.anim = wrap.fxanim(a,
10110                 o,
10111                 'motion',
10112                 .5,
10113                 'easeOut', after);
10114         });
10115         return this;
10116     },
10117     
10118         /**
10119          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10120          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10121          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10122          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10123          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10124          * Usage:
10125          *<pre><code>
10126 // default: slide the element out to the top
10127 el.slideOut();
10128
10129 // custom: slide the element out to the right with a 2-second duration
10130 el.slideOut('r', { duration: 2 });
10131
10132 // common config options shown with default values
10133 el.slideOut('t', {
10134     easing: 'easeOut',
10135     duration: .5,
10136     remove: false,
10137     useDisplay: false
10138 });
10139 </code></pre>
10140          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10141          * @param {Object} options (optional) Object literal with any of the Fx config options
10142          * @return {Roo.Element} The Element
10143          */
10144     slideOut : function(anchor, o){
10145         var el = this.getFxEl();
10146         o = o || {};
10147
10148         el.queueFx(o, function(){
10149
10150             anchor = anchor || "t";
10151
10152             // restore values after effect
10153             var r = this.getFxRestore();
10154             
10155             var b = this.getBox();
10156             // fixed size for slide
10157             this.setSize(b);
10158
10159             // wrap if needed
10160             var wrap = this.fxWrap(r.pos, o, "visible");
10161
10162             var st = this.dom.style;
10163             st.visibility = "visible";
10164             st.position = "absolute";
10165
10166             wrap.setSize(b);
10167
10168             var after = function(){
10169                 if(o.useDisplay){
10170                     el.setDisplayed(false);
10171                 }else{
10172                     el.hide();
10173                 }
10174
10175                 el.fxUnwrap(wrap, r.pos, o);
10176
10177                 st.width = r.width;
10178                 st.height = r.height;
10179
10180                 el.afterFx(o);
10181             };
10182
10183             var a, zero = {to: 0};
10184             switch(anchor.toLowerCase()){
10185                 case "t":
10186                     st.left = st.bottom = "0";
10187                     a = {height: zero};
10188                 break;
10189                 case "l":
10190                     st.right = st.top = "0";
10191                     a = {width: zero};
10192                 break;
10193                 case "r":
10194                     st.left = st.top = "0";
10195                     a = {width: zero, points: {to:[b.right, b.y]}};
10196                 break;
10197                 case "b":
10198                     st.left = st.top = "0";
10199                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10200                 break;
10201                 case "tl":
10202                     st.right = st.bottom = "0";
10203                     a = {width: zero, height: zero};
10204                 break;
10205                 case "bl":
10206                     st.right = st.top = "0";
10207                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10208                 break;
10209                 case "br":
10210                     st.left = st.top = "0";
10211                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10212                 break;
10213                 case "tr":
10214                     st.left = st.bottom = "0";
10215                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10216                 break;
10217             }
10218
10219             arguments.callee.anim = wrap.fxanim(a,
10220                 o,
10221                 'motion',
10222                 .5,
10223                 "easeOut", after);
10224         });
10225         return this;
10226     },
10227
10228         /**
10229          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10230          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10231          * The element must be removed from the DOM using the 'remove' config option if desired.
10232          * Usage:
10233          *<pre><code>
10234 // default
10235 el.puff();
10236
10237 // common config options shown with default values
10238 el.puff({
10239     easing: 'easeOut',
10240     duration: .5,
10241     remove: false,
10242     useDisplay: false
10243 });
10244 </code></pre>
10245          * @param {Object} options (optional) Object literal with any of the Fx config options
10246          * @return {Roo.Element} The Element
10247          */
10248     puff : function(o){
10249         var el = this.getFxEl();
10250         o = o || {};
10251
10252         el.queueFx(o, function(){
10253             this.clearOpacity();
10254             this.show();
10255
10256             // restore values after effect
10257             var r = this.getFxRestore();
10258             var st = this.dom.style;
10259
10260             var after = function(){
10261                 if(o.useDisplay){
10262                     el.setDisplayed(false);
10263                 }else{
10264                     el.hide();
10265                 }
10266
10267                 el.clearOpacity();
10268
10269                 el.setPositioning(r.pos);
10270                 st.width = r.width;
10271                 st.height = r.height;
10272                 st.fontSize = '';
10273                 el.afterFx(o);
10274             };
10275
10276             var width = this.getWidth();
10277             var height = this.getHeight();
10278
10279             arguments.callee.anim = this.fxanim({
10280                     width : {to: this.adjustWidth(width * 2)},
10281                     height : {to: this.adjustHeight(height * 2)},
10282                     points : {by: [-(width * .5), -(height * .5)]},
10283                     opacity : {to: 0},
10284                     fontSize: {to:200, unit: "%"}
10285                 },
10286                 o,
10287                 'motion',
10288                 .5,
10289                 "easeOut", after);
10290         });
10291         return this;
10292     },
10293
10294         /**
10295          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10296          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10297          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10298          * Usage:
10299          *<pre><code>
10300 // default
10301 el.switchOff();
10302
10303 // all config options shown with default values
10304 el.switchOff({
10305     easing: 'easeIn',
10306     duration: .3,
10307     remove: false,
10308     useDisplay: false
10309 });
10310 </code></pre>
10311          * @param {Object} options (optional) Object literal with any of the Fx config options
10312          * @return {Roo.Element} The Element
10313          */
10314     switchOff : function(o){
10315         var el = this.getFxEl();
10316         o = o || {};
10317
10318         el.queueFx(o, function(){
10319             this.clearOpacity();
10320             this.clip();
10321
10322             // restore values after effect
10323             var r = this.getFxRestore();
10324             var st = this.dom.style;
10325
10326             var after = function(){
10327                 if(o.useDisplay){
10328                     el.setDisplayed(false);
10329                 }else{
10330                     el.hide();
10331                 }
10332
10333                 el.clearOpacity();
10334                 el.setPositioning(r.pos);
10335                 st.width = r.width;
10336                 st.height = r.height;
10337
10338                 el.afterFx(o);
10339             };
10340
10341             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10342                 this.clearOpacity();
10343                 (function(){
10344                     this.fxanim({
10345                         height:{to:1},
10346                         points:{by:[0, this.getHeight() * .5]}
10347                     }, o, 'motion', 0.3, 'easeIn', after);
10348                 }).defer(100, this);
10349             });
10350         });
10351         return this;
10352     },
10353
10354     /**
10355      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10356      * changed using the "attr" config option) and then fading back to the original color. If no original
10357      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10358      * Usage:
10359 <pre><code>
10360 // default: highlight background to yellow
10361 el.highlight();
10362
10363 // custom: highlight foreground text to blue for 2 seconds
10364 el.highlight("0000ff", { attr: 'color', duration: 2 });
10365
10366 // common config options shown with default values
10367 el.highlight("ffff9c", {
10368     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10369     endColor: (current color) or "ffffff",
10370     easing: 'easeIn',
10371     duration: 1
10372 });
10373 </code></pre>
10374      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10375      * @param {Object} options (optional) Object literal with any of the Fx config options
10376      * @return {Roo.Element} The Element
10377      */ 
10378     highlight : function(color, o){
10379         var el = this.getFxEl();
10380         o = o || {};
10381
10382         el.queueFx(o, function(){
10383             color = color || "ffff9c";
10384             attr = o.attr || "backgroundColor";
10385
10386             this.clearOpacity();
10387             this.show();
10388
10389             var origColor = this.getColor(attr);
10390             var restoreColor = this.dom.style[attr];
10391             endColor = (o.endColor || origColor) || "ffffff";
10392
10393             var after = function(){
10394                 el.dom.style[attr] = restoreColor;
10395                 el.afterFx(o);
10396             };
10397
10398             var a = {};
10399             a[attr] = {from: color, to: endColor};
10400             arguments.callee.anim = this.fxanim(a,
10401                 o,
10402                 'color',
10403                 1,
10404                 'easeIn', after);
10405         });
10406         return this;
10407     },
10408
10409    /**
10410     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10411     * Usage:
10412 <pre><code>
10413 // default: a single light blue ripple
10414 el.frame();
10415
10416 // custom: 3 red ripples lasting 3 seconds total
10417 el.frame("ff0000", 3, { duration: 3 });
10418
10419 // common config options shown with default values
10420 el.frame("C3DAF9", 1, {
10421     duration: 1 //duration of entire animation (not each individual ripple)
10422     // Note: Easing is not configurable and will be ignored if included
10423 });
10424 </code></pre>
10425     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10426     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10427     * @param {Object} options (optional) Object literal with any of the Fx config options
10428     * @return {Roo.Element} The Element
10429     */
10430     frame : function(color, count, o){
10431         var el = this.getFxEl();
10432         o = o || {};
10433
10434         el.queueFx(o, function(){
10435             color = color || "#C3DAF9";
10436             if(color.length == 6){
10437                 color = "#" + color;
10438             }
10439             count = count || 1;
10440             duration = o.duration || 1;
10441             this.show();
10442
10443             var b = this.getBox();
10444             var animFn = function(){
10445                 var proxy = this.createProxy({
10446
10447                      style:{
10448                         visbility:"hidden",
10449                         position:"absolute",
10450                         "z-index":"35000", // yee haw
10451                         border:"0px solid " + color
10452                      }
10453                   });
10454                 var scale = Roo.isBorderBox ? 2 : 1;
10455                 proxy.animate({
10456                     top:{from:b.y, to:b.y - 20},
10457                     left:{from:b.x, to:b.x - 20},
10458                     borderWidth:{from:0, to:10},
10459                     opacity:{from:1, to:0},
10460                     height:{from:b.height, to:(b.height + (20*scale))},
10461                     width:{from:b.width, to:(b.width + (20*scale))}
10462                 }, duration, function(){
10463                     proxy.remove();
10464                 });
10465                 if(--count > 0){
10466                      animFn.defer((duration/2)*1000, this);
10467                 }else{
10468                     el.afterFx(o);
10469                 }
10470             };
10471             animFn.call(this);
10472         });
10473         return this;
10474     },
10475
10476    /**
10477     * Creates a pause before any subsequent queued effects begin.  If there are
10478     * no effects queued after the pause it will have no effect.
10479     * Usage:
10480 <pre><code>
10481 el.pause(1);
10482 </code></pre>
10483     * @param {Number} seconds The length of time to pause (in seconds)
10484     * @return {Roo.Element} The Element
10485     */
10486     pause : function(seconds){
10487         var el = this.getFxEl();
10488         var o = {};
10489
10490         el.queueFx(o, function(){
10491             setTimeout(function(){
10492                 el.afterFx(o);
10493             }, seconds * 1000);
10494         });
10495         return this;
10496     },
10497
10498    /**
10499     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10500     * using the "endOpacity" config option.
10501     * Usage:
10502 <pre><code>
10503 // default: fade in from opacity 0 to 100%
10504 el.fadeIn();
10505
10506 // custom: fade in from opacity 0 to 75% over 2 seconds
10507 el.fadeIn({ endOpacity: .75, duration: 2});
10508
10509 // common config options shown with default values
10510 el.fadeIn({
10511     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10512     easing: 'easeOut',
10513     duration: .5
10514 });
10515 </code></pre>
10516     * @param {Object} options (optional) Object literal with any of the Fx config options
10517     * @return {Roo.Element} The Element
10518     */
10519     fadeIn : function(o){
10520         var el = this.getFxEl();
10521         o = o || {};
10522         el.queueFx(o, function(){
10523             this.setOpacity(0);
10524             this.fixDisplay();
10525             this.dom.style.visibility = 'visible';
10526             var to = o.endOpacity || 1;
10527             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10528                 o, null, .5, "easeOut", function(){
10529                 if(to == 1){
10530                     this.clearOpacity();
10531                 }
10532                 el.afterFx(o);
10533             });
10534         });
10535         return this;
10536     },
10537
10538    /**
10539     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10540     * using the "endOpacity" config option.
10541     * Usage:
10542 <pre><code>
10543 // default: fade out from the element's current opacity to 0
10544 el.fadeOut();
10545
10546 // custom: fade out from the element's current opacity to 25% over 2 seconds
10547 el.fadeOut({ endOpacity: .25, duration: 2});
10548
10549 // common config options shown with default values
10550 el.fadeOut({
10551     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10552     easing: 'easeOut',
10553     duration: .5
10554     remove: false,
10555     useDisplay: false
10556 });
10557 </code></pre>
10558     * @param {Object} options (optional) Object literal with any of the Fx config options
10559     * @return {Roo.Element} The Element
10560     */
10561     fadeOut : function(o){
10562         var el = this.getFxEl();
10563         o = o || {};
10564         el.queueFx(o, function(){
10565             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10566                 o, null, .5, "easeOut", function(){
10567                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10568                      this.dom.style.display = "none";
10569                 }else{
10570                      this.dom.style.visibility = "hidden";
10571                 }
10572                 this.clearOpacity();
10573                 el.afterFx(o);
10574             });
10575         });
10576         return this;
10577     },
10578
10579    /**
10580     * Animates the transition of an element's dimensions from a starting height/width
10581     * to an ending height/width.
10582     * Usage:
10583 <pre><code>
10584 // change height and width to 100x100 pixels
10585 el.scale(100, 100);
10586
10587 // common config options shown with default values.  The height and width will default to
10588 // the element's existing values if passed as null.
10589 el.scale(
10590     [element's width],
10591     [element's height], {
10592     easing: 'easeOut',
10593     duration: .35
10594 });
10595 </code></pre>
10596     * @param {Number} width  The new width (pass undefined to keep the original width)
10597     * @param {Number} height  The new height (pass undefined to keep the original height)
10598     * @param {Object} options (optional) Object literal with any of the Fx config options
10599     * @return {Roo.Element} The Element
10600     */
10601     scale : function(w, h, o){
10602         this.shift(Roo.apply({}, o, {
10603             width: w,
10604             height: h
10605         }));
10606         return this;
10607     },
10608
10609    /**
10610     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10611     * Any of these properties not specified in the config object will not be changed.  This effect 
10612     * requires that at least one new dimension, position or opacity setting must be passed in on
10613     * the config object in order for the function to have any effect.
10614     * Usage:
10615 <pre><code>
10616 // slide the element horizontally to x position 200 while changing the height and opacity
10617 el.shift({ x: 200, height: 50, opacity: .8 });
10618
10619 // common config options shown with default values.
10620 el.shift({
10621     width: [element's width],
10622     height: [element's height],
10623     x: [element's x position],
10624     y: [element's y position],
10625     opacity: [element's opacity],
10626     easing: 'easeOut',
10627     duration: .35
10628 });
10629 </code></pre>
10630     * @param {Object} options  Object literal with any of the Fx config options
10631     * @return {Roo.Element} The Element
10632     */
10633     shift : function(o){
10634         var el = this.getFxEl();
10635         o = o || {};
10636         el.queueFx(o, function(){
10637             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10638             if(w !== undefined){
10639                 a.width = {to: this.adjustWidth(w)};
10640             }
10641             if(h !== undefined){
10642                 a.height = {to: this.adjustHeight(h)};
10643             }
10644             if(x !== undefined || y !== undefined){
10645                 a.points = {to: [
10646                     x !== undefined ? x : this.getX(),
10647                     y !== undefined ? y : this.getY()
10648                 ]};
10649             }
10650             if(op !== undefined){
10651                 a.opacity = {to: op};
10652             }
10653             if(o.xy !== undefined){
10654                 a.points = {to: o.xy};
10655             }
10656             arguments.callee.anim = this.fxanim(a,
10657                 o, 'motion', .35, "easeOut", function(){
10658                 el.afterFx(o);
10659             });
10660         });
10661         return this;
10662     },
10663
10664         /**
10665          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10666          * ending point of the effect.
10667          * Usage:
10668          *<pre><code>
10669 // default: slide the element downward while fading out
10670 el.ghost();
10671
10672 // custom: slide the element out to the right with a 2-second duration
10673 el.ghost('r', { duration: 2 });
10674
10675 // common config options shown with default values
10676 el.ghost('b', {
10677     easing: 'easeOut',
10678     duration: .5
10679     remove: false,
10680     useDisplay: false
10681 });
10682 </code></pre>
10683          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10684          * @param {Object} options (optional) Object literal with any of the Fx config options
10685          * @return {Roo.Element} The Element
10686          */
10687     ghost : function(anchor, o){
10688         var el = this.getFxEl();
10689         o = o || {};
10690
10691         el.queueFx(o, function(){
10692             anchor = anchor || "b";
10693
10694             // restore values after effect
10695             var r = this.getFxRestore();
10696             var w = this.getWidth(),
10697                 h = this.getHeight();
10698
10699             var st = this.dom.style;
10700
10701             var after = function(){
10702                 if(o.useDisplay){
10703                     el.setDisplayed(false);
10704                 }else{
10705                     el.hide();
10706                 }
10707
10708                 el.clearOpacity();
10709                 el.setPositioning(r.pos);
10710                 st.width = r.width;
10711                 st.height = r.height;
10712
10713                 el.afterFx(o);
10714             };
10715
10716             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10717             switch(anchor.toLowerCase()){
10718                 case "t":
10719                     pt.by = [0, -h];
10720                 break;
10721                 case "l":
10722                     pt.by = [-w, 0];
10723                 break;
10724                 case "r":
10725                     pt.by = [w, 0];
10726                 break;
10727                 case "b":
10728                     pt.by = [0, h];
10729                 break;
10730                 case "tl":
10731                     pt.by = [-w, -h];
10732                 break;
10733                 case "bl":
10734                     pt.by = [-w, h];
10735                 break;
10736                 case "br":
10737                     pt.by = [w, h];
10738                 break;
10739                 case "tr":
10740                     pt.by = [w, -h];
10741                 break;
10742             }
10743
10744             arguments.callee.anim = this.fxanim(a,
10745                 o,
10746                 'motion',
10747                 .5,
10748                 "easeOut", after);
10749         });
10750         return this;
10751     },
10752
10753         /**
10754          * Ensures that all effects queued after syncFx is called on the element are
10755          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10756          * @return {Roo.Element} The Element
10757          */
10758     syncFx : function(){
10759         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10760             block : false,
10761             concurrent : true,
10762             stopFx : false
10763         });
10764         return this;
10765     },
10766
10767         /**
10768          * Ensures that all effects queued after sequenceFx is called on the element are
10769          * run in sequence.  This is the opposite of {@link #syncFx}.
10770          * @return {Roo.Element} The Element
10771          */
10772     sequenceFx : function(){
10773         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10774             block : false,
10775             concurrent : false,
10776             stopFx : false
10777         });
10778         return this;
10779     },
10780
10781         /* @private */
10782     nextFx : function(){
10783         var ef = this.fxQueue[0];
10784         if(ef){
10785             ef.call(this);
10786         }
10787     },
10788
10789         /**
10790          * Returns true if the element has any effects actively running or queued, else returns false.
10791          * @return {Boolean} True if element has active effects, else false
10792          */
10793     hasActiveFx : function(){
10794         return this.fxQueue && this.fxQueue[0];
10795     },
10796
10797         /**
10798          * Stops any running effects and clears the element's internal effects queue if it contains
10799          * any additional effects that haven't started yet.
10800          * @return {Roo.Element} The Element
10801          */
10802     stopFx : function(){
10803         if(this.hasActiveFx()){
10804             var cur = this.fxQueue[0];
10805             if(cur && cur.anim && cur.anim.isAnimated()){
10806                 this.fxQueue = [cur]; // clear out others
10807                 cur.anim.stop(true);
10808             }
10809         }
10810         return this;
10811     },
10812
10813         /* @private */
10814     beforeFx : function(o){
10815         if(this.hasActiveFx() && !o.concurrent){
10816            if(o.stopFx){
10817                this.stopFx();
10818                return true;
10819            }
10820            return false;
10821         }
10822         return true;
10823     },
10824
10825         /**
10826          * Returns true if the element is currently blocking so that no other effect can be queued
10827          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10828          * used to ensure that an effect initiated by a user action runs to completion prior to the
10829          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10830          * @return {Boolean} True if blocking, else false
10831          */
10832     hasFxBlock : function(){
10833         var q = this.fxQueue;
10834         return q && q[0] && q[0].block;
10835     },
10836
10837         /* @private */
10838     queueFx : function(o, fn){
10839         if(!this.fxQueue){
10840             this.fxQueue = [];
10841         }
10842         if(!this.hasFxBlock()){
10843             Roo.applyIf(o, this.fxDefaults);
10844             if(!o.concurrent){
10845                 var run = this.beforeFx(o);
10846                 fn.block = o.block;
10847                 this.fxQueue.push(fn);
10848                 if(run){
10849                     this.nextFx();
10850                 }
10851             }else{
10852                 fn.call(this);
10853             }
10854         }
10855         return this;
10856     },
10857
10858         /* @private */
10859     fxWrap : function(pos, o, vis){
10860         var wrap;
10861         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10862             var wrapXY;
10863             if(o.fixPosition){
10864                 wrapXY = this.getXY();
10865             }
10866             var div = document.createElement("div");
10867             div.style.visibility = vis;
10868             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10869             wrap.setPositioning(pos);
10870             if(wrap.getStyle("position") == "static"){
10871                 wrap.position("relative");
10872             }
10873             this.clearPositioning('auto');
10874             wrap.clip();
10875             wrap.dom.appendChild(this.dom);
10876             if(wrapXY){
10877                 wrap.setXY(wrapXY);
10878             }
10879         }
10880         return wrap;
10881     },
10882
10883         /* @private */
10884     fxUnwrap : function(wrap, pos, o){
10885         this.clearPositioning();
10886         this.setPositioning(pos);
10887         if(!o.wrap){
10888             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10889             wrap.remove();
10890         }
10891     },
10892
10893         /* @private */
10894     getFxRestore : function(){
10895         var st = this.dom.style;
10896         return {pos: this.getPositioning(), width: st.width, height : st.height};
10897     },
10898
10899         /* @private */
10900     afterFx : function(o){
10901         if(o.afterStyle){
10902             this.applyStyles(o.afterStyle);
10903         }
10904         if(o.afterCls){
10905             this.addClass(o.afterCls);
10906         }
10907         if(o.remove === true){
10908             this.remove();
10909         }
10910         Roo.callback(o.callback, o.scope, [this]);
10911         if(!o.concurrent){
10912             this.fxQueue.shift();
10913             this.nextFx();
10914         }
10915     },
10916
10917         /* @private */
10918     getFxEl : function(){ // support for composite element fx
10919         return Roo.get(this.dom);
10920     },
10921
10922         /* @private */
10923     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10924         animType = animType || 'run';
10925         opt = opt || {};
10926         var anim = Roo.lib.Anim[animType](
10927             this.dom, args,
10928             (opt.duration || defaultDur) || .35,
10929             (opt.easing || defaultEase) || 'easeOut',
10930             function(){
10931                 Roo.callback(cb, this);
10932             },
10933             this
10934         );
10935         opt.anim = anim;
10936         return anim;
10937     }
10938 };
10939
10940 // backwords compat
10941 Roo.Fx.resize = Roo.Fx.scale;
10942
10943 //When included, Roo.Fx is automatically applied to Element so that all basic
10944 //effects are available directly via the Element API
10945 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10946  * Based on:
10947  * Ext JS Library 1.1.1
10948  * Copyright(c) 2006-2007, Ext JS, LLC.
10949  *
10950  * Originally Released Under LGPL - original licence link has changed is not relivant.
10951  *
10952  * Fork - LGPL
10953  * <script type="text/javascript">
10954  */
10955
10956
10957 /**
10958  * @class Roo.CompositeElement
10959  * Standard composite class. Creates a Roo.Element for every element in the collection.
10960  * <br><br>
10961  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10962  * actions will be performed on all the elements in this collection.</b>
10963  * <br><br>
10964  * All methods return <i>this</i> and can be chained.
10965  <pre><code>
10966  var els = Roo.select("#some-el div.some-class", true);
10967  // or select directly from an existing element
10968  var el = Roo.get('some-el');
10969  el.select('div.some-class', true);
10970
10971  els.setWidth(100); // all elements become 100 width
10972  els.hide(true); // all elements fade out and hide
10973  // or
10974  els.setWidth(100).hide(true);
10975  </code></pre>
10976  */
10977 Roo.CompositeElement = function(els){
10978     this.elements = [];
10979     this.addElements(els);
10980 };
10981 Roo.CompositeElement.prototype = {
10982     isComposite: true,
10983     addElements : function(els){
10984         if(!els) return this;
10985         if(typeof els == "string"){
10986             els = Roo.Element.selectorFunction(els);
10987         }
10988         var yels = this.elements;
10989         var index = yels.length-1;
10990         for(var i = 0, len = els.length; i < len; i++) {
10991                 yels[++index] = Roo.get(els[i]);
10992         }
10993         return this;
10994     },
10995
10996     /**
10997     * Clears this composite and adds the elements returned by the passed selector.
10998     * @param {String/Array} els A string CSS selector, an array of elements or an element
10999     * @return {CompositeElement} this
11000     */
11001     fill : function(els){
11002         this.elements = [];
11003         this.add(els);
11004         return this;
11005     },
11006
11007     /**
11008     * Filters this composite to only elements that match the passed selector.
11009     * @param {String} selector A string CSS selector
11010     * @param {Boolean} inverse return inverse filter (not matches)
11011     * @return {CompositeElement} this
11012     */
11013     filter : function(selector, inverse){
11014         var els = [];
11015         inverse = inverse || false;
11016         this.each(function(el){
11017             var match = inverse ? !el.is(selector) : el.is(selector);
11018             if(match){
11019                 els[els.length] = el.dom;
11020             }
11021         });
11022         this.fill(els);
11023         return this;
11024     },
11025
11026     invoke : function(fn, args){
11027         var els = this.elements;
11028         for(var i = 0, len = els.length; i < len; i++) {
11029                 Roo.Element.prototype[fn].apply(els[i], args);
11030         }
11031         return this;
11032     },
11033     /**
11034     * Adds elements to this composite.
11035     * @param {String/Array} els A string CSS selector, an array of elements or an element
11036     * @return {CompositeElement} this
11037     */
11038     add : function(els){
11039         if(typeof els == "string"){
11040             this.addElements(Roo.Element.selectorFunction(els));
11041         }else if(els.length !== undefined){
11042             this.addElements(els);
11043         }else{
11044             this.addElements([els]);
11045         }
11046         return this;
11047     },
11048     /**
11049     * Calls the passed function passing (el, this, index) for each element in this composite.
11050     * @param {Function} fn The function to call
11051     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11052     * @return {CompositeElement} this
11053     */
11054     each : function(fn, scope){
11055         var els = this.elements;
11056         for(var i = 0, len = els.length; i < len; i++){
11057             if(fn.call(scope || els[i], els[i], this, i) === false) {
11058                 break;
11059             }
11060         }
11061         return this;
11062     },
11063
11064     /**
11065      * Returns the Element object at the specified index
11066      * @param {Number} index
11067      * @return {Roo.Element}
11068      */
11069     item : function(index){
11070         return this.elements[index] || null;
11071     },
11072
11073     /**
11074      * Returns the first Element
11075      * @return {Roo.Element}
11076      */
11077     first : function(){
11078         return this.item(0);
11079     },
11080
11081     /**
11082      * Returns the last Element
11083      * @return {Roo.Element}
11084      */
11085     last : function(){
11086         return this.item(this.elements.length-1);
11087     },
11088
11089     /**
11090      * Returns the number of elements in this composite
11091      * @return Number
11092      */
11093     getCount : function(){
11094         return this.elements.length;
11095     },
11096
11097     /**
11098      * Returns true if this composite contains the passed element
11099      * @return Boolean
11100      */
11101     contains : function(el){
11102         return this.indexOf(el) !== -1;
11103     },
11104
11105     /**
11106      * Returns true if this composite contains the passed element
11107      * @return Boolean
11108      */
11109     indexOf : function(el){
11110         return this.elements.indexOf(Roo.get(el));
11111     },
11112
11113
11114     /**
11115     * Removes the specified element(s).
11116     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11117     * or an array of any of those.
11118     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11119     * @return {CompositeElement} this
11120     */
11121     removeElement : function(el, removeDom){
11122         if(el instanceof Array){
11123             for(var i = 0, len = el.length; i < len; i++){
11124                 this.removeElement(el[i]);
11125             }
11126             return this;
11127         }
11128         var index = typeof el == 'number' ? el : this.indexOf(el);
11129         if(index !== -1){
11130             if(removeDom){
11131                 var d = this.elements[index];
11132                 if(d.dom){
11133                     d.remove();
11134                 }else{
11135                     d.parentNode.removeChild(d);
11136                 }
11137             }
11138             this.elements.splice(index, 1);
11139         }
11140         return this;
11141     },
11142
11143     /**
11144     * Replaces the specified element with the passed element.
11145     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11146     * to replace.
11147     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11148     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11149     * @return {CompositeElement} this
11150     */
11151     replaceElement : function(el, replacement, domReplace){
11152         var index = typeof el == 'number' ? el : this.indexOf(el);
11153         if(index !== -1){
11154             if(domReplace){
11155                 this.elements[index].replaceWith(replacement);
11156             }else{
11157                 this.elements.splice(index, 1, Roo.get(replacement))
11158             }
11159         }
11160         return this;
11161     },
11162
11163     /**
11164      * Removes all elements.
11165      */
11166     clear : function(){
11167         this.elements = [];
11168     }
11169 };
11170 (function(){
11171     Roo.CompositeElement.createCall = function(proto, fnName){
11172         if(!proto[fnName]){
11173             proto[fnName] = function(){
11174                 return this.invoke(fnName, arguments);
11175             };
11176         }
11177     };
11178     for(var fnName in Roo.Element.prototype){
11179         if(typeof Roo.Element.prototype[fnName] == "function"){
11180             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11181         }
11182     };
11183 })();
11184 /*
11185  * Based on:
11186  * Ext JS Library 1.1.1
11187  * Copyright(c) 2006-2007, Ext JS, LLC.
11188  *
11189  * Originally Released Under LGPL - original licence link has changed is not relivant.
11190  *
11191  * Fork - LGPL
11192  * <script type="text/javascript">
11193  */
11194
11195 /**
11196  * @class Roo.CompositeElementLite
11197  * @extends Roo.CompositeElement
11198  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11199  <pre><code>
11200  var els = Roo.select("#some-el div.some-class");
11201  // or select directly from an existing element
11202  var el = Roo.get('some-el');
11203  el.select('div.some-class');
11204
11205  els.setWidth(100); // all elements become 100 width
11206  els.hide(true); // all elements fade out and hide
11207  // or
11208  els.setWidth(100).hide(true);
11209  </code></pre><br><br>
11210  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11211  * actions will be performed on all the elements in this collection.</b>
11212  */
11213 Roo.CompositeElementLite = function(els){
11214     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11215     this.el = new Roo.Element.Flyweight();
11216 };
11217 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11218     addElements : function(els){
11219         if(els){
11220             if(els instanceof Array){
11221                 this.elements = this.elements.concat(els);
11222             }else{
11223                 var yels = this.elements;
11224                 var index = yels.length-1;
11225                 for(var i = 0, len = els.length; i < len; i++) {
11226                     yels[++index] = els[i];
11227                 }
11228             }
11229         }
11230         return this;
11231     },
11232     invoke : function(fn, args){
11233         var els = this.elements;
11234         var el = this.el;
11235         for(var i = 0, len = els.length; i < len; i++) {
11236             el.dom = els[i];
11237                 Roo.Element.prototype[fn].apply(el, args);
11238         }
11239         return this;
11240     },
11241     /**
11242      * Returns a flyweight Element of the dom element object at the specified index
11243      * @param {Number} index
11244      * @return {Roo.Element}
11245      */
11246     item : function(index){
11247         if(!this.elements[index]){
11248             return null;
11249         }
11250         this.el.dom = this.elements[index];
11251         return this.el;
11252     },
11253
11254     // fixes scope with flyweight
11255     addListener : function(eventName, handler, scope, opt){
11256         var els = this.elements;
11257         for(var i = 0, len = els.length; i < len; i++) {
11258             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11259         }
11260         return this;
11261     },
11262
11263     /**
11264     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11265     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11266     * a reference to the dom node, use el.dom.</b>
11267     * @param {Function} fn The function to call
11268     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11269     * @return {CompositeElement} this
11270     */
11271     each : function(fn, scope){
11272         var els = this.elements;
11273         var el = this.el;
11274         for(var i = 0, len = els.length; i < len; i++){
11275             el.dom = els[i];
11276                 if(fn.call(scope || el, el, this, i) === false){
11277                 break;
11278             }
11279         }
11280         return this;
11281     },
11282
11283     indexOf : function(el){
11284         return this.elements.indexOf(Roo.getDom(el));
11285     },
11286
11287     replaceElement : function(el, replacement, domReplace){
11288         var index = typeof el == 'number' ? el : this.indexOf(el);
11289         if(index !== -1){
11290             replacement = Roo.getDom(replacement);
11291             if(domReplace){
11292                 var d = this.elements[index];
11293                 d.parentNode.insertBefore(replacement, d);
11294                 d.parentNode.removeChild(d);
11295             }
11296             this.elements.splice(index, 1, replacement);
11297         }
11298         return this;
11299     }
11300 });
11301 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11302
11303 /*
11304  * Based on:
11305  * Ext JS Library 1.1.1
11306  * Copyright(c) 2006-2007, Ext JS, LLC.
11307  *
11308  * Originally Released Under LGPL - original licence link has changed is not relivant.
11309  *
11310  * Fork - LGPL
11311  * <script type="text/javascript">
11312  */
11313
11314  
11315
11316 /**
11317  * @class Roo.data.Connection
11318  * @extends Roo.util.Observable
11319  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11320  * either to a configured URL, or to a URL specified at request time.<br><br>
11321  * <p>
11322  * Requests made by this class are asynchronous, and will return immediately. No data from
11323  * the server will be available to the statement immediately following the {@link #request} call.
11324  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11325  * <p>
11326  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11327  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11328  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11329  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11330  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11331  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11332  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11333  * standard DOM methods.
11334  * @constructor
11335  * @param {Object} config a configuration object.
11336  */
11337 Roo.data.Connection = function(config){
11338     Roo.apply(this, config);
11339     this.addEvents({
11340         /**
11341          * @event beforerequest
11342          * Fires before a network request is made to retrieve a data object.
11343          * @param {Connection} conn This Connection object.
11344          * @param {Object} options The options config object passed to the {@link #request} method.
11345          */
11346         "beforerequest" : true,
11347         /**
11348          * @event requestcomplete
11349          * Fires if the request was successfully completed.
11350          * @param {Connection} conn This Connection object.
11351          * @param {Object} response The XHR object containing the response data.
11352          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11353          * @param {Object} options The options config object passed to the {@link #request} method.
11354          */
11355         "requestcomplete" : true,
11356         /**
11357          * @event requestexception
11358          * Fires if an error HTTP status was returned from the server.
11359          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11360          * @param {Connection} conn This Connection object.
11361          * @param {Object} response The XHR object containing the response data.
11362          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11363          * @param {Object} options The options config object passed to the {@link #request} method.
11364          */
11365         "requestexception" : true
11366     });
11367     Roo.data.Connection.superclass.constructor.call(this);
11368 };
11369
11370 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11371     /**
11372      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11373      */
11374     /**
11375      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11376      * extra parameters to each request made by this object. (defaults to undefined)
11377      */
11378     /**
11379      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11380      *  to each request made by this object. (defaults to undefined)
11381      */
11382     /**
11383      * @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)
11384      */
11385     /**
11386      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11387      */
11388     timeout : 30000,
11389     /**
11390      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11391      * @type Boolean
11392      */
11393     autoAbort:false,
11394
11395     /**
11396      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11397      * @type Boolean
11398      */
11399     disableCaching: true,
11400
11401     /**
11402      * Sends an HTTP request to a remote server.
11403      * @param {Object} options An object which may contain the following properties:<ul>
11404      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11405      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11406      * request, a url encoded string or a function to call to get either.</li>
11407      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11408      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11409      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11410      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11411      * <li>options {Object} The parameter to the request call.</li>
11412      * <li>success {Boolean} True if the request succeeded.</li>
11413      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11414      * </ul></li>
11415      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11416      * The callback is passed the following parameters:<ul>
11417      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11418      * <li>options {Object} The parameter to the request call.</li>
11419      * </ul></li>
11420      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure 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>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11426      * for the callback function. Defaults to the browser window.</li>
11427      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11428      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11429      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11430      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11431      * params for the post data. Any params will be appended to the URL.</li>
11432      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11433      * </ul>
11434      * @return {Number} transactionId
11435      */
11436     request : function(o){
11437         if(this.fireEvent("beforerequest", this, o) !== false){
11438             var p = o.params;
11439
11440             if(typeof p == "function"){
11441                 p = p.call(o.scope||window, o);
11442             }
11443             if(typeof p == "object"){
11444                 p = Roo.urlEncode(o.params);
11445             }
11446             if(this.extraParams){
11447                 var extras = Roo.urlEncode(this.extraParams);
11448                 p = p ? (p + '&' + extras) : extras;
11449             }
11450
11451             var url = o.url || this.url;
11452             if(typeof url == 'function'){
11453                 url = url.call(o.scope||window, o);
11454             }
11455
11456             if(o.form){
11457                 var form = Roo.getDom(o.form);
11458                 url = url || form.action;
11459
11460                 var enctype = form.getAttribute("enctype");
11461                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11462                     return this.doFormUpload(o, p, url);
11463                 }
11464                 var f = Roo.lib.Ajax.serializeForm(form);
11465                 p = p ? (p + '&' + f) : f;
11466             }
11467
11468             var hs = o.headers;
11469             if(this.defaultHeaders){
11470                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11471                 if(!o.headers){
11472                     o.headers = hs;
11473                 }
11474             }
11475
11476             var cb = {
11477                 success: this.handleResponse,
11478                 failure: this.handleFailure,
11479                 scope: this,
11480                 argument: {options: o},
11481                 timeout : o.timeout || this.timeout
11482             };
11483
11484             var method = o.method||this.method||(p ? "POST" : "GET");
11485
11486             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11487                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11488             }
11489
11490             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11491                 if(o.autoAbort){
11492                     this.abort();
11493                 }
11494             }else if(this.autoAbort !== false){
11495                 this.abort();
11496             }
11497
11498             if((method == 'GET' && p) || o.xmlData){
11499                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11500                 p = '';
11501             }
11502             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11503             return this.transId;
11504         }else{
11505             Roo.callback(o.callback, o.scope, [o, null, null]);
11506             return null;
11507         }
11508     },
11509
11510     /**
11511      * Determine whether this object has a request outstanding.
11512      * @param {Number} transactionId (Optional) defaults to the last transaction
11513      * @return {Boolean} True if there is an outstanding request.
11514      */
11515     isLoading : function(transId){
11516         if(transId){
11517             return Roo.lib.Ajax.isCallInProgress(transId);
11518         }else{
11519             return this.transId ? true : false;
11520         }
11521     },
11522
11523     /**
11524      * Aborts any outstanding request.
11525      * @param {Number} transactionId (Optional) defaults to the last transaction
11526      */
11527     abort : function(transId){
11528         if(transId || this.isLoading()){
11529             Roo.lib.Ajax.abort(transId || this.transId);
11530         }
11531     },
11532
11533     // private
11534     handleResponse : function(response){
11535         this.transId = false;
11536         var options = response.argument.options;
11537         response.argument = options ? options.argument : null;
11538         this.fireEvent("requestcomplete", this, response, options);
11539         Roo.callback(options.success, options.scope, [response, options]);
11540         Roo.callback(options.callback, options.scope, [options, true, response]);
11541     },
11542
11543     // private
11544     handleFailure : function(response, e){
11545         this.transId = false;
11546         var options = response.argument.options;
11547         response.argument = options ? options.argument : null;
11548         this.fireEvent("requestexception", this, response, options, e);
11549         Roo.callback(options.failure, options.scope, [response, options]);
11550         Roo.callback(options.callback, options.scope, [options, false, response]);
11551     },
11552
11553     // private
11554     doFormUpload : function(o, ps, url){
11555         var id = Roo.id();
11556         var frame = document.createElement('iframe');
11557         frame.id = id;
11558         frame.name = id;
11559         frame.className = 'x-hidden';
11560         if(Roo.isIE){
11561             frame.src = Roo.SSL_SECURE_URL;
11562         }
11563         document.body.appendChild(frame);
11564
11565         if(Roo.isIE){
11566            document.frames[id].name = id;
11567         }
11568
11569         var form = Roo.getDom(o.form);
11570         form.target = id;
11571         form.method = 'POST';
11572         form.enctype = form.encoding = 'multipart/form-data';
11573         if(url){
11574             form.action = url;
11575         }
11576
11577         var hiddens, hd;
11578         if(ps){ // add dynamic params
11579             hiddens = [];
11580             ps = Roo.urlDecode(ps, false);
11581             for(var k in ps){
11582                 if(ps.hasOwnProperty(k)){
11583                     hd = document.createElement('input');
11584                     hd.type = 'hidden';
11585                     hd.name = k;
11586                     hd.value = ps[k];
11587                     form.appendChild(hd);
11588                     hiddens.push(hd);
11589                 }
11590             }
11591         }
11592
11593         function cb(){
11594             var r = {  // bogus response object
11595                 responseText : '',
11596                 responseXML : null
11597             };
11598
11599             r.argument = o ? o.argument : null;
11600
11601             try { //
11602                 var doc;
11603                 if(Roo.isIE){
11604                     doc = frame.contentWindow.document;
11605                 }else {
11606                     doc = (frame.contentDocument || window.frames[id].document);
11607                 }
11608                 if(doc && doc.body){
11609                     r.responseText = doc.body.innerHTML;
11610                 }
11611                 if(doc && doc.XMLDocument){
11612                     r.responseXML = doc.XMLDocument;
11613                 }else {
11614                     r.responseXML = doc;
11615                 }
11616             }
11617             catch(e) {
11618                 // ignore
11619             }
11620
11621             Roo.EventManager.removeListener(frame, 'load', cb, this);
11622
11623             this.fireEvent("requestcomplete", this, r, o);
11624             Roo.callback(o.success, o.scope, [r, o]);
11625             Roo.callback(o.callback, o.scope, [o, true, r]);
11626
11627             setTimeout(function(){document.body.removeChild(frame);}, 100);
11628         }
11629
11630         Roo.EventManager.on(frame, 'load', cb, this);
11631         form.submit();
11632
11633         if(hiddens){ // remove dynamic params
11634             for(var i = 0, len = hiddens.length; i < len; i++){
11635                 form.removeChild(hiddens[i]);
11636             }
11637         }
11638     }
11639 });
11640 /*
11641  * Based on:
11642  * Ext JS Library 1.1.1
11643  * Copyright(c) 2006-2007, Ext JS, LLC.
11644  *
11645  * Originally Released Under LGPL - original licence link has changed is not relivant.
11646  *
11647  * Fork - LGPL
11648  * <script type="text/javascript">
11649  */
11650  
11651 /**
11652  * Global Ajax request class.
11653  * 
11654  * @class Roo.Ajax
11655  * @extends Roo.data.Connection
11656  * @static
11657  * 
11658  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11659  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11660  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11661  * @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)
11662  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11663  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11664  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11665  */
11666 Roo.Ajax = new Roo.data.Connection({
11667     // fix up the docs
11668     /**
11669      * @scope Roo.Ajax
11670      * @type {Boolear} 
11671      */
11672     autoAbort : false,
11673
11674     /**
11675      * Serialize the passed form into a url encoded string
11676      * @scope Roo.Ajax
11677      * @param {String/HTMLElement} form
11678      * @return {String}
11679      */
11680     serializeForm : function(form){
11681         return Roo.lib.Ajax.serializeForm(form);
11682     }
11683 });/*
11684  * Based on:
11685  * Ext JS Library 1.1.1
11686  * Copyright(c) 2006-2007, Ext JS, LLC.
11687  *
11688  * Originally Released Under LGPL - original licence link has changed is not relivant.
11689  *
11690  * Fork - LGPL
11691  * <script type="text/javascript">
11692  */
11693
11694  
11695 /**
11696  * @class Roo.UpdateManager
11697  * @extends Roo.util.Observable
11698  * Provides AJAX-style update for Element object.<br><br>
11699  * Usage:<br>
11700  * <pre><code>
11701  * // Get it from a Roo.Element object
11702  * var el = Roo.get("foo");
11703  * var mgr = el.getUpdateManager();
11704  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11705  * ...
11706  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11707  * <br>
11708  * // or directly (returns the same UpdateManager instance)
11709  * var mgr = new Roo.UpdateManager("myElementId");
11710  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11711  * mgr.on("update", myFcnNeedsToKnow);
11712  * <br>
11713    // short handed call directly from the element object
11714    Roo.get("foo").load({
11715         url: "bar.php",
11716         scripts:true,
11717         params: "for=bar",
11718         text: "Loading Foo..."
11719    });
11720  * </code></pre>
11721  * @constructor
11722  * Create new UpdateManager directly.
11723  * @param {String/HTMLElement/Roo.Element} el The element to update
11724  * @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).
11725  */
11726 Roo.UpdateManager = function(el, forceNew){
11727     el = Roo.get(el);
11728     if(!forceNew && el.updateManager){
11729         return el.updateManager;
11730     }
11731     /**
11732      * The Element object
11733      * @type Roo.Element
11734      */
11735     this.el = el;
11736     /**
11737      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11738      * @type String
11739      */
11740     this.defaultUrl = null;
11741
11742     this.addEvents({
11743         /**
11744          * @event beforeupdate
11745          * Fired before an update is made, return false from your handler and the update is cancelled.
11746          * @param {Roo.Element} el
11747          * @param {String/Object/Function} url
11748          * @param {String/Object} params
11749          */
11750         "beforeupdate": true,
11751         /**
11752          * @event update
11753          * Fired after successful update is made.
11754          * @param {Roo.Element} el
11755          * @param {Object} oResponseObject The response Object
11756          */
11757         "update": true,
11758         /**
11759          * @event failure
11760          * Fired on update failure.
11761          * @param {Roo.Element} el
11762          * @param {Object} oResponseObject The response Object
11763          */
11764         "failure": true
11765     });
11766     var d = Roo.UpdateManager.defaults;
11767     /**
11768      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11769      * @type String
11770      */
11771     this.sslBlankUrl = d.sslBlankUrl;
11772     /**
11773      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11774      * @type Boolean
11775      */
11776     this.disableCaching = d.disableCaching;
11777     /**
11778      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11779      * @type String
11780      */
11781     this.indicatorText = d.indicatorText;
11782     /**
11783      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11784      * @type String
11785      */
11786     this.showLoadIndicator = d.showLoadIndicator;
11787     /**
11788      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11789      * @type Number
11790      */
11791     this.timeout = d.timeout;
11792
11793     /**
11794      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11795      * @type Boolean
11796      */
11797     this.loadScripts = d.loadScripts;
11798
11799     /**
11800      * Transaction object of current executing transaction
11801      */
11802     this.transaction = null;
11803
11804     /**
11805      * @private
11806      */
11807     this.autoRefreshProcId = null;
11808     /**
11809      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11810      * @type Function
11811      */
11812     this.refreshDelegate = this.refresh.createDelegate(this);
11813     /**
11814      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11815      * @type Function
11816      */
11817     this.updateDelegate = this.update.createDelegate(this);
11818     /**
11819      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11820      * @type Function
11821      */
11822     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11823     /**
11824      * @private
11825      */
11826     this.successDelegate = this.processSuccess.createDelegate(this);
11827     /**
11828      * @private
11829      */
11830     this.failureDelegate = this.processFailure.createDelegate(this);
11831
11832     if(!this.renderer){
11833      /**
11834       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11835       */
11836     this.renderer = new Roo.UpdateManager.BasicRenderer();
11837     }
11838     
11839     Roo.UpdateManager.superclass.constructor.call(this);
11840 };
11841
11842 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11843     /**
11844      * Get the Element this UpdateManager is bound to
11845      * @return {Roo.Element} The element
11846      */
11847     getEl : function(){
11848         return this.el;
11849     },
11850     /**
11851      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11852      * @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:
11853 <pre><code>
11854 um.update({<br/>
11855     url: "your-url.php",<br/>
11856     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11857     callback: yourFunction,<br/>
11858     scope: yourObject, //(optional scope)  <br/>
11859     discardUrl: false, <br/>
11860     nocache: false,<br/>
11861     text: "Loading...",<br/>
11862     timeout: 30,<br/>
11863     scripts: false<br/>
11864 });
11865 </code></pre>
11866      * The only required property is url. The optional properties nocache, text and scripts
11867      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11868      * @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}
11869      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11870      * @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.
11871      */
11872     update : function(url, params, callback, discardUrl){
11873         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11874             var method = this.method,
11875                 cfg;
11876             if(typeof url == "object"){ // must be config object
11877                 cfg = url;
11878                 url = cfg.url;
11879                 params = params || cfg.params;
11880                 callback = callback || cfg.callback;
11881                 discardUrl = discardUrl || cfg.discardUrl;
11882                 if(callback && cfg.scope){
11883                     callback = callback.createDelegate(cfg.scope);
11884                 }
11885                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11886                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11887                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11888                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11889                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11890             }
11891             this.showLoading();
11892             if(!discardUrl){
11893                 this.defaultUrl = url;
11894             }
11895             if(typeof url == "function"){
11896                 url = url.call(this);
11897             }
11898
11899             method = method || (params ? "POST" : "GET");
11900             if(method == "GET"){
11901                 url = this.prepareUrl(url);
11902             }
11903
11904             var o = Roo.apply(cfg ||{}, {
11905                 url : url,
11906                 params: params,
11907                 success: this.successDelegate,
11908                 failure: this.failureDelegate,
11909                 callback: undefined,
11910                 timeout: (this.timeout*1000),
11911                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11912             });
11913             Roo.log("updated manager called with timeout of " + o.timeout);
11914             this.transaction = Roo.Ajax.request(o);
11915         }
11916     },
11917
11918     /**
11919      * 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.
11920      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11921      * @param {String/HTMLElement} form The form Id or form element
11922      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11923      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11924      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11925      */
11926     formUpdate : function(form, url, reset, callback){
11927         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11928             if(typeof url == "function"){
11929                 url = url.call(this);
11930             }
11931             form = Roo.getDom(form);
11932             this.transaction = Roo.Ajax.request({
11933                 form: form,
11934                 url:url,
11935                 success: this.successDelegate,
11936                 failure: this.failureDelegate,
11937                 timeout: (this.timeout*1000),
11938                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11939             });
11940             this.showLoading.defer(1, this);
11941         }
11942     },
11943
11944     /**
11945      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11946      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11947      */
11948     refresh : function(callback){
11949         if(this.defaultUrl == null){
11950             return;
11951         }
11952         this.update(this.defaultUrl, null, callback, true);
11953     },
11954
11955     /**
11956      * Set this element to auto refresh.
11957      * @param {Number} interval How often to update (in seconds).
11958      * @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)
11959      * @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}
11960      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11961      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11962      */
11963     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11964         if(refreshNow){
11965             this.update(url || this.defaultUrl, params, callback, true);
11966         }
11967         if(this.autoRefreshProcId){
11968             clearInterval(this.autoRefreshProcId);
11969         }
11970         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11971     },
11972
11973     /**
11974      * Stop auto refresh on this element.
11975      */
11976      stopAutoRefresh : function(){
11977         if(this.autoRefreshProcId){
11978             clearInterval(this.autoRefreshProcId);
11979             delete this.autoRefreshProcId;
11980         }
11981     },
11982
11983     isAutoRefreshing : function(){
11984        return this.autoRefreshProcId ? true : false;
11985     },
11986     /**
11987      * Called to update the element to "Loading" state. Override to perform custom action.
11988      */
11989     showLoading : function(){
11990         if(this.showLoadIndicator){
11991             this.el.update(this.indicatorText);
11992         }
11993     },
11994
11995     /**
11996      * Adds unique parameter to query string if disableCaching = true
11997      * @private
11998      */
11999     prepareUrl : function(url){
12000         if(this.disableCaching){
12001             var append = "_dc=" + (new Date().getTime());
12002             if(url.indexOf("?") !== -1){
12003                 url += "&" + append;
12004             }else{
12005                 url += "?" + append;
12006             }
12007         }
12008         return url;
12009     },
12010
12011     /**
12012      * @private
12013      */
12014     processSuccess : function(response){
12015         this.transaction = null;
12016         if(response.argument.form && response.argument.reset){
12017             try{ // put in try/catch since some older FF releases had problems with this
12018                 response.argument.form.reset();
12019             }catch(e){}
12020         }
12021         if(this.loadScripts){
12022             this.renderer.render(this.el, response, this,
12023                 this.updateComplete.createDelegate(this, [response]));
12024         }else{
12025             this.renderer.render(this.el, response, this);
12026             this.updateComplete(response);
12027         }
12028     },
12029
12030     updateComplete : function(response){
12031         this.fireEvent("update", this.el, response);
12032         if(typeof response.argument.callback == "function"){
12033             response.argument.callback(this.el, true, response);
12034         }
12035     },
12036
12037     /**
12038      * @private
12039      */
12040     processFailure : function(response){
12041         this.transaction = null;
12042         this.fireEvent("failure", this.el, response);
12043         if(typeof response.argument.callback == "function"){
12044             response.argument.callback(this.el, false, response);
12045         }
12046     },
12047
12048     /**
12049      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12050      * @param {Object} renderer The object implementing the render() method
12051      */
12052     setRenderer : function(renderer){
12053         this.renderer = renderer;
12054     },
12055
12056     getRenderer : function(){
12057        return this.renderer;
12058     },
12059
12060     /**
12061      * Set the defaultUrl used for updates
12062      * @param {String/Function} defaultUrl The url or a function to call to get the url
12063      */
12064     setDefaultUrl : function(defaultUrl){
12065         this.defaultUrl = defaultUrl;
12066     },
12067
12068     /**
12069      * Aborts the executing transaction
12070      */
12071     abort : function(){
12072         if(this.transaction){
12073             Roo.Ajax.abort(this.transaction);
12074         }
12075     },
12076
12077     /**
12078      * Returns true if an update is in progress
12079      * @return {Boolean}
12080      */
12081     isUpdating : function(){
12082         if(this.transaction){
12083             return Roo.Ajax.isLoading(this.transaction);
12084         }
12085         return false;
12086     }
12087 });
12088
12089 /**
12090  * @class Roo.UpdateManager.defaults
12091  * @static (not really - but it helps the doc tool)
12092  * The defaults collection enables customizing the default properties of UpdateManager
12093  */
12094    Roo.UpdateManager.defaults = {
12095        /**
12096          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12097          * @type Number
12098          */
12099          timeout : 30,
12100
12101          /**
12102          * True to process scripts by default (Defaults to false).
12103          * @type Boolean
12104          */
12105         loadScripts : false,
12106
12107         /**
12108         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12109         * @type String
12110         */
12111         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12112         /**
12113          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12114          * @type Boolean
12115          */
12116         disableCaching : false,
12117         /**
12118          * Whether to show indicatorText when loading (Defaults to true).
12119          * @type Boolean
12120          */
12121         showLoadIndicator : true,
12122         /**
12123          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12124          * @type String
12125          */
12126         indicatorText : '<div class="loading-indicator">Loading...</div>'
12127    };
12128
12129 /**
12130  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12131  *Usage:
12132  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12133  * @param {String/HTMLElement/Roo.Element} el The element to update
12134  * @param {String} url The url
12135  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12136  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12137  * @static
12138  * @deprecated
12139  * @member Roo.UpdateManager
12140  */
12141 Roo.UpdateManager.updateElement = function(el, url, params, options){
12142     var um = Roo.get(el, true).getUpdateManager();
12143     Roo.apply(um, options);
12144     um.update(url, params, options ? options.callback : null);
12145 };
12146 // alias for backwards compat
12147 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12148 /**
12149  * @class Roo.UpdateManager.BasicRenderer
12150  * Default Content renderer. Updates the elements innerHTML with the responseText.
12151  */
12152 Roo.UpdateManager.BasicRenderer = function(){};
12153
12154 Roo.UpdateManager.BasicRenderer.prototype = {
12155     /**
12156      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12157      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12158      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12159      * @param {Roo.Element} el The element being rendered
12160      * @param {Object} response The YUI Connect response object
12161      * @param {UpdateManager} updateManager The calling update manager
12162      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12163      */
12164      render : function(el, response, updateManager, callback){
12165         el.update(response.responseText, updateManager.loadScripts, callback);
12166     }
12167 };
12168 /*
12169  * Based on:
12170  * Roo JS
12171  * (c)) Alan Knowles
12172  * Licence : LGPL
12173  */
12174
12175
12176 /**
12177  * @class Roo.DomTemplate
12178  * @extends Roo.Template
12179  * An effort at a dom based template engine..
12180  *
12181  * Similar to XTemplate, except it uses dom parsing to create the template..
12182  *
12183  * Supported features:
12184  *
12185  *  Tags:
12186
12187 <pre><code>
12188       {a_variable} - output encoded.
12189       {a_variable.format:("Y-m-d")} - call a method on the variable
12190       {a_variable:raw} - unencoded output
12191       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12192       {a_variable:this.method_on_template(...)} - call a method on the template object.
12193  
12194 </code></pre>
12195  *  The tpl tag:
12196 <pre><code>
12197         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12198         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12199         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12200         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12201   
12202 </code></pre>
12203  *      
12204  */
12205 Roo.DomTemplate = function()
12206 {
12207      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12208      if (this.html) {
12209         this.compile();
12210      }
12211 };
12212
12213
12214 Roo.extend(Roo.DomTemplate, Roo.Template, {
12215     /**
12216      * id counter for sub templates.
12217      */
12218     id : 0,
12219     /**
12220      * flag to indicate if dom parser is inside a pre,
12221      * it will strip whitespace if not.
12222      */
12223     inPre : false,
12224     
12225     /**
12226      * The various sub templates
12227      */
12228     tpls : false,
12229     
12230     
12231     
12232     /**
12233      *
12234      * basic tag replacing syntax
12235      * WORD:WORD()
12236      *
12237      * // you can fake an object call by doing this
12238      *  x.t:(test,tesT) 
12239      * 
12240      */
12241     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12242     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12243     
12244     iterChild : function (node, method) {
12245         
12246         var oldPre = this.inPre;
12247         if (node.tagName == 'PRE') {
12248             this.inPre = true;
12249         }
12250         for( var i = 0; i < node.childNodes.length; i++) {
12251             method.call(this, node.childNodes[i]);
12252         }
12253         this.inPre = oldPre;
12254     },
12255     
12256     
12257     
12258     /**
12259      * compile the template
12260      *
12261      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12262      *
12263      */
12264     compile: function()
12265     {
12266         var s = this.html;
12267         
12268         // covert the html into DOM...
12269         var doc = false;
12270         var div =false;
12271         try {
12272             doc = document.implementation.createHTMLDocument("");
12273             doc.documentElement.innerHTML =   this.html  ;
12274             div = doc.documentElement;
12275         } catch (e) {
12276             // old IE... - nasty -- it causes all sorts of issues.. with
12277             // images getting pulled from server..
12278             div = document.createElement('div');
12279             div.innerHTML = this.html;
12280         }
12281         //doc.documentElement.innerHTML = htmlBody
12282          
12283         
12284         
12285         this.tpls = [];
12286         var _t = this;
12287         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12288         
12289         var tpls = this.tpls;
12290         
12291         // create a top level template from the snippet..
12292         
12293         //Roo.log(div.innerHTML);
12294         
12295         var tpl = {
12296             uid : 'master',
12297             id : this.id++,
12298             attr : false,
12299             value : false,
12300             body : div.innerHTML,
12301             
12302             forCall : false,
12303             execCall : false,
12304             dom : div,
12305             isTop : true
12306             
12307         };
12308         tpls.unshift(tpl);
12309         
12310         
12311         // compile them...
12312         this.tpls = [];
12313         Roo.each(tpls, function(tp){
12314             this.compileTpl(tp);
12315             this.tpls[tp.id] = tp;
12316         }, this);
12317         
12318         this.master = tpls[0];
12319         return this;
12320         
12321         
12322     },
12323     
12324     compileNode : function(node, istop) {
12325         // test for
12326         //Roo.log(node);
12327         
12328         
12329         // skip anything not a tag..
12330         if (node.nodeType != 1) {
12331             if (node.nodeType == 3 && !this.inPre) {
12332                 // reduce white space..
12333                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12334                 
12335             }
12336             return;
12337         }
12338         
12339         var tpl = {
12340             uid : false,
12341             id : false,
12342             attr : false,
12343             value : false,
12344             body : '',
12345             
12346             forCall : false,
12347             execCall : false,
12348             dom : false,
12349             isTop : istop
12350             
12351             
12352         };
12353         
12354         
12355         switch(true) {
12356             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12357             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12358             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12359             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12360             // no default..
12361         }
12362         
12363         
12364         if (!tpl.attr) {
12365             // just itterate children..
12366             this.iterChild(node,this.compileNode);
12367             return;
12368         }
12369         tpl.uid = this.id++;
12370         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12371         node.removeAttribute('roo-'+ tpl.attr);
12372         if (tpl.attr != 'name') {
12373             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12374             node.parentNode.replaceChild(placeholder,  node);
12375         } else {
12376             
12377             var placeholder =  document.createElement('span');
12378             placeholder.className = 'roo-tpl-' + tpl.value;
12379             node.parentNode.replaceChild(placeholder,  node);
12380         }
12381         
12382         // parent now sees '{domtplXXXX}
12383         this.iterChild(node,this.compileNode);
12384         
12385         // we should now have node body...
12386         var div = document.createElement('div');
12387         div.appendChild(node);
12388         tpl.dom = node;
12389         // this has the unfortunate side effect of converting tagged attributes
12390         // eg. href="{...}" into %7C...%7D
12391         // this has been fixed by searching for those combo's although it's a bit hacky..
12392         
12393         
12394         tpl.body = div.innerHTML;
12395         
12396         
12397          
12398         tpl.id = tpl.uid;
12399         switch(tpl.attr) {
12400             case 'for' :
12401                 switch (tpl.value) {
12402                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12403                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12404                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12405                 }
12406                 break;
12407             
12408             case 'exec':
12409                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12410                 break;
12411             
12412             case 'if':     
12413                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12414                 break;
12415             
12416             case 'name':
12417                 tpl.id  = tpl.value; // replace non characters???
12418                 break;
12419             
12420         }
12421         
12422         
12423         this.tpls.push(tpl);
12424         
12425         
12426         
12427     },
12428     
12429     
12430     
12431     
12432     /**
12433      * Compile a segment of the template into a 'sub-template'
12434      *
12435      * 
12436      * 
12437      *
12438      */
12439     compileTpl : function(tpl)
12440     {
12441         var fm = Roo.util.Format;
12442         var useF = this.disableFormats !== true;
12443         
12444         var sep = Roo.isGecko ? "+\n" : ",\n";
12445         
12446         var undef = function(str) {
12447             Roo.debug && Roo.log("Property not found :"  + str);
12448             return '';
12449         };
12450           
12451         //Roo.log(tpl.body);
12452         
12453         
12454         
12455         var fn = function(m, lbrace, name, format, args)
12456         {
12457             //Roo.log("ARGS");
12458             //Roo.log(arguments);
12459             args = args ? args.replace(/\\'/g,"'") : args;
12460             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12461             if (typeof(format) == 'undefined') {
12462                 format =  'htmlEncode'; 
12463             }
12464             if (format == 'raw' ) {
12465                 format = false;
12466             }
12467             
12468             if(name.substr(0, 6) == 'domtpl'){
12469                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12470             }
12471             
12472             // build an array of options to determine if value is undefined..
12473             
12474             // basically get 'xxxx.yyyy' then do
12475             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12476             //    (function () { Roo.log("Property not found"); return ''; })() :
12477             //    ......
12478             
12479             var udef_ar = [];
12480             var lookfor = '';
12481             Roo.each(name.split('.'), function(st) {
12482                 lookfor += (lookfor.length ? '.': '') + st;
12483                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12484             });
12485             
12486             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12487             
12488             
12489             if(format && useF){
12490                 
12491                 args = args ? ',' + args : "";
12492                  
12493                 if(format.substr(0, 5) != "this."){
12494                     format = "fm." + format + '(';
12495                 }else{
12496                     format = 'this.call("'+ format.substr(5) + '", ';
12497                     args = ", values";
12498                 }
12499                 
12500                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12501             }
12502              
12503             if (args && args.length) {
12504                 // called with xxyx.yuu:(test,test)
12505                 // change to ()
12506                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12507             }
12508             // raw.. - :raw modifier..
12509             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12510             
12511         };
12512         var body;
12513         // branched to use + in gecko and [].join() in others
12514         if(Roo.isGecko){
12515             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12516                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12517                     "';};};";
12518         }else{
12519             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12520             body.push(tpl.body.replace(/(\r\n|\n)/g,
12521                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12522             body.push("'].join('');};};");
12523             body = body.join('');
12524         }
12525         
12526         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12527        
12528         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12529         eval(body);
12530         
12531         return this;
12532     },
12533      
12534     /**
12535      * same as applyTemplate, except it's done to one of the subTemplates
12536      * when using named templates, you can do:
12537      *
12538      * var str = pl.applySubTemplate('your-name', values);
12539      *
12540      * 
12541      * @param {Number} id of the template
12542      * @param {Object} values to apply to template
12543      * @param {Object} parent (normaly the instance of this object)
12544      */
12545     applySubTemplate : function(id, values, parent)
12546     {
12547         
12548         
12549         var t = this.tpls[id];
12550         
12551         
12552         try { 
12553             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12554                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12555                 return '';
12556             }
12557         } catch(e) {
12558             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12559             Roo.log(values);
12560           
12561             return '';
12562         }
12563         try { 
12564             
12565             if(t.execCall && t.execCall.call(this, values, parent)){
12566                 return '';
12567             }
12568         } catch(e) {
12569             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12570             Roo.log(values);
12571             return '';
12572         }
12573         
12574         try {
12575             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12576             parent = t.target ? values : parent;
12577             if(t.forCall && vs instanceof Array){
12578                 var buf = [];
12579                 for(var i = 0, len = vs.length; i < len; i++){
12580                     try {
12581                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12582                     } catch (e) {
12583                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12584                         Roo.log(e.body);
12585                         //Roo.log(t.compiled);
12586                         Roo.log(vs[i]);
12587                     }   
12588                 }
12589                 return buf.join('');
12590             }
12591         } catch (e) {
12592             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12593             Roo.log(values);
12594             return '';
12595         }
12596         try {
12597             return t.compiled.call(this, vs, parent);
12598         } catch (e) {
12599             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12600             Roo.log(e.body);
12601             //Roo.log(t.compiled);
12602             Roo.log(values);
12603             return '';
12604         }
12605     },
12606
12607    
12608
12609     applyTemplate : function(values){
12610         return this.master.compiled.call(this, values, {});
12611         //var s = this.subs;
12612     },
12613
12614     apply : function(){
12615         return this.applyTemplate.apply(this, arguments);
12616     }
12617
12618  });
12619
12620 Roo.DomTemplate.from = function(el){
12621     el = Roo.getDom(el);
12622     return new Roo.Domtemplate(el.value || el.innerHTML);
12623 };/*
12624  * Based on:
12625  * Ext JS Library 1.1.1
12626  * Copyright(c) 2006-2007, Ext JS, LLC.
12627  *
12628  * Originally Released Under LGPL - original licence link has changed is not relivant.
12629  *
12630  * Fork - LGPL
12631  * <script type="text/javascript">
12632  */
12633
12634 /**
12635  * @class Roo.util.DelayedTask
12636  * Provides a convenient method of performing setTimeout where a new
12637  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12638  * You can use this class to buffer
12639  * the keypress events for a certain number of milliseconds, and perform only if they stop
12640  * for that amount of time.
12641  * @constructor The parameters to this constructor serve as defaults and are not required.
12642  * @param {Function} fn (optional) The default function to timeout
12643  * @param {Object} scope (optional) The default scope of that timeout
12644  * @param {Array} args (optional) The default Array of arguments
12645  */
12646 Roo.util.DelayedTask = function(fn, scope, args){
12647     var id = null, d, t;
12648
12649     var call = function(){
12650         var now = new Date().getTime();
12651         if(now - t >= d){
12652             clearInterval(id);
12653             id = null;
12654             fn.apply(scope, args || []);
12655         }
12656     };
12657     /**
12658      * Cancels any pending timeout and queues a new one
12659      * @param {Number} delay The milliseconds to delay
12660      * @param {Function} newFn (optional) Overrides function passed to constructor
12661      * @param {Object} newScope (optional) Overrides scope passed to constructor
12662      * @param {Array} newArgs (optional) Overrides args passed to constructor
12663      */
12664     this.delay = function(delay, newFn, newScope, newArgs){
12665         if(id && delay != d){
12666             this.cancel();
12667         }
12668         d = delay;
12669         t = new Date().getTime();
12670         fn = newFn || fn;
12671         scope = newScope || scope;
12672         args = newArgs || args;
12673         if(!id){
12674             id = setInterval(call, d);
12675         }
12676     };
12677
12678     /**
12679      * Cancel the last queued timeout
12680      */
12681     this.cancel = function(){
12682         if(id){
12683             clearInterval(id);
12684             id = null;
12685         }
12686     };
12687 };/*
12688  * Based on:
12689  * Ext JS Library 1.1.1
12690  * Copyright(c) 2006-2007, Ext JS, LLC.
12691  *
12692  * Originally Released Under LGPL - original licence link has changed is not relivant.
12693  *
12694  * Fork - LGPL
12695  * <script type="text/javascript">
12696  */
12697  
12698  
12699 Roo.util.TaskRunner = function(interval){
12700     interval = interval || 10;
12701     var tasks = [], removeQueue = [];
12702     var id = 0;
12703     var running = false;
12704
12705     var stopThread = function(){
12706         running = false;
12707         clearInterval(id);
12708         id = 0;
12709     };
12710
12711     var startThread = function(){
12712         if(!running){
12713             running = true;
12714             id = setInterval(runTasks, interval);
12715         }
12716     };
12717
12718     var removeTask = function(task){
12719         removeQueue.push(task);
12720         if(task.onStop){
12721             task.onStop();
12722         }
12723     };
12724
12725     var runTasks = function(){
12726         if(removeQueue.length > 0){
12727             for(var i = 0, len = removeQueue.length; i < len; i++){
12728                 tasks.remove(removeQueue[i]);
12729             }
12730             removeQueue = [];
12731             if(tasks.length < 1){
12732                 stopThread();
12733                 return;
12734             }
12735         }
12736         var now = new Date().getTime();
12737         for(var i = 0, len = tasks.length; i < len; ++i){
12738             var t = tasks[i];
12739             var itime = now - t.taskRunTime;
12740             if(t.interval <= itime){
12741                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12742                 t.taskRunTime = now;
12743                 if(rt === false || t.taskRunCount === t.repeat){
12744                     removeTask(t);
12745                     return;
12746                 }
12747             }
12748             if(t.duration && t.duration <= (now - t.taskStartTime)){
12749                 removeTask(t);
12750             }
12751         }
12752     };
12753
12754     /**
12755      * Queues a new task.
12756      * @param {Object} task
12757      */
12758     this.start = function(task){
12759         tasks.push(task);
12760         task.taskStartTime = new Date().getTime();
12761         task.taskRunTime = 0;
12762         task.taskRunCount = 0;
12763         startThread();
12764         return task;
12765     };
12766
12767     this.stop = function(task){
12768         removeTask(task);
12769         return task;
12770     };
12771
12772     this.stopAll = function(){
12773         stopThread();
12774         for(var i = 0, len = tasks.length; i < len; i++){
12775             if(tasks[i].onStop){
12776                 tasks[i].onStop();
12777             }
12778         }
12779         tasks = [];
12780         removeQueue = [];
12781     };
12782 };
12783
12784 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12785  * Based on:
12786  * Ext JS Library 1.1.1
12787  * Copyright(c) 2006-2007, Ext JS, LLC.
12788  *
12789  * Originally Released Under LGPL - original licence link has changed is not relivant.
12790  *
12791  * Fork - LGPL
12792  * <script type="text/javascript">
12793  */
12794
12795  
12796 /**
12797  * @class Roo.util.MixedCollection
12798  * @extends Roo.util.Observable
12799  * A Collection class that maintains both numeric indexes and keys and exposes events.
12800  * @constructor
12801  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12802  * collection (defaults to false)
12803  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12804  * and return the key value for that item.  This is used when available to look up the key on items that
12805  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12806  * equivalent to providing an implementation for the {@link #getKey} method.
12807  */
12808 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12809     this.items = [];
12810     this.map = {};
12811     this.keys = [];
12812     this.length = 0;
12813     this.addEvents({
12814         /**
12815          * @event clear
12816          * Fires when the collection is cleared.
12817          */
12818         "clear" : true,
12819         /**
12820          * @event add
12821          * Fires when an item is added to the collection.
12822          * @param {Number} index The index at which the item was added.
12823          * @param {Object} o The item added.
12824          * @param {String} key The key associated with the added item.
12825          */
12826         "add" : true,
12827         /**
12828          * @event replace
12829          * Fires when an item is replaced in the collection.
12830          * @param {String} key he key associated with the new added.
12831          * @param {Object} old The item being replaced.
12832          * @param {Object} new The new item.
12833          */
12834         "replace" : true,
12835         /**
12836          * @event remove
12837          * Fires when an item is removed from the collection.
12838          * @param {Object} o The item being removed.
12839          * @param {String} key (optional) The key associated with the removed item.
12840          */
12841         "remove" : true,
12842         "sort" : true
12843     });
12844     this.allowFunctions = allowFunctions === true;
12845     if(keyFn){
12846         this.getKey = keyFn;
12847     }
12848     Roo.util.MixedCollection.superclass.constructor.call(this);
12849 };
12850
12851 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12852     allowFunctions : false,
12853     
12854 /**
12855  * Adds an item to the collection.
12856  * @param {String} key The key to associate with the item
12857  * @param {Object} o The item to add.
12858  * @return {Object} The item added.
12859  */
12860     add : function(key, o){
12861         if(arguments.length == 1){
12862             o = arguments[0];
12863             key = this.getKey(o);
12864         }
12865         if(typeof key == "undefined" || key === null){
12866             this.length++;
12867             this.items.push(o);
12868             this.keys.push(null);
12869         }else{
12870             var old = this.map[key];
12871             if(old){
12872                 return this.replace(key, o);
12873             }
12874             this.length++;
12875             this.items.push(o);
12876             this.map[key] = o;
12877             this.keys.push(key);
12878         }
12879         this.fireEvent("add", this.length-1, o, key);
12880         return o;
12881     },
12882        
12883 /**
12884   * MixedCollection has a generic way to fetch keys if you implement getKey.
12885 <pre><code>
12886 // normal way
12887 var mc = new Roo.util.MixedCollection();
12888 mc.add(someEl.dom.id, someEl);
12889 mc.add(otherEl.dom.id, otherEl);
12890 //and so on
12891
12892 // using getKey
12893 var mc = new Roo.util.MixedCollection();
12894 mc.getKey = function(el){
12895    return el.dom.id;
12896 };
12897 mc.add(someEl);
12898 mc.add(otherEl);
12899
12900 // or via the constructor
12901 var mc = new Roo.util.MixedCollection(false, function(el){
12902    return el.dom.id;
12903 });
12904 mc.add(someEl);
12905 mc.add(otherEl);
12906 </code></pre>
12907  * @param o {Object} The item for which to find the key.
12908  * @return {Object} The key for the passed item.
12909  */
12910     getKey : function(o){
12911          return o.id; 
12912     },
12913    
12914 /**
12915  * Replaces an item in the collection.
12916  * @param {String} key The key associated with the item to replace, or the item to replace.
12917  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12918  * @return {Object}  The new item.
12919  */
12920     replace : function(key, o){
12921         if(arguments.length == 1){
12922             o = arguments[0];
12923             key = this.getKey(o);
12924         }
12925         var old = this.item(key);
12926         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12927              return this.add(key, o);
12928         }
12929         var index = this.indexOfKey(key);
12930         this.items[index] = o;
12931         this.map[key] = o;
12932         this.fireEvent("replace", key, old, o);
12933         return o;
12934     },
12935    
12936 /**
12937  * Adds all elements of an Array or an Object to the collection.
12938  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12939  * an Array of values, each of which are added to the collection.
12940  */
12941     addAll : function(objs){
12942         if(arguments.length > 1 || objs instanceof Array){
12943             var args = arguments.length > 1 ? arguments : objs;
12944             for(var i = 0, len = args.length; i < len; i++){
12945                 this.add(args[i]);
12946             }
12947         }else{
12948             for(var key in objs){
12949                 if(this.allowFunctions || typeof objs[key] != "function"){
12950                     this.add(key, objs[key]);
12951                 }
12952             }
12953         }
12954     },
12955    
12956 /**
12957  * Executes the specified function once for every item in the collection, passing each
12958  * item as the first and only parameter. returning false from the function will stop the iteration.
12959  * @param {Function} fn The function to execute for each item.
12960  * @param {Object} scope (optional) The scope in which to execute the function.
12961  */
12962     each : function(fn, scope){
12963         var items = [].concat(this.items); // each safe for removal
12964         for(var i = 0, len = items.length; i < len; i++){
12965             if(fn.call(scope || items[i], items[i], i, len) === false){
12966                 break;
12967             }
12968         }
12969     },
12970    
12971 /**
12972  * Executes the specified function once for every key in the collection, passing each
12973  * key, and its associated item as the first two parameters.
12974  * @param {Function} fn The function to execute for each item.
12975  * @param {Object} scope (optional) The scope in which to execute the function.
12976  */
12977     eachKey : function(fn, scope){
12978         for(var i = 0, len = this.keys.length; i < len; i++){
12979             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12980         }
12981     },
12982    
12983 /**
12984  * Returns the first item in the collection which elicits a true return value from the
12985  * passed selection function.
12986  * @param {Function} fn The selection function to execute for each item.
12987  * @param {Object} scope (optional) The scope in which to execute the function.
12988  * @return {Object} The first item in the collection which returned true from the selection function.
12989  */
12990     find : function(fn, scope){
12991         for(var i = 0, len = this.items.length; i < len; i++){
12992             if(fn.call(scope || window, this.items[i], this.keys[i])){
12993                 return this.items[i];
12994             }
12995         }
12996         return null;
12997     },
12998    
12999 /**
13000  * Inserts an item at the specified index in the collection.
13001  * @param {Number} index The index to insert the item at.
13002  * @param {String} key The key to associate with the new item, or the item itself.
13003  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13004  * @return {Object} The item inserted.
13005  */
13006     insert : function(index, key, o){
13007         if(arguments.length == 2){
13008             o = arguments[1];
13009             key = this.getKey(o);
13010         }
13011         if(index >= this.length){
13012             return this.add(key, o);
13013         }
13014         this.length++;
13015         this.items.splice(index, 0, o);
13016         if(typeof key != "undefined" && key != null){
13017             this.map[key] = o;
13018         }
13019         this.keys.splice(index, 0, key);
13020         this.fireEvent("add", index, o, key);
13021         return o;
13022     },
13023    
13024 /**
13025  * Removed an item from the collection.
13026  * @param {Object} o The item to remove.
13027  * @return {Object} The item removed.
13028  */
13029     remove : function(o){
13030         return this.removeAt(this.indexOf(o));
13031     },
13032    
13033 /**
13034  * Remove an item from a specified index in the collection.
13035  * @param {Number} index The index within the collection of the item to remove.
13036  */
13037     removeAt : function(index){
13038         if(index < this.length && index >= 0){
13039             this.length--;
13040             var o = this.items[index];
13041             this.items.splice(index, 1);
13042             var key = this.keys[index];
13043             if(typeof key != "undefined"){
13044                 delete this.map[key];
13045             }
13046             this.keys.splice(index, 1);
13047             this.fireEvent("remove", o, key);
13048         }
13049     },
13050    
13051 /**
13052  * Removed an item associated with the passed key fom the collection.
13053  * @param {String} key The key of the item to remove.
13054  */
13055     removeKey : function(key){
13056         return this.removeAt(this.indexOfKey(key));
13057     },
13058    
13059 /**
13060  * Returns the number of items in the collection.
13061  * @return {Number} the number of items in the collection.
13062  */
13063     getCount : function(){
13064         return this.length; 
13065     },
13066    
13067 /**
13068  * Returns index within the collection of the passed Object.
13069  * @param {Object} o The item to find the index of.
13070  * @return {Number} index of the item.
13071  */
13072     indexOf : function(o){
13073         if(!this.items.indexOf){
13074             for(var i = 0, len = this.items.length; i < len; i++){
13075                 if(this.items[i] == o) return i;
13076             }
13077             return -1;
13078         }else{
13079             return this.items.indexOf(o);
13080         }
13081     },
13082    
13083 /**
13084  * Returns index within the collection of the passed key.
13085  * @param {String} key The key to find the index of.
13086  * @return {Number} index of the key.
13087  */
13088     indexOfKey : function(key){
13089         if(!this.keys.indexOf){
13090             for(var i = 0, len = this.keys.length; i < len; i++){
13091                 if(this.keys[i] == key) return i;
13092             }
13093             return -1;
13094         }else{
13095             return this.keys.indexOf(key);
13096         }
13097     },
13098    
13099 /**
13100  * Returns the item associated with the passed key OR index. Key has priority over index.
13101  * @param {String/Number} key The key or index of the item.
13102  * @return {Object} The item associated with the passed key.
13103  */
13104     item : function(key){
13105         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13106         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13107     },
13108     
13109 /**
13110  * Returns the item at the specified index.
13111  * @param {Number} index The index of the item.
13112  * @return {Object}
13113  */
13114     itemAt : function(index){
13115         return this.items[index];
13116     },
13117     
13118 /**
13119  * Returns the item associated with the passed key.
13120  * @param {String/Number} key The key of the item.
13121  * @return {Object} The item associated with the passed key.
13122  */
13123     key : function(key){
13124         return this.map[key];
13125     },
13126    
13127 /**
13128  * Returns true if the collection contains the passed Object as an item.
13129  * @param {Object} o  The Object to look for in the collection.
13130  * @return {Boolean} True if the collection contains the Object as an item.
13131  */
13132     contains : function(o){
13133         return this.indexOf(o) != -1;
13134     },
13135    
13136 /**
13137  * Returns true if the collection contains the passed Object as a key.
13138  * @param {String} key The key to look for in the collection.
13139  * @return {Boolean} True if the collection contains the Object as a key.
13140  */
13141     containsKey : function(key){
13142         return typeof this.map[key] != "undefined";
13143     },
13144    
13145 /**
13146  * Removes all items from the collection.
13147  */
13148     clear : function(){
13149         this.length = 0;
13150         this.items = [];
13151         this.keys = [];
13152         this.map = {};
13153         this.fireEvent("clear");
13154     },
13155    
13156 /**
13157  * Returns the first item in the collection.
13158  * @return {Object} the first item in the collection..
13159  */
13160     first : function(){
13161         return this.items[0]; 
13162     },
13163    
13164 /**
13165  * Returns the last item in the collection.
13166  * @return {Object} the last item in the collection..
13167  */
13168     last : function(){
13169         return this.items[this.length-1];   
13170     },
13171     
13172     _sort : function(property, dir, fn){
13173         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13174         fn = fn || function(a, b){
13175             return a-b;
13176         };
13177         var c = [], k = this.keys, items = this.items;
13178         for(var i = 0, len = items.length; i < len; i++){
13179             c[c.length] = {key: k[i], value: items[i], index: i};
13180         }
13181         c.sort(function(a, b){
13182             var v = fn(a[property], b[property]) * dsc;
13183             if(v == 0){
13184                 v = (a.index < b.index ? -1 : 1);
13185             }
13186             return v;
13187         });
13188         for(var i = 0, len = c.length; i < len; i++){
13189             items[i] = c[i].value;
13190             k[i] = c[i].key;
13191         }
13192         this.fireEvent("sort", this);
13193     },
13194     
13195     /**
13196      * Sorts this collection with the passed comparison function
13197      * @param {String} direction (optional) "ASC" or "DESC"
13198      * @param {Function} fn (optional) comparison function
13199      */
13200     sort : function(dir, fn){
13201         this._sort("value", dir, fn);
13202     },
13203     
13204     /**
13205      * Sorts this collection by keys
13206      * @param {String} direction (optional) "ASC" or "DESC"
13207      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13208      */
13209     keySort : function(dir, fn){
13210         this._sort("key", dir, fn || function(a, b){
13211             return String(a).toUpperCase()-String(b).toUpperCase();
13212         });
13213     },
13214     
13215     /**
13216      * Returns a range of items in this collection
13217      * @param {Number} startIndex (optional) defaults to 0
13218      * @param {Number} endIndex (optional) default to the last item
13219      * @return {Array} An array of items
13220      */
13221     getRange : function(start, end){
13222         var items = this.items;
13223         if(items.length < 1){
13224             return [];
13225         }
13226         start = start || 0;
13227         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13228         var r = [];
13229         if(start <= end){
13230             for(var i = start; i <= end; i++) {
13231                     r[r.length] = items[i];
13232             }
13233         }else{
13234             for(var i = start; i >= end; i--) {
13235                     r[r.length] = items[i];
13236             }
13237         }
13238         return r;
13239     },
13240         
13241     /**
13242      * Filter the <i>objects</i> in this collection by a specific property. 
13243      * Returns a new collection that has been filtered.
13244      * @param {String} property A property on your objects
13245      * @param {String/RegExp} value Either string that the property values 
13246      * should start with or a RegExp to test against the property
13247      * @return {MixedCollection} The new filtered collection
13248      */
13249     filter : function(property, value){
13250         if(!value.exec){ // not a regex
13251             value = String(value);
13252             if(value.length == 0){
13253                 return this.clone();
13254             }
13255             value = new RegExp("^" + Roo.escapeRe(value), "i");
13256         }
13257         return this.filterBy(function(o){
13258             return o && value.test(o[property]);
13259         });
13260         },
13261     
13262     /**
13263      * Filter by a function. * Returns a new collection that has been filtered.
13264      * The passed function will be called with each 
13265      * object in the collection. If the function returns true, the value is included 
13266      * otherwise it is filtered.
13267      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13268      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13269      * @return {MixedCollection} The new filtered collection
13270      */
13271     filterBy : function(fn, scope){
13272         var r = new Roo.util.MixedCollection();
13273         r.getKey = this.getKey;
13274         var k = this.keys, it = this.items;
13275         for(var i = 0, len = it.length; i < len; i++){
13276             if(fn.call(scope||this, it[i], k[i])){
13277                                 r.add(k[i], it[i]);
13278                         }
13279         }
13280         return r;
13281     },
13282     
13283     /**
13284      * Creates a duplicate of this collection
13285      * @return {MixedCollection}
13286      */
13287     clone : function(){
13288         var r = new Roo.util.MixedCollection();
13289         var k = this.keys, it = this.items;
13290         for(var i = 0, len = it.length; i < len; i++){
13291             r.add(k[i], it[i]);
13292         }
13293         r.getKey = this.getKey;
13294         return r;
13295     }
13296 });
13297 /**
13298  * Returns the item associated with the passed key or index.
13299  * @method
13300  * @param {String/Number} key The key or index of the item.
13301  * @return {Object} The item associated with the passed key.
13302  */
13303 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13304  * Based on:
13305  * Ext JS Library 1.1.1
13306  * Copyright(c) 2006-2007, Ext JS, LLC.
13307  *
13308  * Originally Released Under LGPL - original licence link has changed is not relivant.
13309  *
13310  * Fork - LGPL
13311  * <script type="text/javascript">
13312  */
13313 /**
13314  * @class Roo.util.JSON
13315  * Modified version of Douglas Crockford"s json.js that doesn"t
13316  * mess with the Object prototype 
13317  * http://www.json.org/js.html
13318  * @singleton
13319  */
13320 Roo.util.JSON = new (function(){
13321     var useHasOwn = {}.hasOwnProperty ? true : false;
13322     
13323     // crashes Safari in some instances
13324     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13325     
13326     var pad = function(n) {
13327         return n < 10 ? "0" + n : n;
13328     };
13329     
13330     var m = {
13331         "\b": '\\b',
13332         "\t": '\\t',
13333         "\n": '\\n',
13334         "\f": '\\f',
13335         "\r": '\\r',
13336         '"' : '\\"',
13337         "\\": '\\\\'
13338     };
13339
13340     var encodeString = function(s){
13341         if (/["\\\x00-\x1f]/.test(s)) {
13342             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13343                 var c = m[b];
13344                 if(c){
13345                     return c;
13346                 }
13347                 c = b.charCodeAt();
13348                 return "\\u00" +
13349                     Math.floor(c / 16).toString(16) +
13350                     (c % 16).toString(16);
13351             }) + '"';
13352         }
13353         return '"' + s + '"';
13354     };
13355     
13356     var encodeArray = function(o){
13357         var a = ["["], b, i, l = o.length, v;
13358             for (i = 0; i < l; i += 1) {
13359                 v = o[i];
13360                 switch (typeof v) {
13361                     case "undefined":
13362                     case "function":
13363                     case "unknown":
13364                         break;
13365                     default:
13366                         if (b) {
13367                             a.push(',');
13368                         }
13369                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13370                         b = true;
13371                 }
13372             }
13373             a.push("]");
13374             return a.join("");
13375     };
13376     
13377     var encodeDate = function(o){
13378         return '"' + o.getFullYear() + "-" +
13379                 pad(o.getMonth() + 1) + "-" +
13380                 pad(o.getDate()) + "T" +
13381                 pad(o.getHours()) + ":" +
13382                 pad(o.getMinutes()) + ":" +
13383                 pad(o.getSeconds()) + '"';
13384     };
13385     
13386     /**
13387      * Encodes an Object, Array or other value
13388      * @param {Mixed} o The variable to encode
13389      * @return {String} The JSON string
13390      */
13391     this.encode = function(o)
13392     {
13393         // should this be extended to fully wrap stringify..
13394         
13395         if(typeof o == "undefined" || o === null){
13396             return "null";
13397         }else if(o instanceof Array){
13398             return encodeArray(o);
13399         }else if(o instanceof Date){
13400             return encodeDate(o);
13401         }else if(typeof o == "string"){
13402             return encodeString(o);
13403         }else if(typeof o == "number"){
13404             return isFinite(o) ? String(o) : "null";
13405         }else if(typeof o == "boolean"){
13406             return String(o);
13407         }else {
13408             var a = ["{"], b, i, v;
13409             for (i in o) {
13410                 if(!useHasOwn || o.hasOwnProperty(i)) {
13411                     v = o[i];
13412                     switch (typeof v) {
13413                     case "undefined":
13414                     case "function":
13415                     case "unknown":
13416                         break;
13417                     default:
13418                         if(b){
13419                             a.push(',');
13420                         }
13421                         a.push(this.encode(i), ":",
13422                                 v === null ? "null" : this.encode(v));
13423                         b = true;
13424                     }
13425                 }
13426             }
13427             a.push("}");
13428             return a.join("");
13429         }
13430     };
13431     
13432     /**
13433      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13434      * @param {String} json The JSON string
13435      * @return {Object} The resulting object
13436      */
13437     this.decode = function(json){
13438         
13439         return  /** eval:var:json */ eval("(" + json + ')');
13440     };
13441 })();
13442 /** 
13443  * Shorthand for {@link Roo.util.JSON#encode}
13444  * @member Roo encode 
13445  * @method */
13446 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13447 /** 
13448  * Shorthand for {@link Roo.util.JSON#decode}
13449  * @member Roo decode 
13450  * @method */
13451 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13452 /*
13453  * Based on:
13454  * Ext JS Library 1.1.1
13455  * Copyright(c) 2006-2007, Ext JS, LLC.
13456  *
13457  * Originally Released Under LGPL - original licence link has changed is not relivant.
13458  *
13459  * Fork - LGPL
13460  * <script type="text/javascript">
13461  */
13462  
13463 /**
13464  * @class Roo.util.Format
13465  * Reusable data formatting functions
13466  * @singleton
13467  */
13468 Roo.util.Format = function(){
13469     var trimRe = /^\s+|\s+$/g;
13470     return {
13471         /**
13472          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13473          * @param {String} value The string to truncate
13474          * @param {Number} length The maximum length to allow before truncating
13475          * @return {String} The converted text
13476          */
13477         ellipsis : function(value, len){
13478             if(value && value.length > len){
13479                 return value.substr(0, len-3)+"...";
13480             }
13481             return value;
13482         },
13483
13484         /**
13485          * Checks a reference and converts it to empty string if it is undefined
13486          * @param {Mixed} value Reference to check
13487          * @return {Mixed} Empty string if converted, otherwise the original value
13488          */
13489         undef : function(value){
13490             return typeof value != "undefined" ? value : "";
13491         },
13492
13493         /**
13494          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13495          * @param {String} value The string to encode
13496          * @return {String} The encoded text
13497          */
13498         htmlEncode : function(value){
13499             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13500         },
13501
13502         /**
13503          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13504          * @param {String} value The string to decode
13505          * @return {String} The decoded text
13506          */
13507         htmlDecode : function(value){
13508             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13509         },
13510
13511         /**
13512          * Trims any whitespace from either side of a string
13513          * @param {String} value The text to trim
13514          * @return {String} The trimmed text
13515          */
13516         trim : function(value){
13517             return String(value).replace(trimRe, "");
13518         },
13519
13520         /**
13521          * Returns a substring from within an original string
13522          * @param {String} value The original text
13523          * @param {Number} start The start index of the substring
13524          * @param {Number} length The length of the substring
13525          * @return {String} The substring
13526          */
13527         substr : function(value, start, length){
13528             return String(value).substr(start, length);
13529         },
13530
13531         /**
13532          * Converts a string to all lower case letters
13533          * @param {String} value The text to convert
13534          * @return {String} The converted text
13535          */
13536         lowercase : function(value){
13537             return String(value).toLowerCase();
13538         },
13539
13540         /**
13541          * Converts a string to all upper case letters
13542          * @param {String} value The text to convert
13543          * @return {String} The converted text
13544          */
13545         uppercase : function(value){
13546             return String(value).toUpperCase();
13547         },
13548
13549         /**
13550          * Converts the first character only of a string to upper case
13551          * @param {String} value The text to convert
13552          * @return {String} The converted text
13553          */
13554         capitalize : function(value){
13555             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13556         },
13557
13558         // private
13559         call : function(value, fn){
13560             if(arguments.length > 2){
13561                 var args = Array.prototype.slice.call(arguments, 2);
13562                 args.unshift(value);
13563                  
13564                 return /** eval:var:value */  eval(fn).apply(window, args);
13565             }else{
13566                 /** eval:var:value */
13567                 return /** eval:var:value */ eval(fn).call(window, value);
13568             }
13569         },
13570
13571        
13572         /**
13573          * safer version of Math.toFixed..??/
13574          * @param {Number/String} value The numeric value to format
13575          * @param {Number/String} value Decimal places 
13576          * @return {String} The formatted currency string
13577          */
13578         toFixed : function(v, n)
13579         {
13580             // why not use to fixed - precision is buggered???
13581             if (!n) {
13582                 return Math.round(v-0);
13583             }
13584             var fact = Math.pow(10,n+1);
13585             v = (Math.round((v-0)*fact))/fact;
13586             var z = (''+fact).substring(2);
13587             if (v == Math.floor(v)) {
13588                 return Math.floor(v) + '.' + z;
13589             }
13590             
13591             // now just padd decimals..
13592             var ps = String(v).split('.');
13593             var fd = (ps[1] + z);
13594             var r = fd.substring(0,n); 
13595             var rm = fd.substring(n); 
13596             if (rm < 5) {
13597                 return ps[0] + '.' + r;
13598             }
13599             r*=1; // turn it into a number;
13600             r++;
13601             if (String(r).length != n) {
13602                 ps[0]*=1;
13603                 ps[0]++;
13604                 r = String(r).substring(1); // chop the end off.
13605             }
13606             
13607             return ps[0] + '.' + r;
13608              
13609         },
13610         
13611         /**
13612          * Format a number as US currency
13613          * @param {Number/String} value The numeric value to format
13614          * @return {String} The formatted currency string
13615          */
13616         usMoney : function(v){
13617             return '$' + Roo.util.Format.number(v);
13618         },
13619         
13620         /**
13621          * Format a number
13622          * eventually this should probably emulate php's number_format
13623          * @param {Number/String} value The numeric value to format
13624          * @param {Number} decimals number of decimal places
13625          * @return {String} The formatted currency string
13626          */
13627         number : function(v,decimals)
13628         {
13629             // multiply and round.
13630             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13631             var mul = Math.pow(10, decimals);
13632             var zero = String(mul).substring(1);
13633             v = (Math.round((v-0)*mul))/mul;
13634             
13635             // if it's '0' number.. then
13636             
13637             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13638             v = String(v);
13639             var ps = v.split('.');
13640             var whole = ps[0];
13641             
13642             
13643             var r = /(\d+)(\d{3})/;
13644             // add comma's
13645             while (r.test(whole)) {
13646                 whole = whole.replace(r, '$1' + ',' + '$2');
13647             }
13648             
13649             
13650             var sub = ps[1] ?
13651                     // has decimals..
13652                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13653                     // does not have decimals
13654                     (decimals ? ('.' + zero) : '');
13655             
13656             
13657             return whole + sub ;
13658         },
13659         
13660         /**
13661          * Parse a value into a formatted date using the specified format pattern.
13662          * @param {Mixed} value The value to format
13663          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13664          * @return {String} The formatted date string
13665          */
13666         date : function(v, format){
13667             if(!v){
13668                 return "";
13669             }
13670             if(!(v instanceof Date)){
13671                 v = new Date(Date.parse(v));
13672             }
13673             return v.dateFormat(format || Roo.util.Format.defaults.date);
13674         },
13675
13676         /**
13677          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13678          * @param {String} format Any valid date format string
13679          * @return {Function} The date formatting function
13680          */
13681         dateRenderer : function(format){
13682             return function(v){
13683                 return Roo.util.Format.date(v, format);  
13684             };
13685         },
13686
13687         // private
13688         stripTagsRE : /<\/?[^>]+>/gi,
13689         
13690         /**
13691          * Strips all HTML tags
13692          * @param {Mixed} value The text from which to strip tags
13693          * @return {String} The stripped text
13694          */
13695         stripTags : function(v){
13696             return !v ? v : String(v).replace(this.stripTagsRE, "");
13697         }
13698     };
13699 }();
13700 Roo.util.Format.defaults = {
13701     date : 'd/M/Y'
13702 };/*
13703  * Based on:
13704  * Ext JS Library 1.1.1
13705  * Copyright(c) 2006-2007, Ext JS, LLC.
13706  *
13707  * Originally Released Under LGPL - original licence link has changed is not relivant.
13708  *
13709  * Fork - LGPL
13710  * <script type="text/javascript">
13711  */
13712
13713
13714  
13715
13716 /**
13717  * @class Roo.MasterTemplate
13718  * @extends Roo.Template
13719  * Provides a template that can have child templates. The syntax is:
13720 <pre><code>
13721 var t = new Roo.MasterTemplate(
13722         '&lt;select name="{name}"&gt;',
13723                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13724         '&lt;/select&gt;'
13725 );
13726 t.add('options', {value: 'foo', text: 'bar'});
13727 // or you can add multiple child elements in one shot
13728 t.addAll('options', [
13729     {value: 'foo', text: 'bar'},
13730     {value: 'foo2', text: 'bar2'},
13731     {value: 'foo3', text: 'bar3'}
13732 ]);
13733 // then append, applying the master template values
13734 t.append('my-form', {name: 'my-select'});
13735 </code></pre>
13736 * A name attribute for the child template is not required if you have only one child
13737 * template or you want to refer to them by index.
13738  */
13739 Roo.MasterTemplate = function(){
13740     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13741     this.originalHtml = this.html;
13742     var st = {};
13743     var m, re = this.subTemplateRe;
13744     re.lastIndex = 0;
13745     var subIndex = 0;
13746     while(m = re.exec(this.html)){
13747         var name = m[1], content = m[2];
13748         st[subIndex] = {
13749             name: name,
13750             index: subIndex,
13751             buffer: [],
13752             tpl : new Roo.Template(content)
13753         };
13754         if(name){
13755             st[name] = st[subIndex];
13756         }
13757         st[subIndex].tpl.compile();
13758         st[subIndex].tpl.call = this.call.createDelegate(this);
13759         subIndex++;
13760     }
13761     this.subCount = subIndex;
13762     this.subs = st;
13763 };
13764 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13765     /**
13766     * The regular expression used to match sub templates
13767     * @type RegExp
13768     * @property
13769     */
13770     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13771
13772     /**
13773      * Applies the passed values to a child template.
13774      * @param {String/Number} name (optional) The name or index of the child template
13775      * @param {Array/Object} values The values to be applied to the template
13776      * @return {MasterTemplate} this
13777      */
13778      add : function(name, values){
13779         if(arguments.length == 1){
13780             values = arguments[0];
13781             name = 0;
13782         }
13783         var s = this.subs[name];
13784         s.buffer[s.buffer.length] = s.tpl.apply(values);
13785         return this;
13786     },
13787
13788     /**
13789      * Applies all the passed values to a child template.
13790      * @param {String/Number} name (optional) The name or index of the child template
13791      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13792      * @param {Boolean} reset (optional) True to reset the template first
13793      * @return {MasterTemplate} this
13794      */
13795     fill : function(name, values, reset){
13796         var a = arguments;
13797         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13798             values = a[0];
13799             name = 0;
13800             reset = a[1];
13801         }
13802         if(reset){
13803             this.reset();
13804         }
13805         for(var i = 0, len = values.length; i < len; i++){
13806             this.add(name, values[i]);
13807         }
13808         return this;
13809     },
13810
13811     /**
13812      * Resets the template for reuse
13813      * @return {MasterTemplate} this
13814      */
13815      reset : function(){
13816         var s = this.subs;
13817         for(var i = 0; i < this.subCount; i++){
13818             s[i].buffer = [];
13819         }
13820         return this;
13821     },
13822
13823     applyTemplate : function(values){
13824         var s = this.subs;
13825         var replaceIndex = -1;
13826         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13827             return s[++replaceIndex].buffer.join("");
13828         });
13829         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13830     },
13831
13832     apply : function(){
13833         return this.applyTemplate.apply(this, arguments);
13834     },
13835
13836     compile : function(){return this;}
13837 });
13838
13839 /**
13840  * Alias for fill().
13841  * @method
13842  */
13843 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13844  /**
13845  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13846  * var tpl = Roo.MasterTemplate.from('element-id');
13847  * @param {String/HTMLElement} el
13848  * @param {Object} config
13849  * @static
13850  */
13851 Roo.MasterTemplate.from = function(el, config){
13852     el = Roo.getDom(el);
13853     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13854 };/*
13855  * Based on:
13856  * Ext JS Library 1.1.1
13857  * Copyright(c) 2006-2007, Ext JS, LLC.
13858  *
13859  * Originally Released Under LGPL - original licence link has changed is not relivant.
13860  *
13861  * Fork - LGPL
13862  * <script type="text/javascript">
13863  */
13864
13865  
13866 /**
13867  * @class Roo.util.CSS
13868  * Utility class for manipulating CSS rules
13869  * @singleton
13870  */
13871 Roo.util.CSS = function(){
13872         var rules = null;
13873         var doc = document;
13874
13875     var camelRe = /(-[a-z])/gi;
13876     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13877
13878    return {
13879    /**
13880     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13881     * tag and appended to the HEAD of the document.
13882     * @param {String|Object} cssText The text containing the css rules
13883     * @param {String} id An id to add to the stylesheet for later removal
13884     * @return {StyleSheet}
13885     */
13886     createStyleSheet : function(cssText, id){
13887         var ss;
13888         var head = doc.getElementsByTagName("head")[0];
13889         var nrules = doc.createElement("style");
13890         nrules.setAttribute("type", "text/css");
13891         if(id){
13892             nrules.setAttribute("id", id);
13893         }
13894         if (typeof(cssText) != 'string') {
13895             // support object maps..
13896             // not sure if this a good idea.. 
13897             // perhaps it should be merged with the general css handling
13898             // and handle js style props.
13899             var cssTextNew = [];
13900             for(var n in cssText) {
13901                 var citems = [];
13902                 for(var k in cssText[n]) {
13903                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13904                 }
13905                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13906                 
13907             }
13908             cssText = cssTextNew.join("\n");
13909             
13910         }
13911        
13912        
13913        if(Roo.isIE){
13914            head.appendChild(nrules);
13915            ss = nrules.styleSheet;
13916            ss.cssText = cssText;
13917        }else{
13918            try{
13919                 nrules.appendChild(doc.createTextNode(cssText));
13920            }catch(e){
13921                nrules.cssText = cssText; 
13922            }
13923            head.appendChild(nrules);
13924            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13925        }
13926        this.cacheStyleSheet(ss);
13927        return ss;
13928    },
13929
13930    /**
13931     * Removes a style or link tag by id
13932     * @param {String} id The id of the tag
13933     */
13934    removeStyleSheet : function(id){
13935        var existing = doc.getElementById(id);
13936        if(existing){
13937            existing.parentNode.removeChild(existing);
13938        }
13939    },
13940
13941    /**
13942     * Dynamically swaps an existing stylesheet reference for a new one
13943     * @param {String} id The id of an existing link tag to remove
13944     * @param {String} url The href of the new stylesheet to include
13945     */
13946    swapStyleSheet : function(id, url){
13947        this.removeStyleSheet(id);
13948        var ss = doc.createElement("link");
13949        ss.setAttribute("rel", "stylesheet");
13950        ss.setAttribute("type", "text/css");
13951        ss.setAttribute("id", id);
13952        ss.setAttribute("href", url);
13953        doc.getElementsByTagName("head")[0].appendChild(ss);
13954    },
13955    
13956    /**
13957     * Refresh the rule cache if you have dynamically added stylesheets
13958     * @return {Object} An object (hash) of rules indexed by selector
13959     */
13960    refreshCache : function(){
13961        return this.getRules(true);
13962    },
13963
13964    // private
13965    cacheStyleSheet : function(stylesheet){
13966        if(!rules){
13967            rules = {};
13968        }
13969        try{// try catch for cross domain access issue
13970            var ssRules = stylesheet.cssRules || stylesheet.rules;
13971            for(var j = ssRules.length-1; j >= 0; --j){
13972                rules[ssRules[j].selectorText] = ssRules[j];
13973            }
13974        }catch(e){}
13975    },
13976    
13977    /**
13978     * Gets all css rules for the document
13979     * @param {Boolean} refreshCache true to refresh the internal cache
13980     * @return {Object} An object (hash) of rules indexed by selector
13981     */
13982    getRules : function(refreshCache){
13983                 if(rules == null || refreshCache){
13984                         rules = {};
13985                         var ds = doc.styleSheets;
13986                         for(var i =0, len = ds.length; i < len; i++){
13987                             try{
13988                         this.cacheStyleSheet(ds[i]);
13989                     }catch(e){} 
13990                 }
13991                 }
13992                 return rules;
13993         },
13994         
13995         /**
13996     * Gets an an individual CSS rule by selector(s)
13997     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13998     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13999     * @return {CSSRule} The CSS rule or null if one is not found
14000     */
14001    getRule : function(selector, refreshCache){
14002                 var rs = this.getRules(refreshCache);
14003                 if(!(selector instanceof Array)){
14004                     return rs[selector];
14005                 }
14006                 for(var i = 0; i < selector.length; i++){
14007                         if(rs[selector[i]]){
14008                                 return rs[selector[i]];
14009                         }
14010                 }
14011                 return null;
14012         },
14013         
14014         
14015         /**
14016     * Updates a rule property
14017     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14018     * @param {String} property The css property
14019     * @param {String} value The new value for the property
14020     * @return {Boolean} true If a rule was found and updated
14021     */
14022    updateRule : function(selector, property, value){
14023                 if(!(selector instanceof Array)){
14024                         var rule = this.getRule(selector);
14025                         if(rule){
14026                                 rule.style[property.replace(camelRe, camelFn)] = value;
14027                                 return true;
14028                         }
14029                 }else{
14030                         for(var i = 0; i < selector.length; i++){
14031                                 if(this.updateRule(selector[i], property, value)){
14032                                         return true;
14033                                 }
14034                         }
14035                 }
14036                 return false;
14037         }
14038    };   
14039 }();/*
14040  * Based on:
14041  * Ext JS Library 1.1.1
14042  * Copyright(c) 2006-2007, Ext JS, LLC.
14043  *
14044  * Originally Released Under LGPL - original licence link has changed is not relivant.
14045  *
14046  * Fork - LGPL
14047  * <script type="text/javascript">
14048  */
14049
14050  
14051
14052 /**
14053  * @class Roo.util.ClickRepeater
14054  * @extends Roo.util.Observable
14055  * 
14056  * A wrapper class which can be applied to any element. Fires a "click" event while the
14057  * mouse is pressed. The interval between firings may be specified in the config but
14058  * defaults to 10 milliseconds.
14059  * 
14060  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14061  * 
14062  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14063  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14064  * Similar to an autorepeat key delay.
14065  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14066  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14067  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14068  *           "interval" and "delay" are ignored. "immediate" is honored.
14069  * @cfg {Boolean} preventDefault True to prevent the default click event
14070  * @cfg {Boolean} stopDefault True to stop the default click event
14071  * 
14072  * @history
14073  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14074  *     2007-02-02 jvs Renamed to ClickRepeater
14075  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14076  *
14077  *  @constructor
14078  * @param {String/HTMLElement/Element} el The element to listen on
14079  * @param {Object} config
14080  **/
14081 Roo.util.ClickRepeater = function(el, config)
14082 {
14083     this.el = Roo.get(el);
14084     this.el.unselectable();
14085
14086     Roo.apply(this, config);
14087
14088     this.addEvents({
14089     /**
14090      * @event mousedown
14091      * Fires when the mouse button is depressed.
14092      * @param {Roo.util.ClickRepeater} this
14093      */
14094         "mousedown" : true,
14095     /**
14096      * @event click
14097      * Fires on a specified interval during the time the element is pressed.
14098      * @param {Roo.util.ClickRepeater} this
14099      */
14100         "click" : true,
14101     /**
14102      * @event mouseup
14103      * Fires when the mouse key is released.
14104      * @param {Roo.util.ClickRepeater} this
14105      */
14106         "mouseup" : true
14107     });
14108
14109     this.el.on("mousedown", this.handleMouseDown, this);
14110     if(this.preventDefault || this.stopDefault){
14111         this.el.on("click", function(e){
14112             if(this.preventDefault){
14113                 e.preventDefault();
14114             }
14115             if(this.stopDefault){
14116                 e.stopEvent();
14117             }
14118         }, this);
14119     }
14120
14121     // allow inline handler
14122     if(this.handler){
14123         this.on("click", this.handler,  this.scope || this);
14124     }
14125
14126     Roo.util.ClickRepeater.superclass.constructor.call(this);
14127 };
14128
14129 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14130     interval : 20,
14131     delay: 250,
14132     preventDefault : true,
14133     stopDefault : false,
14134     timer : 0,
14135
14136     // private
14137     handleMouseDown : function(){
14138         clearTimeout(this.timer);
14139         this.el.blur();
14140         if(this.pressClass){
14141             this.el.addClass(this.pressClass);
14142         }
14143         this.mousedownTime = new Date();
14144
14145         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14146         this.el.on("mouseout", this.handleMouseOut, this);
14147
14148         this.fireEvent("mousedown", this);
14149         this.fireEvent("click", this);
14150         
14151         this.timer = this.click.defer(this.delay || this.interval, this);
14152     },
14153
14154     // private
14155     click : function(){
14156         this.fireEvent("click", this);
14157         this.timer = this.click.defer(this.getInterval(), this);
14158     },
14159
14160     // private
14161     getInterval: function(){
14162         if(!this.accelerate){
14163             return this.interval;
14164         }
14165         var pressTime = this.mousedownTime.getElapsed();
14166         if(pressTime < 500){
14167             return 400;
14168         }else if(pressTime < 1700){
14169             return 320;
14170         }else if(pressTime < 2600){
14171             return 250;
14172         }else if(pressTime < 3500){
14173             return 180;
14174         }else if(pressTime < 4400){
14175             return 140;
14176         }else if(pressTime < 5300){
14177             return 80;
14178         }else if(pressTime < 6200){
14179             return 50;
14180         }else{
14181             return 10;
14182         }
14183     },
14184
14185     // private
14186     handleMouseOut : function(){
14187         clearTimeout(this.timer);
14188         if(this.pressClass){
14189             this.el.removeClass(this.pressClass);
14190         }
14191         this.el.on("mouseover", this.handleMouseReturn, this);
14192     },
14193
14194     // private
14195     handleMouseReturn : function(){
14196         this.el.un("mouseover", this.handleMouseReturn);
14197         if(this.pressClass){
14198             this.el.addClass(this.pressClass);
14199         }
14200         this.click();
14201     },
14202
14203     // private
14204     handleMouseUp : function(){
14205         clearTimeout(this.timer);
14206         this.el.un("mouseover", this.handleMouseReturn);
14207         this.el.un("mouseout", this.handleMouseOut);
14208         Roo.get(document).un("mouseup", this.handleMouseUp);
14209         this.el.removeClass(this.pressClass);
14210         this.fireEvent("mouseup", this);
14211     }
14212 });/*
14213  * Based on:
14214  * Ext JS Library 1.1.1
14215  * Copyright(c) 2006-2007, Ext JS, LLC.
14216  *
14217  * Originally Released Under LGPL - original licence link has changed is not relivant.
14218  *
14219  * Fork - LGPL
14220  * <script type="text/javascript">
14221  */
14222
14223  
14224 /**
14225  * @class Roo.KeyNav
14226  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14227  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14228  * way to implement custom navigation schemes for any UI component.</p>
14229  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14230  * pageUp, pageDown, del, home, end.  Usage:</p>
14231  <pre><code>
14232 var nav = new Roo.KeyNav("my-element", {
14233     "left" : function(e){
14234         this.moveLeft(e.ctrlKey);
14235     },
14236     "right" : function(e){
14237         this.moveRight(e.ctrlKey);
14238     },
14239     "enter" : function(e){
14240         this.save();
14241     },
14242     scope : this
14243 });
14244 </code></pre>
14245  * @constructor
14246  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14247  * @param {Object} config The config
14248  */
14249 Roo.KeyNav = function(el, config){
14250     this.el = Roo.get(el);
14251     Roo.apply(this, config);
14252     if(!this.disabled){
14253         this.disabled = true;
14254         this.enable();
14255     }
14256 };
14257
14258 Roo.KeyNav.prototype = {
14259     /**
14260      * @cfg {Boolean} disabled
14261      * True to disable this KeyNav instance (defaults to false)
14262      */
14263     disabled : false,
14264     /**
14265      * @cfg {String} defaultEventAction
14266      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14267      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14268      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14269      */
14270     defaultEventAction: "stopEvent",
14271     /**
14272      * @cfg {Boolean} forceKeyDown
14273      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14274      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14275      * handle keydown instead of keypress.
14276      */
14277     forceKeyDown : false,
14278
14279     // private
14280     prepareEvent : function(e){
14281         var k = e.getKey();
14282         var h = this.keyToHandler[k];
14283         //if(h && this[h]){
14284         //    e.stopPropagation();
14285         //}
14286         if(Roo.isSafari && h && k >= 37 && k <= 40){
14287             e.stopEvent();
14288         }
14289     },
14290
14291     // private
14292     relay : function(e){
14293         var k = e.getKey();
14294         var h = this.keyToHandler[k];
14295         if(h && this[h]){
14296             if(this.doRelay(e, this[h], h) !== true){
14297                 e[this.defaultEventAction]();
14298             }
14299         }
14300     },
14301
14302     // private
14303     doRelay : function(e, h, hname){
14304         return h.call(this.scope || this, e);
14305     },
14306
14307     // possible handlers
14308     enter : false,
14309     left : false,
14310     right : false,
14311     up : false,
14312     down : false,
14313     tab : false,
14314     esc : false,
14315     pageUp : false,
14316     pageDown : false,
14317     del : false,
14318     home : false,
14319     end : false,
14320
14321     // quick lookup hash
14322     keyToHandler : {
14323         37 : "left",
14324         39 : "right",
14325         38 : "up",
14326         40 : "down",
14327         33 : "pageUp",
14328         34 : "pageDown",
14329         46 : "del",
14330         36 : "home",
14331         35 : "end",
14332         13 : "enter",
14333         27 : "esc",
14334         9  : "tab"
14335     },
14336
14337         /**
14338          * Enable this KeyNav
14339          */
14340         enable: function(){
14341                 if(this.disabled){
14342             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14343             // the EventObject will normalize Safari automatically
14344             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14345                 this.el.on("keydown", this.relay,  this);
14346             }else{
14347                 this.el.on("keydown", this.prepareEvent,  this);
14348                 this.el.on("keypress", this.relay,  this);
14349             }
14350                     this.disabled = false;
14351                 }
14352         },
14353
14354         /**
14355          * Disable this KeyNav
14356          */
14357         disable: function(){
14358                 if(!this.disabled){
14359                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14360                 this.el.un("keydown", this.relay);
14361             }else{
14362                 this.el.un("keydown", this.prepareEvent);
14363                 this.el.un("keypress", this.relay);
14364             }
14365                     this.disabled = true;
14366                 }
14367         }
14368 };/*
14369  * Based on:
14370  * Ext JS Library 1.1.1
14371  * Copyright(c) 2006-2007, Ext JS, LLC.
14372  *
14373  * Originally Released Under LGPL - original licence link has changed is not relivant.
14374  *
14375  * Fork - LGPL
14376  * <script type="text/javascript">
14377  */
14378
14379  
14380 /**
14381  * @class Roo.KeyMap
14382  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14383  * The constructor accepts the same config object as defined by {@link #addBinding}.
14384  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14385  * combination it will call the function with this signature (if the match is a multi-key
14386  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14387  * A KeyMap can also handle a string representation of keys.<br />
14388  * Usage:
14389  <pre><code>
14390 // map one key by key code
14391 var map = new Roo.KeyMap("my-element", {
14392     key: 13, // or Roo.EventObject.ENTER
14393     fn: myHandler,
14394     scope: myObject
14395 });
14396
14397 // map multiple keys to one action by string
14398 var map = new Roo.KeyMap("my-element", {
14399     key: "a\r\n\t",
14400     fn: myHandler,
14401     scope: myObject
14402 });
14403
14404 // map multiple keys to multiple actions by strings and array of codes
14405 var map = new Roo.KeyMap("my-element", [
14406     {
14407         key: [10,13],
14408         fn: function(){ alert("Return was pressed"); }
14409     }, {
14410         key: "abc",
14411         fn: function(){ alert('a, b or c was pressed'); }
14412     }, {
14413         key: "\t",
14414         ctrl:true,
14415         shift:true,
14416         fn: function(){ alert('Control + shift + tab was pressed.'); }
14417     }
14418 ]);
14419 </code></pre>
14420  * <b>Note: A KeyMap starts enabled</b>
14421  * @constructor
14422  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14423  * @param {Object} config The config (see {@link #addBinding})
14424  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14425  */
14426 Roo.KeyMap = function(el, config, eventName){
14427     this.el  = Roo.get(el);
14428     this.eventName = eventName || "keydown";
14429     this.bindings = [];
14430     if(config){
14431         this.addBinding(config);
14432     }
14433     this.enable();
14434 };
14435
14436 Roo.KeyMap.prototype = {
14437     /**
14438      * True to stop the event from bubbling and prevent the default browser action if the
14439      * key was handled by the KeyMap (defaults to false)
14440      * @type Boolean
14441      */
14442     stopEvent : false,
14443
14444     /**
14445      * Add a new binding to this KeyMap. The following config object properties are supported:
14446      * <pre>
14447 Property    Type             Description
14448 ----------  ---------------  ----------------------------------------------------------------------
14449 key         String/Array     A single keycode or an array of keycodes to handle
14450 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14451 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14452 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14453 fn          Function         The function to call when KeyMap finds the expected key combination
14454 scope       Object           The scope of the callback function
14455 </pre>
14456      *
14457      * Usage:
14458      * <pre><code>
14459 // Create a KeyMap
14460 var map = new Roo.KeyMap(document, {
14461     key: Roo.EventObject.ENTER,
14462     fn: handleKey,
14463     scope: this
14464 });
14465
14466 //Add a new binding to the existing KeyMap later
14467 map.addBinding({
14468     key: 'abc',
14469     shift: true,
14470     fn: handleKey,
14471     scope: this
14472 });
14473 </code></pre>
14474      * @param {Object/Array} config A single KeyMap config or an array of configs
14475      */
14476         addBinding : function(config){
14477         if(config instanceof Array){
14478             for(var i = 0, len = config.length; i < len; i++){
14479                 this.addBinding(config[i]);
14480             }
14481             return;
14482         }
14483         var keyCode = config.key,
14484             shift = config.shift, 
14485             ctrl = config.ctrl, 
14486             alt = config.alt,
14487             fn = config.fn,
14488             scope = config.scope;
14489         if(typeof keyCode == "string"){
14490             var ks = [];
14491             var keyString = keyCode.toUpperCase();
14492             for(var j = 0, len = keyString.length; j < len; j++){
14493                 ks.push(keyString.charCodeAt(j));
14494             }
14495             keyCode = ks;
14496         }
14497         var keyArray = keyCode instanceof Array;
14498         var handler = function(e){
14499             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14500                 var k = e.getKey();
14501                 if(keyArray){
14502                     for(var i = 0, len = keyCode.length; i < len; i++){
14503                         if(keyCode[i] == k){
14504                           if(this.stopEvent){
14505                               e.stopEvent();
14506                           }
14507                           fn.call(scope || window, k, e);
14508                           return;
14509                         }
14510                     }
14511                 }else{
14512                     if(k == keyCode){
14513                         if(this.stopEvent){
14514                            e.stopEvent();
14515                         }
14516                         fn.call(scope || window, k, e);
14517                     }
14518                 }
14519             }
14520         };
14521         this.bindings.push(handler);  
14522         },
14523
14524     /**
14525      * Shorthand for adding a single key listener
14526      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14527      * following options:
14528      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14529      * @param {Function} fn The function to call
14530      * @param {Object} scope (optional) The scope of the function
14531      */
14532     on : function(key, fn, scope){
14533         var keyCode, shift, ctrl, alt;
14534         if(typeof key == "object" && !(key instanceof Array)){
14535             keyCode = key.key;
14536             shift = key.shift;
14537             ctrl = key.ctrl;
14538             alt = key.alt;
14539         }else{
14540             keyCode = key;
14541         }
14542         this.addBinding({
14543             key: keyCode,
14544             shift: shift,
14545             ctrl: ctrl,
14546             alt: alt,
14547             fn: fn,
14548             scope: scope
14549         })
14550     },
14551
14552     // private
14553     handleKeyDown : function(e){
14554             if(this.enabled){ //just in case
14555             var b = this.bindings;
14556             for(var i = 0, len = b.length; i < len; i++){
14557                 b[i].call(this, e);
14558             }
14559             }
14560         },
14561         
14562         /**
14563          * Returns true if this KeyMap is enabled
14564          * @return {Boolean} 
14565          */
14566         isEnabled : function(){
14567             return this.enabled;  
14568         },
14569         
14570         /**
14571          * Enables this KeyMap
14572          */
14573         enable: function(){
14574                 if(!this.enabled){
14575                     this.el.on(this.eventName, this.handleKeyDown, this);
14576                     this.enabled = true;
14577                 }
14578         },
14579
14580         /**
14581          * Disable this KeyMap
14582          */
14583         disable: function(){
14584                 if(this.enabled){
14585                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14586                     this.enabled = false;
14587                 }
14588         }
14589 };/*
14590  * Based on:
14591  * Ext JS Library 1.1.1
14592  * Copyright(c) 2006-2007, Ext JS, LLC.
14593  *
14594  * Originally Released Under LGPL - original licence link has changed is not relivant.
14595  *
14596  * Fork - LGPL
14597  * <script type="text/javascript">
14598  */
14599
14600  
14601 /**
14602  * @class Roo.util.TextMetrics
14603  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14604  * wide, in pixels, a given block of text will be.
14605  * @singleton
14606  */
14607 Roo.util.TextMetrics = function(){
14608     var shared;
14609     return {
14610         /**
14611          * Measures the size of the specified text
14612          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14613          * that can affect the size of the rendered text
14614          * @param {String} text The text to measure
14615          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14616          * in order to accurately measure the text height
14617          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14618          */
14619         measure : function(el, text, fixedWidth){
14620             if(!shared){
14621                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14622             }
14623             shared.bind(el);
14624             shared.setFixedWidth(fixedWidth || 'auto');
14625             return shared.getSize(text);
14626         },
14627
14628         /**
14629          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14630          * the overhead of multiple calls to initialize the style properties on each measurement.
14631          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14632          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14633          * in order to accurately measure the text height
14634          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14635          */
14636         createInstance : function(el, fixedWidth){
14637             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14638         }
14639     };
14640 }();
14641
14642  
14643
14644 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14645     var ml = new Roo.Element(document.createElement('div'));
14646     document.body.appendChild(ml.dom);
14647     ml.position('absolute');
14648     ml.setLeftTop(-1000, -1000);
14649     ml.hide();
14650
14651     if(fixedWidth){
14652         ml.setWidth(fixedWidth);
14653     }
14654      
14655     var instance = {
14656         /**
14657          * Returns the size of the specified text based on the internal element's style and width properties
14658          * @memberOf Roo.util.TextMetrics.Instance#
14659          * @param {String} text The text to measure
14660          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14661          */
14662         getSize : function(text){
14663             ml.update(text);
14664             var s = ml.getSize();
14665             ml.update('');
14666             return s;
14667         },
14668
14669         /**
14670          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14671          * that can affect the size of the rendered text
14672          * @memberOf Roo.util.TextMetrics.Instance#
14673          * @param {String/HTMLElement} el The element, dom node or id
14674          */
14675         bind : function(el){
14676             ml.setStyle(
14677                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14678             );
14679         },
14680
14681         /**
14682          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14683          * to set a fixed width in order to accurately measure the text height.
14684          * @memberOf Roo.util.TextMetrics.Instance#
14685          * @param {Number} width The width to set on the element
14686          */
14687         setFixedWidth : function(width){
14688             ml.setWidth(width);
14689         },
14690
14691         /**
14692          * Returns the measured width of the specified text
14693          * @memberOf Roo.util.TextMetrics.Instance#
14694          * @param {String} text The text to measure
14695          * @return {Number} width The width in pixels
14696          */
14697         getWidth : function(text){
14698             ml.dom.style.width = 'auto';
14699             return this.getSize(text).width;
14700         },
14701
14702         /**
14703          * Returns the measured height of the specified text.  For multiline text, be sure to call
14704          * {@link #setFixedWidth} if necessary.
14705          * @memberOf Roo.util.TextMetrics.Instance#
14706          * @param {String} text The text to measure
14707          * @return {Number} height The height in pixels
14708          */
14709         getHeight : function(text){
14710             return this.getSize(text).height;
14711         }
14712     };
14713
14714     instance.bind(bindTo);
14715
14716     return instance;
14717 };
14718
14719 // backwards compat
14720 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14721  * Based on:
14722  * Ext JS Library 1.1.1
14723  * Copyright(c) 2006-2007, Ext JS, LLC.
14724  *
14725  * Originally Released Under LGPL - original licence link has changed is not relivant.
14726  *
14727  * Fork - LGPL
14728  * <script type="text/javascript">
14729  */
14730
14731 /**
14732  * @class Roo.state.Provider
14733  * Abstract base class for state provider implementations. This class provides methods
14734  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14735  * Provider interface.
14736  */
14737 Roo.state.Provider = function(){
14738     /**
14739      * @event statechange
14740      * Fires when a state change occurs.
14741      * @param {Provider} this This state provider
14742      * @param {String} key The state key which was changed
14743      * @param {String} value The encoded value for the state
14744      */
14745     this.addEvents({
14746         "statechange": true
14747     });
14748     this.state = {};
14749     Roo.state.Provider.superclass.constructor.call(this);
14750 };
14751 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14752     /**
14753      * Returns the current value for a key
14754      * @param {String} name The key name
14755      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14756      * @return {Mixed} The state data
14757      */
14758     get : function(name, defaultValue){
14759         return typeof this.state[name] == "undefined" ?
14760             defaultValue : this.state[name];
14761     },
14762     
14763     /**
14764      * Clears a value from the state
14765      * @param {String} name The key name
14766      */
14767     clear : function(name){
14768         delete this.state[name];
14769         this.fireEvent("statechange", this, name, null);
14770     },
14771     
14772     /**
14773      * Sets the value for a key
14774      * @param {String} name The key name
14775      * @param {Mixed} value The value to set
14776      */
14777     set : function(name, value){
14778         this.state[name] = value;
14779         this.fireEvent("statechange", this, name, value);
14780     },
14781     
14782     /**
14783      * Decodes a string previously encoded with {@link #encodeValue}.
14784      * @param {String} value The value to decode
14785      * @return {Mixed} The decoded value
14786      */
14787     decodeValue : function(cookie){
14788         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14789         var matches = re.exec(unescape(cookie));
14790         if(!matches || !matches[1]) return; // non state cookie
14791         var type = matches[1];
14792         var v = matches[2];
14793         switch(type){
14794             case "n":
14795                 return parseFloat(v);
14796             case "d":
14797                 return new Date(Date.parse(v));
14798             case "b":
14799                 return (v == "1");
14800             case "a":
14801                 var all = [];
14802                 var values = v.split("^");
14803                 for(var i = 0, len = values.length; i < len; i++){
14804                     all.push(this.decodeValue(values[i]));
14805                 }
14806                 return all;
14807            case "o":
14808                 var all = {};
14809                 var values = v.split("^");
14810                 for(var i = 0, len = values.length; i < len; i++){
14811                     var kv = values[i].split("=");
14812                     all[kv[0]] = this.decodeValue(kv[1]);
14813                 }
14814                 return all;
14815            default:
14816                 return v;
14817         }
14818     },
14819     
14820     /**
14821      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14822      * @param {Mixed} value The value to encode
14823      * @return {String} The encoded value
14824      */
14825     encodeValue : function(v){
14826         var enc;
14827         if(typeof v == "number"){
14828             enc = "n:" + v;
14829         }else if(typeof v == "boolean"){
14830             enc = "b:" + (v ? "1" : "0");
14831         }else if(v instanceof Date){
14832             enc = "d:" + v.toGMTString();
14833         }else if(v instanceof Array){
14834             var flat = "";
14835             for(var i = 0, len = v.length; i < len; i++){
14836                 flat += this.encodeValue(v[i]);
14837                 if(i != len-1) flat += "^";
14838             }
14839             enc = "a:" + flat;
14840         }else if(typeof v == "object"){
14841             var flat = "";
14842             for(var key in v){
14843                 if(typeof v[key] != "function"){
14844                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14845                 }
14846             }
14847             enc = "o:" + flat.substring(0, flat.length-1);
14848         }else{
14849             enc = "s:" + v;
14850         }
14851         return escape(enc);        
14852     }
14853 });
14854
14855 /*
14856  * Based on:
14857  * Ext JS Library 1.1.1
14858  * Copyright(c) 2006-2007, Ext JS, LLC.
14859  *
14860  * Originally Released Under LGPL - original licence link has changed is not relivant.
14861  *
14862  * Fork - LGPL
14863  * <script type="text/javascript">
14864  */
14865 /**
14866  * @class Roo.state.Manager
14867  * This is the global state manager. By default all components that are "state aware" check this class
14868  * for state information if you don't pass them a custom state provider. In order for this class
14869  * to be useful, it must be initialized with a provider when your application initializes.
14870  <pre><code>
14871 // in your initialization function
14872 init : function(){
14873    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14874    ...
14875    // supposed you have a {@link Roo.BorderLayout}
14876    var layout = new Roo.BorderLayout(...);
14877    layout.restoreState();
14878    // or a {Roo.BasicDialog}
14879    var dialog = new Roo.BasicDialog(...);
14880    dialog.restoreState();
14881  </code></pre>
14882  * @singleton
14883  */
14884 Roo.state.Manager = function(){
14885     var provider = new Roo.state.Provider();
14886     
14887     return {
14888         /**
14889          * Configures the default state provider for your application
14890          * @param {Provider} stateProvider The state provider to set
14891          */
14892         setProvider : function(stateProvider){
14893             provider = stateProvider;
14894         },
14895         
14896         /**
14897          * Returns the current value for a key
14898          * @param {String} name The key name
14899          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14900          * @return {Mixed} The state data
14901          */
14902         get : function(key, defaultValue){
14903             return provider.get(key, defaultValue);
14904         },
14905         
14906         /**
14907          * Sets the value for a key
14908          * @param {String} name The key name
14909          * @param {Mixed} value The state data
14910          */
14911          set : function(key, value){
14912             provider.set(key, value);
14913         },
14914         
14915         /**
14916          * Clears a value from the state
14917          * @param {String} name The key name
14918          */
14919         clear : function(key){
14920             provider.clear(key);
14921         },
14922         
14923         /**
14924          * Gets the currently configured state provider
14925          * @return {Provider} The state provider
14926          */
14927         getProvider : function(){
14928             return provider;
14929         }
14930     };
14931 }();
14932 /*
14933  * Based on:
14934  * Ext JS Library 1.1.1
14935  * Copyright(c) 2006-2007, Ext JS, LLC.
14936  *
14937  * Originally Released Under LGPL - original licence link has changed is not relivant.
14938  *
14939  * Fork - LGPL
14940  * <script type="text/javascript">
14941  */
14942 /**
14943  * @class Roo.state.CookieProvider
14944  * @extends Roo.state.Provider
14945  * The default Provider implementation which saves state via cookies.
14946  * <br />Usage:
14947  <pre><code>
14948    var cp = new Roo.state.CookieProvider({
14949        path: "/cgi-bin/",
14950        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14951        domain: "roojs.com"
14952    })
14953    Roo.state.Manager.setProvider(cp);
14954  </code></pre>
14955  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14956  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14957  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14958  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14959  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14960  * domain the page is running on including the 'www' like 'www.roojs.com')
14961  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14962  * @constructor
14963  * Create a new CookieProvider
14964  * @param {Object} config The configuration object
14965  */
14966 Roo.state.CookieProvider = function(config){
14967     Roo.state.CookieProvider.superclass.constructor.call(this);
14968     this.path = "/";
14969     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14970     this.domain = null;
14971     this.secure = false;
14972     Roo.apply(this, config);
14973     this.state = this.readCookies();
14974 };
14975
14976 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14977     // private
14978     set : function(name, value){
14979         if(typeof value == "undefined" || value === null){
14980             this.clear(name);
14981             return;
14982         }
14983         this.setCookie(name, value);
14984         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14985     },
14986
14987     // private
14988     clear : function(name){
14989         this.clearCookie(name);
14990         Roo.state.CookieProvider.superclass.clear.call(this, name);
14991     },
14992
14993     // private
14994     readCookies : function(){
14995         var cookies = {};
14996         var c = document.cookie + ";";
14997         var re = /\s?(.*?)=(.*?);/g;
14998         var matches;
14999         while((matches = re.exec(c)) != null){
15000             var name = matches[1];
15001             var value = matches[2];
15002             if(name && name.substring(0,3) == "ys-"){
15003                 cookies[name.substr(3)] = this.decodeValue(value);
15004             }
15005         }
15006         return cookies;
15007     },
15008
15009     // private
15010     setCookie : function(name, value){
15011         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15012            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15013            ((this.path == null) ? "" : ("; path=" + this.path)) +
15014            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15015            ((this.secure == true) ? "; secure" : "");
15016     },
15017
15018     // private
15019     clearCookie : function(name){
15020         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15021            ((this.path == null) ? "" : ("; path=" + this.path)) +
15022            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15023            ((this.secure == true) ? "; secure" : "");
15024     }
15025 });/*
15026  * Based on:
15027  * Ext JS Library 1.1.1
15028  * Copyright(c) 2006-2007, Ext JS, LLC.
15029  *
15030  * Originally Released Under LGPL - original licence link has changed is not relivant.
15031  *
15032  * Fork - LGPL
15033  * <script type="text/javascript">
15034  */
15035  
15036
15037 /**
15038  * @class Roo.ComponentMgr
15039  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15040  * @singleton
15041  */
15042 Roo.ComponentMgr = function(){
15043     var all = new Roo.util.MixedCollection();
15044
15045     return {
15046         /**
15047          * Registers a component.
15048          * @param {Roo.Component} c The component
15049          */
15050         register : function(c){
15051             all.add(c);
15052         },
15053
15054         /**
15055          * Unregisters a component.
15056          * @param {Roo.Component} c The component
15057          */
15058         unregister : function(c){
15059             all.remove(c);
15060         },
15061
15062         /**
15063          * Returns a component by id
15064          * @param {String} id The component id
15065          */
15066         get : function(id){
15067             return all.get(id);
15068         },
15069
15070         /**
15071          * Registers a function that will be called when a specified component is added to ComponentMgr
15072          * @param {String} id The component id
15073          * @param {Funtction} fn The callback function
15074          * @param {Object} scope The scope of the callback
15075          */
15076         onAvailable : function(id, fn, scope){
15077             all.on("add", function(index, o){
15078                 if(o.id == id){
15079                     fn.call(scope || o, o);
15080                     all.un("add", fn, scope);
15081                 }
15082             });
15083         }
15084     };
15085 }();/*
15086  * Based on:
15087  * Ext JS Library 1.1.1
15088  * Copyright(c) 2006-2007, Ext JS, LLC.
15089  *
15090  * Originally Released Under LGPL - original licence link has changed is not relivant.
15091  *
15092  * Fork - LGPL
15093  * <script type="text/javascript">
15094  */
15095  
15096 /**
15097  * @class Roo.Component
15098  * @extends Roo.util.Observable
15099  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15100  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15101  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15102  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15103  * All visual components (widgets) that require rendering into a layout should subclass Component.
15104  * @constructor
15105  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15106  * 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
15107  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15108  */
15109 Roo.Component = function(config){
15110     config = config || {};
15111     if(config.tagName || config.dom || typeof config == "string"){ // element object
15112         config = {el: config, id: config.id || config};
15113     }
15114     this.initialConfig = config;
15115
15116     Roo.apply(this, config);
15117     this.addEvents({
15118         /**
15119          * @event disable
15120          * Fires after the component is disabled.
15121              * @param {Roo.Component} this
15122              */
15123         disable : true,
15124         /**
15125          * @event enable
15126          * Fires after the component is enabled.
15127              * @param {Roo.Component} this
15128              */
15129         enable : true,
15130         /**
15131          * @event beforeshow
15132          * Fires before the component is shown.  Return false to stop the show.
15133              * @param {Roo.Component} this
15134              */
15135         beforeshow : true,
15136         /**
15137          * @event show
15138          * Fires after the component is shown.
15139              * @param {Roo.Component} this
15140              */
15141         show : true,
15142         /**
15143          * @event beforehide
15144          * Fires before the component is hidden. Return false to stop the hide.
15145              * @param {Roo.Component} this
15146              */
15147         beforehide : true,
15148         /**
15149          * @event hide
15150          * Fires after the component is hidden.
15151              * @param {Roo.Component} this
15152              */
15153         hide : true,
15154         /**
15155          * @event beforerender
15156          * Fires before the component is rendered. Return false to stop the render.
15157              * @param {Roo.Component} this
15158              */
15159         beforerender : true,
15160         /**
15161          * @event render
15162          * Fires after the component is rendered.
15163              * @param {Roo.Component} this
15164              */
15165         render : true,
15166         /**
15167          * @event beforedestroy
15168          * Fires before the component is destroyed. Return false to stop the destroy.
15169              * @param {Roo.Component} this
15170              */
15171         beforedestroy : true,
15172         /**
15173          * @event destroy
15174          * Fires after the component is destroyed.
15175              * @param {Roo.Component} this
15176              */
15177         destroy : true
15178     });
15179     if(!this.id){
15180         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15181     }
15182     Roo.ComponentMgr.register(this);
15183     Roo.Component.superclass.constructor.call(this);
15184     this.initComponent();
15185     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15186         this.render(this.renderTo);
15187         delete this.renderTo;
15188     }
15189 };
15190
15191 /** @private */
15192 Roo.Component.AUTO_ID = 1000;
15193
15194 Roo.extend(Roo.Component, Roo.util.Observable, {
15195     /**
15196      * @scope Roo.Component.prototype
15197      * @type {Boolean}
15198      * true if this component is hidden. Read-only.
15199      */
15200     hidden : false,
15201     /**
15202      * @type {Boolean}
15203      * true if this component is disabled. Read-only.
15204      */
15205     disabled : false,
15206     /**
15207      * @type {Boolean}
15208      * true if this component has been rendered. Read-only.
15209      */
15210     rendered : false,
15211     
15212     /** @cfg {String} disableClass
15213      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15214      */
15215     disabledClass : "x-item-disabled",
15216         /** @cfg {Boolean} allowDomMove
15217          * Whether the component can move the Dom node when rendering (defaults to true).
15218          */
15219     allowDomMove : true,
15220     /** @cfg {String} hideMode (display|visibility)
15221      * How this component should hidden. Supported values are
15222      * "visibility" (css visibility), "offsets" (negative offset position) and
15223      * "display" (css display) - defaults to "display".
15224      */
15225     hideMode: 'display',
15226
15227     /** @private */
15228     ctype : "Roo.Component",
15229
15230     /**
15231      * @cfg {String} actionMode 
15232      * which property holds the element that used for  hide() / show() / disable() / enable()
15233      * default is 'el' 
15234      */
15235     actionMode : "el",
15236
15237     /** @private */
15238     getActionEl : function(){
15239         return this[this.actionMode];
15240     },
15241
15242     initComponent : Roo.emptyFn,
15243     /**
15244      * If this is a lazy rendering component, render it to its container element.
15245      * @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.
15246      */
15247     render : function(container, position){
15248         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15249             if(!container && this.el){
15250                 this.el = Roo.get(this.el);
15251                 container = this.el.dom.parentNode;
15252                 this.allowDomMove = false;
15253             }
15254             this.container = Roo.get(container);
15255             this.rendered = true;
15256             if(position !== undefined){
15257                 if(typeof position == 'number'){
15258                     position = this.container.dom.childNodes[position];
15259                 }else{
15260                     position = Roo.getDom(position);
15261                 }
15262             }
15263             this.onRender(this.container, position || null);
15264             if(this.cls){
15265                 this.el.addClass(this.cls);
15266                 delete this.cls;
15267             }
15268             if(this.style){
15269                 this.el.applyStyles(this.style);
15270                 delete this.style;
15271             }
15272             this.fireEvent("render", this);
15273             this.afterRender(this.container);
15274             if(this.hidden){
15275                 this.hide();
15276             }
15277             if(this.disabled){
15278                 this.disable();
15279             }
15280         }
15281         return this;
15282     },
15283
15284     /** @private */
15285     // default function is not really useful
15286     onRender : function(ct, position){
15287         if(this.el){
15288             this.el = Roo.get(this.el);
15289             if(this.allowDomMove !== false){
15290                 ct.dom.insertBefore(this.el.dom, position);
15291             }
15292         }
15293     },
15294
15295     /** @private */
15296     getAutoCreate : function(){
15297         var cfg = typeof this.autoCreate == "object" ?
15298                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15299         if(this.id && !cfg.id){
15300             cfg.id = this.id;
15301         }
15302         return cfg;
15303     },
15304
15305     /** @private */
15306     afterRender : Roo.emptyFn,
15307
15308     /**
15309      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15310      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15311      */
15312     destroy : function(){
15313         if(this.fireEvent("beforedestroy", this) !== false){
15314             this.purgeListeners();
15315             this.beforeDestroy();
15316             if(this.rendered){
15317                 this.el.removeAllListeners();
15318                 this.el.remove();
15319                 if(this.actionMode == "container"){
15320                     this.container.remove();
15321                 }
15322             }
15323             this.onDestroy();
15324             Roo.ComponentMgr.unregister(this);
15325             this.fireEvent("destroy", this);
15326         }
15327     },
15328
15329         /** @private */
15330     beforeDestroy : function(){
15331
15332     },
15333
15334         /** @private */
15335         onDestroy : function(){
15336
15337     },
15338
15339     /**
15340      * Returns the underlying {@link Roo.Element}.
15341      * @return {Roo.Element} The element
15342      */
15343     getEl : function(){
15344         return this.el;
15345     },
15346
15347     /**
15348      * Returns the id of this component.
15349      * @return {String}
15350      */
15351     getId : function(){
15352         return this.id;
15353     },
15354
15355     /**
15356      * Try to focus this component.
15357      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15358      * @return {Roo.Component} this
15359      */
15360     focus : function(selectText){
15361         if(this.rendered){
15362             this.el.focus();
15363             if(selectText === true){
15364                 this.el.dom.select();
15365             }
15366         }
15367         return this;
15368     },
15369
15370     /** @private */
15371     blur : function(){
15372         if(this.rendered){
15373             this.el.blur();
15374         }
15375         return this;
15376     },
15377
15378     /**
15379      * Disable this component.
15380      * @return {Roo.Component} this
15381      */
15382     disable : function(){
15383         if(this.rendered){
15384             this.onDisable();
15385         }
15386         this.disabled = true;
15387         this.fireEvent("disable", this);
15388         return this;
15389     },
15390
15391         // private
15392     onDisable : function(){
15393         this.getActionEl().addClass(this.disabledClass);
15394         this.el.dom.disabled = true;
15395     },
15396
15397     /**
15398      * Enable this component.
15399      * @return {Roo.Component} this
15400      */
15401     enable : function(){
15402         if(this.rendered){
15403             this.onEnable();
15404         }
15405         this.disabled = false;
15406         this.fireEvent("enable", this);
15407         return this;
15408     },
15409
15410         // private
15411     onEnable : function(){
15412         this.getActionEl().removeClass(this.disabledClass);
15413         this.el.dom.disabled = false;
15414     },
15415
15416     /**
15417      * Convenience function for setting disabled/enabled by boolean.
15418      * @param {Boolean} disabled
15419      */
15420     setDisabled : function(disabled){
15421         this[disabled ? "disable" : "enable"]();
15422     },
15423
15424     /**
15425      * Show this component.
15426      * @return {Roo.Component} this
15427      */
15428     show: function(){
15429         if(this.fireEvent("beforeshow", this) !== false){
15430             this.hidden = false;
15431             if(this.rendered){
15432                 this.onShow();
15433             }
15434             this.fireEvent("show", this);
15435         }
15436         return this;
15437     },
15438
15439     // private
15440     onShow : function(){
15441         var ae = this.getActionEl();
15442         if(this.hideMode == 'visibility'){
15443             ae.dom.style.visibility = "visible";
15444         }else if(this.hideMode == 'offsets'){
15445             ae.removeClass('x-hidden');
15446         }else{
15447             ae.dom.style.display = "";
15448         }
15449     },
15450
15451     /**
15452      * Hide this component.
15453      * @return {Roo.Component} this
15454      */
15455     hide: function(){
15456         if(this.fireEvent("beforehide", this) !== false){
15457             this.hidden = true;
15458             if(this.rendered){
15459                 this.onHide();
15460             }
15461             this.fireEvent("hide", this);
15462         }
15463         return this;
15464     },
15465
15466     // private
15467     onHide : function(){
15468         var ae = this.getActionEl();
15469         if(this.hideMode == 'visibility'){
15470             ae.dom.style.visibility = "hidden";
15471         }else if(this.hideMode == 'offsets'){
15472             ae.addClass('x-hidden');
15473         }else{
15474             ae.dom.style.display = "none";
15475         }
15476     },
15477
15478     /**
15479      * Convenience function to hide or show this component by boolean.
15480      * @param {Boolean} visible True to show, false to hide
15481      * @return {Roo.Component} this
15482      */
15483     setVisible: function(visible){
15484         if(visible) {
15485             this.show();
15486         }else{
15487             this.hide();
15488         }
15489         return this;
15490     },
15491
15492     /**
15493      * Returns true if this component is visible.
15494      */
15495     isVisible : function(){
15496         return this.getActionEl().isVisible();
15497     },
15498
15499     cloneConfig : function(overrides){
15500         overrides = overrides || {};
15501         var id = overrides.id || Roo.id();
15502         var cfg = Roo.applyIf(overrides, this.initialConfig);
15503         cfg.id = id; // prevent dup id
15504         return new this.constructor(cfg);
15505     }
15506 });/*
15507  * Based on:
15508  * Ext JS Library 1.1.1
15509  * Copyright(c) 2006-2007, Ext JS, LLC.
15510  *
15511  * Originally Released Under LGPL - original licence link has changed is not relivant.
15512  *
15513  * Fork - LGPL
15514  * <script type="text/javascript">
15515  */
15516
15517 /**
15518  * @class Roo.BoxComponent
15519  * @extends Roo.Component
15520  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15521  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15522  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15523  * layout containers.
15524  * @constructor
15525  * @param {Roo.Element/String/Object} config The configuration options.
15526  */
15527 Roo.BoxComponent = function(config){
15528     Roo.Component.call(this, config);
15529     this.addEvents({
15530         /**
15531          * @event resize
15532          * Fires after the component is resized.
15533              * @param {Roo.Component} this
15534              * @param {Number} adjWidth The box-adjusted width that was set
15535              * @param {Number} adjHeight The box-adjusted height that was set
15536              * @param {Number} rawWidth The width that was originally specified
15537              * @param {Number} rawHeight The height that was originally specified
15538              */
15539         resize : true,
15540         /**
15541          * @event move
15542          * Fires after the component is moved.
15543              * @param {Roo.Component} this
15544              * @param {Number} x The new x position
15545              * @param {Number} y The new y position
15546              */
15547         move : true
15548     });
15549 };
15550
15551 Roo.extend(Roo.BoxComponent, Roo.Component, {
15552     // private, set in afterRender to signify that the component has been rendered
15553     boxReady : false,
15554     // private, used to defer height settings to subclasses
15555     deferHeight: false,
15556     /** @cfg {Number} width
15557      * width (optional) size of component
15558      */
15559      /** @cfg {Number} height
15560      * height (optional) size of component
15561      */
15562      
15563     /**
15564      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15565      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15566      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15567      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15568      * @return {Roo.BoxComponent} this
15569      */
15570     setSize : function(w, h){
15571         // support for standard size objects
15572         if(typeof w == 'object'){
15573             h = w.height;
15574             w = w.width;
15575         }
15576         // not rendered
15577         if(!this.boxReady){
15578             this.width = w;
15579             this.height = h;
15580             return this;
15581         }
15582
15583         // prevent recalcs when not needed
15584         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15585             return this;
15586         }
15587         this.lastSize = {width: w, height: h};
15588
15589         var adj = this.adjustSize(w, h);
15590         var aw = adj.width, ah = adj.height;
15591         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15592             var rz = this.getResizeEl();
15593             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15594                 rz.setSize(aw, ah);
15595             }else if(!this.deferHeight && ah !== undefined){
15596                 rz.setHeight(ah);
15597             }else if(aw !== undefined){
15598                 rz.setWidth(aw);
15599             }
15600             this.onResize(aw, ah, w, h);
15601             this.fireEvent('resize', this, aw, ah, w, h);
15602         }
15603         return this;
15604     },
15605
15606     /**
15607      * Gets the current size of the component's underlying element.
15608      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15609      */
15610     getSize : function(){
15611         return this.el.getSize();
15612     },
15613
15614     /**
15615      * Gets the current XY position of the component's underlying element.
15616      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15617      * @return {Array} The XY position of the element (e.g., [100, 200])
15618      */
15619     getPosition : function(local){
15620         if(local === true){
15621             return [this.el.getLeft(true), this.el.getTop(true)];
15622         }
15623         return this.xy || this.el.getXY();
15624     },
15625
15626     /**
15627      * Gets the current box measurements of the component's underlying element.
15628      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15629      * @returns {Object} box An object in the format {x, y, width, height}
15630      */
15631     getBox : function(local){
15632         var s = this.el.getSize();
15633         if(local){
15634             s.x = this.el.getLeft(true);
15635             s.y = this.el.getTop(true);
15636         }else{
15637             var xy = this.xy || this.el.getXY();
15638             s.x = xy[0];
15639             s.y = xy[1];
15640         }
15641         return s;
15642     },
15643
15644     /**
15645      * Sets the current box measurements of the component's underlying element.
15646      * @param {Object} box An object in the format {x, y, width, height}
15647      * @returns {Roo.BoxComponent} this
15648      */
15649     updateBox : function(box){
15650         this.setSize(box.width, box.height);
15651         this.setPagePosition(box.x, box.y);
15652         return this;
15653     },
15654
15655     // protected
15656     getResizeEl : function(){
15657         return this.resizeEl || this.el;
15658     },
15659
15660     // protected
15661     getPositionEl : function(){
15662         return this.positionEl || this.el;
15663     },
15664
15665     /**
15666      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15667      * This method fires the move event.
15668      * @param {Number} left The new left
15669      * @param {Number} top The new top
15670      * @returns {Roo.BoxComponent} this
15671      */
15672     setPosition : function(x, y){
15673         this.x = x;
15674         this.y = y;
15675         if(!this.boxReady){
15676             return this;
15677         }
15678         var adj = this.adjustPosition(x, y);
15679         var ax = adj.x, ay = adj.y;
15680
15681         var el = this.getPositionEl();
15682         if(ax !== undefined || ay !== undefined){
15683             if(ax !== undefined && ay !== undefined){
15684                 el.setLeftTop(ax, ay);
15685             }else if(ax !== undefined){
15686                 el.setLeft(ax);
15687             }else if(ay !== undefined){
15688                 el.setTop(ay);
15689             }
15690             this.onPosition(ax, ay);
15691             this.fireEvent('move', this, ax, ay);
15692         }
15693         return this;
15694     },
15695
15696     /**
15697      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15698      * This method fires the move event.
15699      * @param {Number} x The new x position
15700      * @param {Number} y The new y position
15701      * @returns {Roo.BoxComponent} this
15702      */
15703     setPagePosition : function(x, y){
15704         this.pageX = x;
15705         this.pageY = y;
15706         if(!this.boxReady){
15707             return;
15708         }
15709         if(x === undefined || y === undefined){ // cannot translate undefined points
15710             return;
15711         }
15712         var p = this.el.translatePoints(x, y);
15713         this.setPosition(p.left, p.top);
15714         return this;
15715     },
15716
15717     // private
15718     onRender : function(ct, position){
15719         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15720         if(this.resizeEl){
15721             this.resizeEl = Roo.get(this.resizeEl);
15722         }
15723         if(this.positionEl){
15724             this.positionEl = Roo.get(this.positionEl);
15725         }
15726     },
15727
15728     // private
15729     afterRender : function(){
15730         Roo.BoxComponent.superclass.afterRender.call(this);
15731         this.boxReady = true;
15732         this.setSize(this.width, this.height);
15733         if(this.x || this.y){
15734             this.setPosition(this.x, this.y);
15735         }
15736         if(this.pageX || this.pageY){
15737             this.setPagePosition(this.pageX, this.pageY);
15738         }
15739     },
15740
15741     /**
15742      * Force the component's size to recalculate based on the underlying element's current height and width.
15743      * @returns {Roo.BoxComponent} this
15744      */
15745     syncSize : function(){
15746         delete this.lastSize;
15747         this.setSize(this.el.getWidth(), this.el.getHeight());
15748         return this;
15749     },
15750
15751     /**
15752      * Called after the component is resized, this method is empty by default but can be implemented by any
15753      * subclass that needs to perform custom logic after a resize occurs.
15754      * @param {Number} adjWidth The box-adjusted width that was set
15755      * @param {Number} adjHeight The box-adjusted height that was set
15756      * @param {Number} rawWidth The width that was originally specified
15757      * @param {Number} rawHeight The height that was originally specified
15758      */
15759     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15760
15761     },
15762
15763     /**
15764      * Called after the component is moved, this method is empty by default but can be implemented by any
15765      * subclass that needs to perform custom logic after a move occurs.
15766      * @param {Number} x The new x position
15767      * @param {Number} y The new y position
15768      */
15769     onPosition : function(x, y){
15770
15771     },
15772
15773     // private
15774     adjustSize : function(w, h){
15775         if(this.autoWidth){
15776             w = 'auto';
15777         }
15778         if(this.autoHeight){
15779             h = 'auto';
15780         }
15781         return {width : w, height: h};
15782     },
15783
15784     // private
15785     adjustPosition : function(x, y){
15786         return {x : x, y: y};
15787     }
15788 });/*
15789  * Original code for Roojs - LGPL
15790  * <script type="text/javascript">
15791  */
15792  
15793 /**
15794  * @class Roo.XComponent
15795  * A delayed Element creator...
15796  * Or a way to group chunks of interface together.
15797  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15798  *  used in conjunction with XComponent.build() it will create an instance of each element,
15799  *  then call addxtype() to build the User interface.
15800  * 
15801  * Mypart.xyx = new Roo.XComponent({
15802
15803     parent : 'Mypart.xyz', // empty == document.element.!!
15804     order : '001',
15805     name : 'xxxx'
15806     region : 'xxxx'
15807     disabled : function() {} 
15808      
15809     tree : function() { // return an tree of xtype declared components
15810         var MODULE = this;
15811         return 
15812         {
15813             xtype : 'NestedLayoutPanel',
15814             // technicall
15815         }
15816      ]
15817  *})
15818  *
15819  *
15820  * It can be used to build a big heiracy, with parent etc.
15821  * or you can just use this to render a single compoent to a dom element
15822  * MYPART.render(Roo.Element | String(id) | dom_element )
15823  *
15824  *
15825  * Usage patterns.
15826  *
15827  * Classic Roo
15828  *
15829  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15830  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15831  *
15832  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15833  *
15834  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15835  * - if mulitple topModules exist, the last one is defined as the top module.
15836  *
15837  * Embeded Roo
15838  * 
15839  * When the top level or multiple modules are to embedded into a existing HTML page,
15840  * the parent element can container '#id' of the element where the module will be drawn.
15841  *
15842  * Bootstrap Roo
15843  *
15844  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15845  * it relies more on a include mechanism, where sub modules are included into an outer page.
15846  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15847  * 
15848  * Bootstrap Roo Included elements
15849  *
15850  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15851  * hence confusing the component builder as it thinks there are multiple top level elements. 
15852  *
15853  * 
15854  * 
15855  * @extends Roo.util.Observable
15856  * @constructor
15857  * @param cfg {Object} configuration of component
15858  * 
15859  */
15860 Roo.XComponent = function(cfg) {
15861     Roo.apply(this, cfg);
15862     this.addEvents({ 
15863         /**
15864              * @event built
15865              * Fires when this the componnt is built
15866              * @param {Roo.XComponent} c the component
15867              */
15868         'built' : true
15869         
15870     });
15871     this.region = this.region || 'center'; // default..
15872     Roo.XComponent.register(this);
15873     this.modules = false;
15874     this.el = false; // where the layout goes..
15875     
15876     
15877 }
15878 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15879     /**
15880      * @property el
15881      * The created element (with Roo.factory())
15882      * @type {Roo.Layout}
15883      */
15884     el  : false,
15885     
15886     /**
15887      * @property el
15888      * for BC  - use el in new code
15889      * @type {Roo.Layout}
15890      */
15891     panel : false,
15892     
15893     /**
15894      * @property layout
15895      * for BC  - use el in new code
15896      * @type {Roo.Layout}
15897      */
15898     layout : false,
15899     
15900      /**
15901      * @cfg {Function|boolean} disabled
15902      * If this module is disabled by some rule, return true from the funtion
15903      */
15904     disabled : false,
15905     
15906     /**
15907      * @cfg {String} parent 
15908      * Name of parent element which it get xtype added to..
15909      */
15910     parent: false,
15911     
15912     /**
15913      * @cfg {String} order
15914      * Used to set the order in which elements are created (usefull for multiple tabs)
15915      */
15916     
15917     order : false,
15918     /**
15919      * @cfg {String} name
15920      * String to display while loading.
15921      */
15922     name : false,
15923     /**
15924      * @cfg {String} region
15925      * Region to render component to (defaults to center)
15926      */
15927     region : 'center',
15928     
15929     /**
15930      * @cfg {Array} items
15931      * A single item array - the first element is the root of the tree..
15932      * It's done this way to stay compatible with the Xtype system...
15933      */
15934     items : false,
15935     
15936     /**
15937      * @property _tree
15938      * The method that retuns the tree of parts that make up this compoennt 
15939      * @type {function}
15940      */
15941     _tree  : false,
15942     
15943      /**
15944      * render
15945      * render element to dom or tree
15946      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15947      */
15948     
15949     render : function(el)
15950     {
15951         
15952         el = el || false;
15953         var hp = this.parent ? 1 : 0;
15954         Roo.debug &&  Roo.log(this);
15955         
15956         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15957             // if parent is a '#.....' string, then let's use that..
15958             var ename = this.parent.substr(1);
15959             this.parent = false;
15960             Roo.debug && Roo.log(ename);
15961             switch (ename) {
15962                 case 'bootstrap-body' :
15963                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15964                         this.parent = { el :  new  Roo.bootstrap.Body() };
15965                         Roo.debug && Roo.log("setting el to doc body");
15966                          
15967                     } else {
15968                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15969                     }
15970                     break;
15971                 case 'bootstrap':
15972                     this.parent = { el : true};
15973                     // fall through
15974                 default:
15975                     el = Roo.get(ename);
15976                     break;
15977             }
15978                 
15979             
15980             if (!el && !this.parent) {
15981                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15982                 return;
15983             }
15984         }
15985         Roo.debug && Roo.log("EL:");
15986         Roo.debug && Roo.log(el);
15987         Roo.debug && Roo.log("this.parent.el:");
15988         Roo.debug && Roo.log(this.parent.el);
15989         
15990         var tree = this._tree ? this._tree() : this.tree();
15991
15992         // altertive root elements ??? - we need a better way to indicate these.
15993         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15994                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15995         
15996         if (!this.parent && is_alt) {
15997             //el = Roo.get(document.body);
15998             this.parent = { el : true };
15999         }
16000             
16001             
16002         
16003         if (!this.parent) {
16004             
16005             Roo.debug && Roo.log("no parent - creating one");
16006             
16007             el = el ? Roo.get(el) : false;      
16008             
16009             // it's a top level one..
16010             this.parent =  {
16011                 el : new Roo.BorderLayout(el || document.body, {
16012                 
16013                      center: {
16014                          titlebar: false,
16015                          autoScroll:false,
16016                          closeOnTab: true,
16017                          tabPosition: 'top',
16018                           //resizeTabs: true,
16019                          alwaysShowTabs: el && hp? false :  true,
16020                          hideTabs: el || !hp ? true :  false,
16021                          minTabWidth: 140
16022                      }
16023                  })
16024             }
16025         }
16026         
16027         if (!this.parent.el) {
16028                 // probably an old style ctor, which has been disabled.
16029                 return;
16030
16031         }
16032                 // The 'tree' method is  '_tree now' 
16033             
16034         tree.region = tree.region || this.region;
16035         
16036         if (this.parent.el === true) {
16037             // bootstrap... - body..
16038             this.parent.el = Roo.factory(tree);
16039         }
16040         
16041         this.el = this.parent.el.addxtype(tree);
16042         this.fireEvent('built', this);
16043         
16044         this.panel = this.el;
16045         this.layout = this.panel.layout;
16046         this.parentLayout = this.parent.layout  || false;  
16047          
16048     }
16049     
16050 });
16051
16052 Roo.apply(Roo.XComponent, {
16053     /**
16054      * @property  hideProgress
16055      * true to disable the building progress bar.. usefull on single page renders.
16056      * @type Boolean
16057      */
16058     hideProgress : false,
16059     /**
16060      * @property  buildCompleted
16061      * True when the builder has completed building the interface.
16062      * @type Boolean
16063      */
16064     buildCompleted : false,
16065      
16066     /**
16067      * @property  topModule
16068      * the upper most module - uses document.element as it's constructor.
16069      * @type Object
16070      */
16071      
16072     topModule  : false,
16073       
16074     /**
16075      * @property  modules
16076      * array of modules to be created by registration system.
16077      * @type {Array} of Roo.XComponent
16078      */
16079     
16080     modules : [],
16081     /**
16082      * @property  elmodules
16083      * array of modules to be created by which use #ID 
16084      * @type {Array} of Roo.XComponent
16085      */
16086      
16087     elmodules : [],
16088
16089      /**
16090      * @property  build_from_html
16091      * Build elements from html - used by bootstrap HTML stuff 
16092      *    - this is cleared after build is completed
16093      * @type {boolean} true  (default false)
16094      */
16095      
16096     build_from_html : false,
16097
16098     /**
16099      * Register components to be built later.
16100      *
16101      * This solves the following issues
16102      * - Building is not done on page load, but after an authentication process has occured.
16103      * - Interface elements are registered on page load
16104      * - Parent Interface elements may not be loaded before child, so this handles that..
16105      * 
16106      *
16107      * example:
16108      * 
16109      * MyApp.register({
16110           order : '000001',
16111           module : 'Pman.Tab.projectMgr',
16112           region : 'center',
16113           parent : 'Pman.layout',
16114           disabled : false,  // or use a function..
16115         })
16116      
16117      * * @param {Object} details about module
16118      */
16119     register : function(obj) {
16120                 
16121         Roo.XComponent.event.fireEvent('register', obj);
16122         switch(typeof(obj.disabled) ) {
16123                 
16124             case 'undefined':
16125                 break;
16126             
16127             case 'function':
16128                 if ( obj.disabled() ) {
16129                         return;
16130                 }
16131                 break;
16132             
16133             default:
16134                 if (obj.disabled) {
16135                         return;
16136                 }
16137                 break;
16138         }
16139                 
16140         this.modules.push(obj);
16141          
16142     },
16143     /**
16144      * convert a string to an object..
16145      * eg. 'AAA.BBB' -> finds AAA.BBB
16146
16147      */
16148     
16149     toObject : function(str)
16150     {
16151         if (!str || typeof(str) == 'object') {
16152             return str;
16153         }
16154         if (str.substring(0,1) == '#') {
16155             return str;
16156         }
16157
16158         var ar = str.split('.');
16159         var rt, o;
16160         rt = ar.shift();
16161             /** eval:var:o */
16162         try {
16163             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16164         } catch (e) {
16165             throw "Module not found : " + str;
16166         }
16167         
16168         if (o === false) {
16169             throw "Module not found : " + str;
16170         }
16171         Roo.each(ar, function(e) {
16172             if (typeof(o[e]) == 'undefined') {
16173                 throw "Module not found : " + str;
16174             }
16175             o = o[e];
16176         });
16177         
16178         return o;
16179         
16180     },
16181     
16182     
16183     /**
16184      * move modules into their correct place in the tree..
16185      * 
16186      */
16187     preBuild : function ()
16188     {
16189         var _t = this;
16190         Roo.each(this.modules , function (obj)
16191         {
16192             Roo.XComponent.event.fireEvent('beforebuild', obj);
16193             
16194             var opar = obj.parent;
16195             try { 
16196                 obj.parent = this.toObject(opar);
16197             } catch(e) {
16198                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16199                 return;
16200             }
16201             
16202             if (!obj.parent) {
16203                 Roo.debug && Roo.log("GOT top level module");
16204                 Roo.debug && Roo.log(obj);
16205                 obj.modules = new Roo.util.MixedCollection(false, 
16206                     function(o) { return o.order + '' }
16207                 );
16208                 this.topModule = obj;
16209                 return;
16210             }
16211                         // parent is a string (usually a dom element name..)
16212             if (typeof(obj.parent) == 'string') {
16213                 this.elmodules.push(obj);
16214                 return;
16215             }
16216             if (obj.parent.constructor != Roo.XComponent) {
16217                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16218             }
16219             if (!obj.parent.modules) {
16220                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16221                     function(o) { return o.order + '' }
16222                 );
16223             }
16224             if (obj.parent.disabled) {
16225                 obj.disabled = true;
16226             }
16227             obj.parent.modules.add(obj);
16228         }, this);
16229     },
16230     
16231      /**
16232      * make a list of modules to build.
16233      * @return {Array} list of modules. 
16234      */ 
16235     
16236     buildOrder : function()
16237     {
16238         var _this = this;
16239         var cmp = function(a,b) {   
16240             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16241         };
16242         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16243             throw "No top level modules to build";
16244         }
16245         
16246         // make a flat list in order of modules to build.
16247         var mods = this.topModule ? [ this.topModule ] : [];
16248                 
16249         
16250         // elmodules (is a list of DOM based modules )
16251         Roo.each(this.elmodules, function(e) {
16252             mods.push(e);
16253             if (!this.topModule &&
16254                 typeof(e.parent) == 'string' &&
16255                 e.parent.substring(0,1) == '#' &&
16256                 Roo.get(e.parent.substr(1))
16257                ) {
16258                 
16259                 _this.topModule = e;
16260             }
16261             
16262         });
16263
16264         
16265         // add modules to their parents..
16266         var addMod = function(m) {
16267             Roo.debug && Roo.log("build Order: add: " + m.name);
16268                 
16269             mods.push(m);
16270             if (m.modules && !m.disabled) {
16271                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16272                 m.modules.keySort('ASC',  cmp );
16273                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16274     
16275                 m.modules.each(addMod);
16276             } else {
16277                 Roo.debug && Roo.log("build Order: no child modules");
16278             }
16279             // not sure if this is used any more..
16280             if (m.finalize) {
16281                 m.finalize.name = m.name + " (clean up) ";
16282                 mods.push(m.finalize);
16283             }
16284             
16285         }
16286         if (this.topModule && this.topModule.modules) { 
16287             this.topModule.modules.keySort('ASC',  cmp );
16288             this.topModule.modules.each(addMod);
16289         } 
16290         return mods;
16291     },
16292     
16293      /**
16294      * Build the registered modules.
16295      * @param {Object} parent element.
16296      * @param {Function} optional method to call after module has been added.
16297      * 
16298      */ 
16299    
16300     build : function(opts) 
16301     {
16302         
16303         if (typeof(opts) != 'undefined') {
16304             Roo.apply(this,opts);
16305         }
16306         
16307         this.preBuild();
16308         var mods = this.buildOrder();
16309       
16310         //this.allmods = mods;
16311         //Roo.debug && Roo.log(mods);
16312         //return;
16313         if (!mods.length) { // should not happen
16314             throw "NO modules!!!";
16315         }
16316         
16317         
16318         var msg = "Building Interface...";
16319         // flash it up as modal - so we store the mask!?
16320         if (!this.hideProgress && Roo.MessageBox) {
16321             Roo.MessageBox.show({ title: 'loading' });
16322             Roo.MessageBox.show({
16323                title: "Please wait...",
16324                msg: msg,
16325                width:450,
16326                progress:true,
16327                closable:false,
16328                modal: false
16329               
16330             });
16331         }
16332         var total = mods.length;
16333         
16334         var _this = this;
16335         var progressRun = function() {
16336             if (!mods.length) {
16337                 Roo.debug && Roo.log('hide?');
16338                 if (!this.hideProgress && Roo.MessageBox) {
16339                     Roo.MessageBox.hide();
16340                 }
16341                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16342                 
16343                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16344                 
16345                 // THE END...
16346                 return false;   
16347             }
16348             
16349             var m = mods.shift();
16350             
16351             
16352             Roo.debug && Roo.log(m);
16353             // not sure if this is supported any more.. - modules that are are just function
16354             if (typeof(m) == 'function') { 
16355                 m.call(this);
16356                 return progressRun.defer(10, _this);
16357             } 
16358             
16359             
16360             msg = "Building Interface " + (total  - mods.length) + 
16361                     " of " + total + 
16362                     (m.name ? (' - ' + m.name) : '');
16363                         Roo.debug && Roo.log(msg);
16364             if (!this.hideProgress &&  Roo.MessageBox) { 
16365                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16366             }
16367             
16368          
16369             // is the module disabled?
16370             var disabled = (typeof(m.disabled) == 'function') ?
16371                 m.disabled.call(m.module.disabled) : m.disabled;    
16372             
16373             
16374             if (disabled) {
16375                 return progressRun(); // we do not update the display!
16376             }
16377             
16378             // now build 
16379             
16380                         
16381                         
16382             m.render();
16383             // it's 10 on top level, and 1 on others??? why...
16384             return progressRun.defer(10, _this);
16385              
16386         }
16387         progressRun.defer(1, _this);
16388      
16389         
16390         
16391     },
16392         
16393         
16394         /**
16395          * Event Object.
16396          *
16397          *
16398          */
16399         event: false, 
16400     /**
16401          * wrapper for event.on - aliased later..  
16402          * Typically use to register a event handler for register:
16403          *
16404          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16405          *
16406          */
16407     on : false
16408    
16409     
16410     
16411 });
16412
16413 Roo.XComponent.event = new Roo.util.Observable({
16414                 events : { 
16415                         /**
16416                          * @event register
16417                          * Fires when an Component is registered,
16418                          * set the disable property on the Component to stop registration.
16419                          * @param {Roo.XComponent} c the component being registerd.
16420                          * 
16421                          */
16422                         'register' : true,
16423             /**
16424                          * @event beforebuild
16425                          * Fires before each Component is built
16426                          * can be used to apply permissions.
16427                          * @param {Roo.XComponent} c the component being registerd.
16428                          * 
16429                          */
16430                         'beforebuild' : true,
16431                         /**
16432                          * @event buildcomplete
16433                          * Fires on the top level element when all elements have been built
16434                          * @param {Roo.XComponent} the top level component.
16435                          */
16436                         'buildcomplete' : true
16437                         
16438                 }
16439 });
16440
16441 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16442