roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64         isTouch =  'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123         
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618         /** @type Boolean */
619         isTouch : isTouch,
620
621         /**
622          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623          * you may want to set this to true.
624          * @type Boolean
625          */
626         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
627         
628         
629                 
630         /**
631          * Selects a single element as a Roo Element
632          * This is about as close as you can get to jQuery's $('do crazy stuff')
633          * @param {String} selector The selector/xpath query
634          * @param {Node} root (optional) The start of the query (defaults to document).
635          * @return {Roo.Element}
636          */
637         selectNode : function(selector, root) 
638         {
639             var node = Roo.DomQuery.selectNode(selector,root);
640             return node ? Roo.get(node) : new Roo.Element(false);
641         }
642         
643     });
644
645
646 })();
647
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 /*
651  * Based on:
652  * Ext JS Library 1.1.1
653  * Copyright(c) 2006-2007, Ext JS, LLC.
654  *
655  * Originally Released Under LGPL - original licence link has changed is not relivant.
656  *
657  * Fork - LGPL
658  * <script type="text/javascript">
659  */
660
661 (function() {    
662     // wrappedn so fnCleanup is not in global scope...
663     if(Roo.isIE) {
664         function fnCleanUp() {
665             var p = Function.prototype;
666             delete p.createSequence;
667             delete p.defer;
668             delete p.createDelegate;
669             delete p.createCallback;
670             delete p.createInterceptor;
671
672             window.detachEvent("onunload", fnCleanUp);
673         }
674         window.attachEvent("onunload", fnCleanUp);
675     }
676 })();
677
678
679 /**
680  * @class Function
681  * These functions are available on every Function object (any JavaScript function).
682  */
683 Roo.apply(Function.prototype, {
684      /**
685      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687      * Will create a function that is bound to those 2 args.
688      * @return {Function} The new function
689     */
690     createCallback : function(/*args...*/){
691         // make args available, in function below
692         var args = arguments;
693         var method = this;
694         return function() {
695             return method.apply(window, args);
696         };
697     },
698
699     /**
700      * Creates a delegate (callback) that sets the scope to obj.
701      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702      * Will create a function that is automatically scoped to this.
703      * @param {Object} obj (optional) The object for which the scope is set
704      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706      *                                             if a number the args are inserted at the specified position
707      * @return {Function} The new function
708      */
709     createDelegate : function(obj, args, appendArgs){
710         var method = this;
711         return function() {
712             var callArgs = args || arguments;
713             if(appendArgs === true){
714                 callArgs = Array.prototype.slice.call(arguments, 0);
715                 callArgs = callArgs.concat(args);
716             }else if(typeof appendArgs == "number"){
717                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
720             }
721             return method.apply(obj || window, callArgs);
722         };
723     },
724
725     /**
726      * Calls this function after the number of millseconds specified.
727      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728      * @param {Object} obj (optional) The object for which the scope is set
729      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731      *                                             if a number the args are inserted at the specified position
732      * @return {Number} The timeout id that can be used with clearTimeout
733      */
734     defer : function(millis, obj, args, appendArgs){
735         var fn = this.createDelegate(obj, args, appendArgs);
736         if(millis){
737             return setTimeout(fn, millis);
738         }
739         fn();
740         return 0;
741     },
742     /**
743      * Create a combined function call sequence of the original function + the passed function.
744      * The resulting function returns the results of the original function.
745      * The passed fcn is called with the parameters of the original function
746      * @param {Function} fcn The function to sequence
747      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748      * @return {Function} The new function
749      */
750     createSequence : function(fcn, scope){
751         if(typeof fcn != "function"){
752             return this;
753         }
754         var method = this;
755         return function() {
756             var retval = method.apply(this || window, arguments);
757             fcn.apply(scope || this || window, arguments);
758             return retval;
759         };
760     },
761
762     /**
763      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function.
766      * @addon
767      * @param {Function} fcn The function to call before the original
768      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769      * @return {Function} The new function
770      */
771     createInterceptor : function(fcn, scope){
772         if(typeof fcn != "function"){
773             return this;
774         }
775         var method = this;
776         return function() {
777             fcn.target = this;
778             fcn.method = method;
779             if(fcn.apply(scope || this || window, arguments) === false){
780                 return;
781             }
782             return method.apply(this || window, arguments);
783         };
784     }
785 });
786 /*
787  * Based on:
788  * Ext JS Library 1.1.1
789  * Copyright(c) 2006-2007, Ext JS, LLC.
790  *
791  * Originally Released Under LGPL - original licence link has changed is not relivant.
792  *
793  * Fork - LGPL
794  * <script type="text/javascript">
795  */
796
797 Roo.applyIf(String, {
798     
799     /** @scope String */
800     
801     /**
802      * Escapes the passed string for ' and \
803      * @param {String} string The string to escape
804      * @return {String} The escaped string
805      * @static
806      */
807     escape : function(string) {
808         return string.replace(/('|\\)/g, "\\$1");
809     },
810
811     /**
812      * Pads the left side of a string with a specified character.  This is especially useful
813      * for normalizing number and date strings.  Example usage:
814      * <pre><code>
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
817 </code></pre>
818      * @param {String} string The original string
819      * @param {Number} size The total length of the output string
820      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821      * @return {String} The padded string
822      * @static
823      */
824     leftPad : function (val, size, ch) {
825         var result = new String(val);
826         if(ch === null || ch === undefined || ch === '') {
827             ch = " ";
828         }
829         while (result.length < size) {
830             result = ch + result;
831         }
832         return result;
833     },
834
835     /**
836      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
837      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
838      * <pre><code>
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
842 </code></pre>
843      * @param {String} string The tokenized string to be formatted
844      * @param {String} value1 The value to replace token {0}
845      * @param {String} value2 Etc...
846      * @return {String} The formatted string
847      * @static
848      */
849     format : function(format){
850         var args = Array.prototype.slice.call(arguments, 1);
851         return format.replace(/\{(\d+)\}/g, function(m, i){
852             return Roo.util.Format.htmlEncode(args[i]);
853         });
854     }
855 });
856
857 /**
858  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
859  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
860  * they are already different, the first value passed in is returned.  Note that this method returns the new value
861  * but does not change the current string.
862  * <pre><code>
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
865
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
868 </code></pre>
869  * @param {String} value The value to compare to the current string
870  * @param {String} other The new value to use if the string already equals the first value passed in
871  * @return {String} The new value
872  */
873  
874 String.prototype.toggle = function(value, other){
875     return this == value ? other : value;
876 };/*
877  * Based on:
878  * Ext JS Library 1.1.1
879  * Copyright(c) 2006-2007, Ext JS, LLC.
880  *
881  * Originally Released Under LGPL - original licence link has changed is not relivant.
882  *
883  * Fork - LGPL
884  * <script type="text/javascript">
885  */
886
887  /**
888  * @class Number
889  */
890 Roo.applyIf(Number.prototype, {
891     /**
892      * Checks whether or not the current number is within a desired range.  If the number is already within the
893      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894      * exceeded.  Note that this method returns the constrained value but does not change the current number.
895      * @param {Number} min The minimum number in the range
896      * @param {Number} max The maximum number in the range
897      * @return {Number} The constrained value if outside the range, otherwise the current value
898      */
899     constrain : function(min, max){
900         return Math.min(Math.max(this, min), max);
901     }
902 });/*
903  * Based on:
904  * Ext JS Library 1.1.1
905  * Copyright(c) 2006-2007, Ext JS, LLC.
906  *
907  * Originally Released Under LGPL - original licence link has changed is not relivant.
908  *
909  * Fork - LGPL
910  * <script type="text/javascript">
911  */
912  /**
913  * @class Array
914  */
915 Roo.applyIf(Array.prototype, {
916     /**
917      * Checks whether or not the specified object exists in the array.
918      * @param {Object} o The object to check for
919      * @return {Number} The index of o in the array (or -1 if it is not found)
920      */
921     indexOf : function(o){
922        for (var i = 0, len = this.length; i < len; i++){
923               if(this[i] == o) return i;
924        }
925            return -1;
926     },
927
928     /**
929      * Removes the specified object from the array.  If the object is not found nothing happens.
930      * @param {Object} o The object to remove
931      */
932     remove : function(o){
933        var index = this.indexOf(o);
934        if(index != -1){
935            this.splice(index, 1);
936        }
937     },
938     /**
939      * Map (JS 1.6 compatibility)
940      * @param {Function} function  to call
941      */
942     map : function(fun )
943     {
944         var len = this.length >>> 0;
945         if (typeof fun != "function")
946             throw new TypeError();
947
948         var res = new Array(len);
949         var thisp = arguments[1];
950         for (var i = 0; i < len; i++)
951         {
952             if (i in this)
953                 res[i] = fun.call(thisp, this[i], i, this);
954         }
955
956         return res;
957     }
958     
959 });
960
961
962  /*
963  * Based on:
964  * Ext JS Library 1.1.1
965  * Copyright(c) 2006-2007, Ext JS, LLC.
966  *
967  * Originally Released Under LGPL - original licence link has changed is not relivant.
968  *
969  * Fork - LGPL
970  * <script type="text/javascript">
971  */
972
973 /**
974  * @class Date
975  *
976  * The date parsing and format syntax is a subset of
977  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978  * supported will provide results equivalent to their PHP versions.
979  *
980  * Following is the list of all currently supported formats:
981  *<pre>
982 Sample date:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
984
985 Format  Output      Description
986 ------  ----------  --------------------------------------------------------------
987   d      10         Day of the month, 2 digits with leading zeros
988   D      Wed        A textual representation of a day, three letters
989   j      10         Day of the month without leading zeros
990   l      Wednesday  A full textual representation of the day of the week
991   S      th         English ordinal day of month suffix, 2 chars (use with j)
992   w      3          Numeric representation of the day of the week
993   z      9          The julian date, or day of the year (0-365)
994   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995   F      January    A full textual representation of the month
996   m      01         Numeric representation of a month, with leading zeros
997   M      Jan        Month name abbreviation, three letters
998   n      1          Numeric representation of a month, without leading zeros
999   t      31         Number of days in the given month
1000   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1001   Y      2007       A full numeric representation of a year, 4 digits
1002   y      07         A two digit representation of a year
1003   a      pm         Lowercase Ante meridiem and Post meridiem
1004   A      PM         Uppercase Ante meridiem and Post meridiem
1005   g      3          12-hour format of an hour without leading zeros
1006   G      15         24-hour format of an hour without leading zeros
1007   h      03         12-hour format of an hour with leading zeros
1008   H      15         24-hour format of an hour with leading zeros
1009   i      05         Minutes with leading zeros
1010   s      01         Seconds, with leading zeros
1011   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1013   T      CST        Timezone setting of the machine running the code
1014   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1015 </pre>
1016  *
1017  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1018  * <pre><code>
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d'));                         //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1023  </code></pre>
1024  *
1025  * Here are some standard date/time patterns that you might find helpful.  They
1026  * are not part of the source of Date.js, but to use them you can simply copy this
1027  * block of code into any script that is included after Date.js and they will also become
1028  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1029  * <pre><code>
1030 Date.patterns = {
1031     ISO8601Long:"Y-m-d H:i:s",
1032     ISO8601Short:"Y-m-d",
1033     ShortDate: "n/j/Y",
1034     LongDate: "l, F d, Y",
1035     FullDateTime: "l, F d, Y g:i:s A",
1036     MonthDay: "F d",
1037     ShortTime: "g:i A",
1038     LongTime: "g:i:s A",
1039     SortableDateTime: "Y-m-d\\TH:i:s",
1040     UniversalSortableDateTime: "Y-m-d H:i:sO",
1041     YearMonth: "F, Y"
1042 };
1043 </code></pre>
1044  *
1045  * Example usage:
1046  * <pre><code>
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1049  </code></pre>
1050  */
1051
1052 /*
1053  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054  * They generate precompiled functions from date formats instead of parsing and
1055  * processing the pattern every time you format a date.  These functions are available
1056  * on every Date object (any javascript function).
1057  *
1058  * The original article and download are here:
1059  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1060  *
1061  */
1062  
1063  
1064  // was in core
1065 /**
1066  Returns the number of milliseconds between this date and date
1067  @param {Date} date (optional) Defaults to now
1068  @return {Number} The diff in milliseconds
1069  @member Date getElapsed
1070  */
1071 Date.prototype.getElapsed = function(date) {
1072         return Math.abs((date || new Date()).getTime()-this.getTime());
1073 };
1074 // was in date file..
1075
1076
1077 // private
1078 Date.parseFunctions = {count:0};
1079 // private
1080 Date.parseRegexes = [];
1081 // private
1082 Date.formatFunctions = {count:0};
1083
1084 // private
1085 Date.prototype.dateFormat = function(format) {
1086     if (Date.formatFunctions[format] == null) {
1087         Date.createNewFormat(format);
1088     }
1089     var func = Date.formatFunctions[format];
1090     return this[func]();
1091 };
1092
1093
1094 /**
1095  * Formats a date given the supplied format string
1096  * @param {String} format The format string
1097  * @return {String} The formatted date
1098  * @method
1099  */
1100 Date.prototype.format = Date.prototype.dateFormat;
1101
1102 // private
1103 Date.createNewFormat = function(format) {
1104     var funcName = "format" + Date.formatFunctions.count++;
1105     Date.formatFunctions[format] = funcName;
1106     var code = "Date.prototype." + funcName + " = function(){return ";
1107     var special = false;
1108     var ch = '';
1109     for (var i = 0; i < format.length; ++i) {
1110         ch = format.charAt(i);
1111         if (!special && ch == "\\") {
1112             special = true;
1113         }
1114         else if (special) {
1115             special = false;
1116             code += "'" + String.escape(ch) + "' + ";
1117         }
1118         else {
1119             code += Date.getFormatCode(ch);
1120         }
1121     }
1122     /** eval:var:zzzzzzzzzzzzz */
1123     eval(code.substring(0, code.length - 3) + ";}");
1124 };
1125
1126 // private
1127 Date.getFormatCode = function(character) {
1128     switch (character) {
1129     case "d":
1130         return "String.leftPad(this.getDate(), 2, '0') + ";
1131     case "D":
1132         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1133     case "j":
1134         return "this.getDate() + ";
1135     case "l":
1136         return "Date.dayNames[this.getDay()] + ";
1137     case "S":
1138         return "this.getSuffix() + ";
1139     case "w":
1140         return "this.getDay() + ";
1141     case "z":
1142         return "this.getDayOfYear() + ";
1143     case "W":
1144         return "this.getWeekOfYear() + ";
1145     case "F":
1146         return "Date.monthNames[this.getMonth()] + ";
1147     case "m":
1148         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1149     case "M":
1150         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1151     case "n":
1152         return "(this.getMonth() + 1) + ";
1153     case "t":
1154         return "this.getDaysInMonth() + ";
1155     case "L":
1156         return "(this.isLeapYear() ? 1 : 0) + ";
1157     case "Y":
1158         return "this.getFullYear() + ";
1159     case "y":
1160         return "('' + this.getFullYear()).substring(2, 4) + ";
1161     case "a":
1162         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1163     case "A":
1164         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1165     case "g":
1166         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1167     case "G":
1168         return "this.getHours() + ";
1169     case "h":
1170         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1171     case "H":
1172         return "String.leftPad(this.getHours(), 2, '0') + ";
1173     case "i":
1174         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1175     case "s":
1176         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1177     case "O":
1178         return "this.getGMTOffset() + ";
1179     case "P":
1180         return "this.getGMTColonOffset() + ";
1181     case "T":
1182         return "this.getTimezone() + ";
1183     case "Z":
1184         return "(this.getTimezoneOffset() * -60) + ";
1185     default:
1186         return "'" + String.escape(character) + "' + ";
1187     }
1188 };
1189
1190 /**
1191  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1193  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1194  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1195  * string or the parse operation will fail.
1196  * Example Usage:
1197 <pre><code>
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1200
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1203
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1206
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1209 </code></pre>
1210  * @param {String} input The unparsed date as a string
1211  * @param {String} format The format the date is in
1212  * @return {Date} The parsed date
1213  * @static
1214  */
1215 Date.parseDate = function(input, format) {
1216     if (Date.parseFunctions[format] == null) {
1217         Date.createParser(format);
1218     }
1219     var func = Date.parseFunctions[format];
1220     return Date[func](input);
1221 };
1222 /**
1223  * @private
1224  */
1225 Date.createParser = function(format) {
1226     var funcName = "parse" + Date.parseFunctions.count++;
1227     var regexNum = Date.parseRegexes.length;
1228     var currentGroup = 1;
1229     Date.parseFunctions[format] = funcName;
1230
1231     var code = "Date." + funcName + " = function(input){\n"
1232         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233         + "var d = new Date();\n"
1234         + "y = d.getFullYear();\n"
1235         + "m = d.getMonth();\n"
1236         + "d = d.getDate();\n"
1237         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238         + "if (results && results.length > 0) {";
1239     var regex = "";
1240
1241     var special = false;
1242     var ch = '';
1243     for (var i = 0; i < format.length; ++i) {
1244         ch = format.charAt(i);
1245         if (!special && ch == "\\") {
1246             special = true;
1247         }
1248         else if (special) {
1249             special = false;
1250             regex += String.escape(ch);
1251         }
1252         else {
1253             var obj = Date.formatCodeToRegex(ch, currentGroup);
1254             currentGroup += obj.g;
1255             regex += obj.s;
1256             if (obj.g && obj.c) {
1257                 code += obj.c;
1258             }
1259         }
1260     }
1261
1262     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i, s);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265         + "{v = new Date(y, m, d, h, i);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267         + "{v = new Date(y, m, d, h);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269         + "{v = new Date(y, m, d);}\n"
1270         + "else if (y >= 0 && m >= 0)\n"
1271         + "{v = new Date(y, m);}\n"
1272         + "else if (y >= 0)\n"
1273         + "{v = new Date(y);}\n"
1274         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277         + ";}";
1278
1279     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280     /** eval:var:zzzzzzzzzzzzz */
1281     eval(code);
1282 };
1283
1284 // private
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286     switch (character) {
1287     case "D":
1288         return {g:0,
1289         c:null,
1290         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291     case "j":
1292         return {g:1,
1293             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294             s:"(\\d{1,2})"}; // day of month without leading zeroes
1295     case "d":
1296         return {g:1,
1297             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{2})"}; // day of month with leading zeroes
1299     case "l":
1300         return {g:0,
1301             c:null,
1302             s:"(?:" + Date.dayNames.join("|") + ")"};
1303     case "S":
1304         return {g:0,
1305             c:null,
1306             s:"(?:st|nd|rd|th)"};
1307     case "w":
1308         return {g:0,
1309             c:null,
1310             s:"\\d"};
1311     case "z":
1312         return {g:0,
1313             c:null,
1314             s:"(?:\\d{1,3})"};
1315     case "W":
1316         return {g:0,
1317             c:null,
1318             s:"(?:\\d{2})"};
1319     case "F":
1320         return {g:1,
1321             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322             s:"(" + Date.monthNames.join("|") + ")"};
1323     case "M":
1324         return {g:1,
1325             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327     case "n":
1328         return {g:1,
1329             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331     case "m":
1332         return {g:1,
1333             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1335     case "t":
1336         return {g:0,
1337             c:null,
1338             s:"\\d{1,2}"};
1339     case "L":
1340         return {g:0,
1341             c:null,
1342             s:"(?:1|0)"};
1343     case "Y":
1344         return {g:1,
1345             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1346             s:"(\\d{4})"};
1347     case "y":
1348         return {g:1,
1349             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1351             s:"(\\d{1,2})"};
1352     case "a":
1353         return {g:1,
1354             c:"if (results[" + currentGroup + "] == 'am') {\n"
1355                 + "if (h == 12) { h = 0; }\n"
1356                 + "} else { if (h < 12) { h += 12; }}",
1357             s:"(am|pm)"};
1358     case "A":
1359         return {g:1,
1360             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361                 + "if (h == 12) { h = 0; }\n"
1362                 + "} else { if (h < 12) { h += 12; }}",
1363             s:"(AM|PM)"};
1364     case "g":
1365     case "G":
1366         return {g:1,
1367             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1369     case "h":
1370     case "H":
1371         return {g:1,
1372             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1374     case "i":
1375         return {g:1,
1376             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1377             s:"(\\d{2})"};
1378     case "s":
1379         return {g:1,
1380             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{2})"};
1382     case "O":
1383         return {g:1,
1384             c:[
1385                 "o = results[", currentGroup, "];\n",
1386                 "var sn = o.substring(0,1);\n", // get + / - sign
1387                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391             ].join(""),
1392             s:"([+\-]\\d{2,4})"};
1393     
1394     
1395     case "P":
1396         return {g:1,
1397                 c:[
1398                    "o = results[", currentGroup, "];\n",
1399                    "var sn = o.substring(0,1);\n",
1400                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401                    "var mn = o.substring(4,6) % 60;\n",
1402                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1404             ].join(""),
1405             s:"([+\-]\\d{4})"};
1406     case "T":
1407         return {g:0,
1408             c:null,
1409             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410     case "Z":
1411         return {g:1,
1412             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1415     default:
1416         return {g:0,
1417             c:null,
1418             s:String.escape(character)};
1419     }
1420 };
1421
1422 /**
1423  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424  * @return {String} The abbreviated timezone name (e.g. 'CST')
1425  */
1426 Date.prototype.getTimezone = function() {
1427     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1428 };
1429
1430 /**
1431  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1433  */
1434 Date.prototype.getGMTOffset = function() {
1435     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1438 };
1439
1440 /**
1441  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442  * @return {String} 2-characters representing hours and 2-characters representing minutes
1443  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1444  */
1445 Date.prototype.getGMTColonOffset = function() {
1446         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1448                 + ":"
1449                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1450 }
1451
1452 /**
1453  * Get the numeric day number of the year, adjusted for leap year.
1454  * @return {Number} 0 through 364 (365 in leap years)
1455  */
1456 Date.prototype.getDayOfYear = function() {
1457     var num = 0;
1458     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459     for (var i = 0; i < this.getMonth(); ++i) {
1460         num += Date.daysInMonth[i];
1461     }
1462     return num + this.getDate() - 1;
1463 };
1464
1465 /**
1466  * Get the string representation of the numeric week number of the year
1467  * (equivalent to the format specifier 'W').
1468  * @return {String} '00' through '52'
1469  */
1470 Date.prototype.getWeekOfYear = function() {
1471     // Skip to Thursday of this week
1472     var now = this.getDayOfYear() + (4 - this.getDay());
1473     // Find the first Thursday of the year
1474     var jan1 = new Date(this.getFullYear(), 0, 1);
1475     var then = (7 - jan1.getDay() + 4);
1476     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1477 };
1478
1479 /**
1480  * Whether or not the current date is in a leap year.
1481  * @return {Boolean} True if the current date is in a leap year, else false
1482  */
1483 Date.prototype.isLeapYear = function() {
1484     var year = this.getFullYear();
1485     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1486 };
1487
1488 /**
1489  * Get the first day of the current month, adjusted for leap year.  The returned value
1490  * is the numeric day index within the week (0-6) which can be used in conjunction with
1491  * the {@link #monthNames} array to retrieve the textual day name.
1492  * Example:
1493  *<pre><code>
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1496 </code></pre>
1497  * @return {Number} The day number (0-6)
1498  */
1499 Date.prototype.getFirstDayOfMonth = function() {
1500     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501     return (day < 0) ? (day + 7) : day;
1502 };
1503
1504 /**
1505  * Get the last day of the current month, adjusted for leap year.  The returned value
1506  * is the numeric day index within the week (0-6) which can be used in conjunction with
1507  * the {@link #monthNames} array to retrieve the textual day name.
1508  * Example:
1509  *<pre><code>
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1512 </code></pre>
1513  * @return {Number} The day number (0-6)
1514  */
1515 Date.prototype.getLastDayOfMonth = function() {
1516     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517     return (day < 0) ? (day + 7) : day;
1518 };
1519
1520
1521 /**
1522  * Get the first date of this date's month
1523  * @return {Date}
1524  */
1525 Date.prototype.getFirstDateOfMonth = function() {
1526     return new Date(this.getFullYear(), this.getMonth(), 1);
1527 };
1528
1529 /**
1530  * Get the last date of this date's month
1531  * @return {Date}
1532  */
1533 Date.prototype.getLastDateOfMonth = function() {
1534     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 };
1536 /**
1537  * Get the number of days in the current month, adjusted for leap year.
1538  * @return {Number} The number of days in the month
1539  */
1540 Date.prototype.getDaysInMonth = function() {
1541     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542     return Date.daysInMonth[this.getMonth()];
1543 };
1544
1545 /**
1546  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547  * @return {String} 'st, 'nd', 'rd' or 'th'
1548  */
1549 Date.prototype.getSuffix = function() {
1550     switch (this.getDate()) {
1551         case 1:
1552         case 21:
1553         case 31:
1554             return "st";
1555         case 2:
1556         case 22:
1557             return "nd";
1558         case 3:
1559         case 23:
1560             return "rd";
1561         default:
1562             return "th";
1563     }
1564 };
1565
1566 // private
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568
1569 /**
1570  * An array of textual month names.
1571  * Override these values for international dates, for example...
1572  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1573  * @type Array
1574  * @static
1575  */
1576 Date.monthNames =
1577    ["January",
1578     "February",
1579     "March",
1580     "April",
1581     "May",
1582     "June",
1583     "July",
1584     "August",
1585     "September",
1586     "October",
1587     "November",
1588     "December"];
1589
1590 /**
1591  * An array of textual day names.
1592  * Override these values for international dates, for example...
1593  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1594  * @type Array
1595  * @static
1596  */
1597 Date.dayNames =
1598    ["Sunday",
1599     "Monday",
1600     "Tuesday",
1601     "Wednesday",
1602     "Thursday",
1603     "Friday",
1604     "Saturday"];
1605
1606 // private
1607 Date.y2kYear = 50;
1608 // private
1609 Date.monthNumbers = {
1610     Jan:0,
1611     Feb:1,
1612     Mar:2,
1613     Apr:3,
1614     May:4,
1615     Jun:5,
1616     Jul:6,
1617     Aug:7,
1618     Sep:8,
1619     Oct:9,
1620     Nov:10,
1621     Dec:11};
1622
1623 /**
1624  * Creates and returns a new Date instance with the exact same date value as the called instance.
1625  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626  * variable will also be changed.  When the intention is to create a new variable that will not
1627  * modify the original instance, you should create a clone.
1628  *
1629  * Example of correctly cloning a date:
1630  * <pre><code>
1631 //wrong way:
1632 var orig = new Date('10/1/2006');
1633 var copy = orig;
1634 copy.setDate(5);
1635 document.write(orig);  //returns 'Thu Oct 05 2006'!
1636
1637 //correct way:
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1640 copy.setDate(5);
1641 document.write(orig);  //returns 'Thu Oct 01 2006'
1642 </code></pre>
1643  * @return {Date} The new Date instance
1644  */
1645 Date.prototype.clone = function() {
1646         return new Date(this.getTime());
1647 };
1648
1649 /**
1650  * Clears any time information from this date
1651  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652  @return {Date} this or the clone
1653  */
1654 Date.prototype.clearTime = function(clone){
1655     if(clone){
1656         return this.clone().clearTime();
1657     }
1658     this.setHours(0);
1659     this.setMinutes(0);
1660     this.setSeconds(0);
1661     this.setMilliseconds(0);
1662     return this;
1663 };
1664
1665 // private
1666 // safari setMonth is broken
1667 if(Roo.isSafari){
1668     Date.brokenSetMonth = Date.prototype.setMonth;
1669         Date.prototype.setMonth = function(num){
1670                 if(num <= -1){
1671                         var n = Math.ceil(-num);
1672                         var back_year = Math.ceil(n/12);
1673                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1674                         this.setFullYear(this.getFullYear() - back_year);
1675                         return Date.brokenSetMonth.call(this, month);
1676                 } else {
1677                         return Date.brokenSetMonth.apply(this, arguments);
1678                 }
1679         };
1680 }
1681
1682 /** Date interval constant 
1683 * @static 
1684 * @type String */
1685 Date.MILLI = "ms";
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.SECOND = "s";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.MINUTE = "mi";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.HOUR = "h";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.DAY = "d";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MONTH = "mo";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.YEAR = "y";
1710
1711 /**
1712  * Provides a convenient method of performing basic date arithmetic.  This method
1713  * does not modify the Date instance being called - it creates and returns
1714  * a new Date instance containing the resulting date value.
1715  *
1716  * Examples:
1717  * <pre><code>
1718 //Basic usage:
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1721
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1725
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729  </code></pre>
1730  *
1731  * @param {String} interval   A valid date interval enum value
1732  * @param {Number} value      The amount to add to the current date
1733  * @return {Date} The new Date instance
1734  */
1735 Date.prototype.add = function(interval, value){
1736   var d = this.clone();
1737   if (!interval || value === 0) return d;
1738   switch(interval.toLowerCase()){
1739     case Date.MILLI:
1740       d.setMilliseconds(this.getMilliseconds() + value);
1741       break;
1742     case Date.SECOND:
1743       d.setSeconds(this.getSeconds() + value);
1744       break;
1745     case Date.MINUTE:
1746       d.setMinutes(this.getMinutes() + value);
1747       break;
1748     case Date.HOUR:
1749       d.setHours(this.getHours() + value);
1750       break;
1751     case Date.DAY:
1752       d.setDate(this.getDate() + value);
1753       break;
1754     case Date.MONTH:
1755       var day = this.getDate();
1756       if(day > 28){
1757           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758       }
1759       d.setDate(day);
1760       d.setMonth(this.getMonth() + value);
1761       break;
1762     case Date.YEAR:
1763       d.setFullYear(this.getFullYear() + value);
1764       break;
1765   }
1766   return d;
1767 };
1768 /*
1769  * Based on:
1770  * Ext JS Library 1.1.1
1771  * Copyright(c) 2006-2007, Ext JS, LLC.
1772  *
1773  * Originally Released Under LGPL - original licence link has changed is not relivant.
1774  *
1775  * Fork - LGPL
1776  * <script type="text/javascript">
1777  */
1778
1779 /**
1780  * @class Roo.lib.Dom
1781  * @static
1782  * 
1783  * Dom utils (from YIU afaik)
1784  * 
1785  **/
1786 Roo.lib.Dom = {
1787     /**
1788      * Get the view width
1789      * @param {Boolean} full True will get the full document, otherwise it's the view width
1790      * @return {Number} The width
1791      */
1792      
1793     getViewWidth : function(full) {
1794         return full ? this.getDocumentWidth() : this.getViewportWidth();
1795     },
1796     /**
1797      * Get the view height
1798      * @param {Boolean} full True will get the full document, otherwise it's the view height
1799      * @return {Number} The height
1800      */
1801     getViewHeight : function(full) {
1802         return full ? this.getDocumentHeight() : this.getViewportHeight();
1803     },
1804
1805     getDocumentHeight: function() {
1806         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807         return Math.max(scrollHeight, this.getViewportHeight());
1808     },
1809
1810     getDocumentWidth: function() {
1811         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812         return Math.max(scrollWidth, this.getViewportWidth());
1813     },
1814
1815     getViewportHeight: function() {
1816         var height = self.innerHeight;
1817         var mode = document.compatMode;
1818
1819         if ((mode || Roo.isIE) && !Roo.isOpera) {
1820             height = (mode == "CSS1Compat") ?
1821                      document.documentElement.clientHeight :
1822                      document.body.clientHeight;
1823         }
1824
1825         return height;
1826     },
1827
1828     getViewportWidth: function() {
1829         var width = self.innerWidth;
1830         var mode = document.compatMode;
1831
1832         if (mode || Roo.isIE) {
1833             width = (mode == "CSS1Compat") ?
1834                     document.documentElement.clientWidth :
1835                     document.body.clientWidth;
1836         }
1837         return width;
1838     },
1839
1840     isAncestor : function(p, c) {
1841         p = Roo.getDom(p);
1842         c = Roo.getDom(c);
1843         if (!p || !c) {
1844             return false;
1845         }
1846
1847         if (p.contains && !Roo.isSafari) {
1848             return p.contains(c);
1849         } else if (p.compareDocumentPosition) {
1850             return !!(p.compareDocumentPosition(c) & 16);
1851         } else {
1852             var parent = c.parentNode;
1853             while (parent) {
1854                 if (parent == p) {
1855                     return true;
1856                 }
1857                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858                     return false;
1859                 }
1860                 parent = parent.parentNode;
1861             }
1862             return false;
1863         }
1864     },
1865
1866     getRegion : function(el) {
1867         return Roo.lib.Region.getRegion(el);
1868     },
1869
1870     getY : function(el) {
1871         return this.getXY(el)[1];
1872     },
1873
1874     getX : function(el) {
1875         return this.getXY(el)[0];
1876     },
1877
1878     getXY : function(el) {
1879         var p, pe, b, scroll, bd = document.body;
1880         el = Roo.getDom(el);
1881         var fly = Roo.lib.AnimBase.fly;
1882         if (el.getBoundingClientRect) {
1883             b = el.getBoundingClientRect();
1884             scroll = fly(document).getScroll();
1885             return [b.left + scroll.left, b.top + scroll.top];
1886         }
1887         var x = 0, y = 0;
1888
1889         p = el;
1890
1891         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1892
1893         while (p) {
1894
1895             x += p.offsetLeft;
1896             y += p.offsetTop;
1897
1898             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1899                 hasAbsolute = true;
1900             }
1901
1902             if (Roo.isGecko) {
1903                 pe = fly(p);
1904
1905                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1907
1908
1909                 x += bl;
1910                 y += bt;
1911
1912
1913                 if (p != el && pe.getStyle('overflow') != 'visible') {
1914                     x += bl;
1915                     y += bt;
1916                 }
1917             }
1918             p = p.offsetParent;
1919         }
1920
1921         if (Roo.isSafari && hasAbsolute) {
1922             x -= bd.offsetLeft;
1923             y -= bd.offsetTop;
1924         }
1925
1926         if (Roo.isGecko && !hasAbsolute) {
1927             var dbd = fly(bd);
1928             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1930         }
1931
1932         p = el.parentNode;
1933         while (p && p != bd) {
1934             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1935                 x -= p.scrollLeft;
1936                 y -= p.scrollTop;
1937             }
1938             p = p.parentNode;
1939         }
1940         return [x, y];
1941     },
1942  
1943   
1944
1945
1946     setXY : function(el, xy) {
1947         el = Roo.fly(el, '_setXY');
1948         el.position();
1949         var pts = el.translatePoints(xy);
1950         if (xy[0] !== false) {
1951             el.dom.style.left = pts.left + "px";
1952         }
1953         if (xy[1] !== false) {
1954             el.dom.style.top = pts.top + "px";
1955         }
1956     },
1957
1958     setX : function(el, x) {
1959         this.setXY(el, [x, false]);
1960     },
1961
1962     setY : function(el, y) {
1963         this.setXY(el, [false, y]);
1964     }
1965 };
1966 /*
1967  * Portions of this file are based on pieces of Yahoo User Interface Library
1968  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969  * YUI licensed under the BSD License:
1970  * http://developer.yahoo.net/yui/license.txt
1971  * <script type="text/javascript">
1972  *
1973  */
1974
1975 Roo.lib.Event = function() {
1976     var loadComplete = false;
1977     var listeners = [];
1978     var unloadListeners = [];
1979     var retryCount = 0;
1980     var onAvailStack = [];
1981     var counter = 0;
1982     var lastError = null;
1983
1984     return {
1985         POLL_RETRYS: 200,
1986         POLL_INTERVAL: 20,
1987         EL: 0,
1988         TYPE: 1,
1989         FN: 2,
1990         WFN: 3,
1991         OBJ: 3,
1992         ADJ_SCOPE: 4,
1993         _interval: null,
1994
1995         startInterval: function() {
1996             if (!this._interval) {
1997                 var self = this;
1998                 var callback = function() {
1999                     self._tryPreloadAttach();
2000                 };
2001                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2002
2003             }
2004         },
2005
2006         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007             onAvailStack.push({ id:         p_id,
2008                 fn:         p_fn,
2009                 obj:        p_obj,
2010                 override:   p_override,
2011                 checkReady: false    });
2012
2013             retryCount = this.POLL_RETRYS;
2014             this.startInterval();
2015         },
2016
2017
2018         addListener: function(el, eventName, fn) {
2019             el = Roo.getDom(el);
2020             if (!el || !fn) {
2021                 return false;
2022             }
2023
2024             if ("unload" == eventName) {
2025                 unloadListeners[unloadListeners.length] =
2026                 [el, eventName, fn];
2027                 return true;
2028             }
2029
2030             var wrappedFn = function(e) {
2031                 return fn(Roo.lib.Event.getEvent(e));
2032             };
2033
2034             var li = [el, eventName, fn, wrappedFn];
2035
2036             var index = listeners.length;
2037             listeners[index] = li;
2038
2039             this.doAdd(el, eventName, wrappedFn, false);
2040             return true;
2041
2042         },
2043
2044
2045         removeListener: function(el, eventName, fn) {
2046             var i, len;
2047
2048             el = Roo.getDom(el);
2049
2050             if(!fn) {
2051                 return this.purgeElement(el, false, eventName);
2052             }
2053
2054
2055             if ("unload" == eventName) {
2056
2057                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058                     var li = unloadListeners[i];
2059                     if (li &&
2060                         li[0] == el &&
2061                         li[1] == eventName &&
2062                         li[2] == fn) {
2063                         unloadListeners.splice(i, 1);
2064                         return true;
2065                     }
2066                 }
2067
2068                 return false;
2069             }
2070
2071             var cacheItem = null;
2072
2073
2074             var index = arguments[3];
2075
2076             if ("undefined" == typeof index) {
2077                 index = this._getCacheIndex(el, eventName, fn);
2078             }
2079
2080             if (index >= 0) {
2081                 cacheItem = listeners[index];
2082             }
2083
2084             if (!el || !cacheItem) {
2085                 return false;
2086             }
2087
2088             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2089
2090             delete listeners[index][this.WFN];
2091             delete listeners[index][this.FN];
2092             listeners.splice(index, 1);
2093
2094             return true;
2095
2096         },
2097
2098
2099         getTarget: function(ev, resolveTextNode) {
2100             ev = ev.browserEvent || ev;
2101             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2102             var t = ev.target || ev.srcElement;
2103             return this.resolveTextNode(t);
2104         },
2105
2106
2107         resolveTextNode: function(node) {
2108             if (Roo.isSafari && node && 3 == node.nodeType) {
2109                 return node.parentNode;
2110             } else {
2111                 return node;
2112             }
2113         },
2114
2115
2116         getPageX: function(ev) {
2117             ev = ev.browserEvent || ev;
2118             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2119             var x = ev.pageX;
2120             if (!x && 0 !== x) {
2121                 x = ev.clientX || 0;
2122
2123                 if (Roo.isIE) {
2124                     x += this.getScroll()[1];
2125                 }
2126             }
2127
2128             return x;
2129         },
2130
2131
2132         getPageY: function(ev) {
2133             ev = ev.browserEvent || ev;
2134             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2135             var y = ev.pageY;
2136             if (!y && 0 !== y) {
2137                 y = ev.clientY || 0;
2138
2139                 if (Roo.isIE) {
2140                     y += this.getScroll()[0];
2141                 }
2142             }
2143
2144
2145             return y;
2146         },
2147
2148
2149         getXY: function(ev) {
2150             ev = ev.browserEvent || ev;
2151             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2152             return [this.getPageX(ev), this.getPageY(ev)];
2153         },
2154
2155
2156         getRelatedTarget: function(ev) {
2157             ev = ev.browserEvent || ev;
2158             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2159             var t = ev.relatedTarget;
2160             if (!t) {
2161                 if (ev.type == "mouseout") {
2162                     t = ev.toElement;
2163                 } else if (ev.type == "mouseover") {
2164                     t = ev.fromElement;
2165                 }
2166             }
2167
2168             return this.resolveTextNode(t);
2169         },
2170
2171
2172         getTime: function(ev) {
2173             ev = ev.browserEvent || ev;
2174             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2175             if (!ev.time) {
2176                 var t = new Date().getTime();
2177                 try {
2178                     ev.time = t;
2179                 } catch(ex) {
2180                     this.lastError = ex;
2181                     return t;
2182                 }
2183             }
2184
2185             return ev.time;
2186         },
2187
2188
2189         stopEvent: function(ev) {
2190             this.stopPropagation(ev);
2191             this.preventDefault(ev);
2192         },
2193
2194
2195         stopPropagation: function(ev) {
2196             ev = ev.browserEvent || ev;
2197             if (ev.stopPropagation) {
2198                 ev.stopPropagation();
2199             } else {
2200                 ev.cancelBubble = true;
2201             }
2202         },
2203
2204
2205         preventDefault: function(ev) {
2206             ev = ev.browserEvent || ev;
2207             if(ev.preventDefault) {
2208                 ev.preventDefault();
2209             } else {
2210                 ev.returnValue = false;
2211             }
2212         },
2213
2214
2215         getEvent: function(e) {
2216             var ev = e || window.event;
2217             if (!ev) {
2218                 var c = this.getEvent.caller;
2219                 while (c) {
2220                     ev = c.arguments[0];
2221                     if (ev && Event == ev.constructor) {
2222                         break;
2223                     }
2224                     c = c.caller;
2225                 }
2226             }
2227             return ev;
2228         },
2229
2230
2231         getCharCode: function(ev) {
2232             ev = ev.browserEvent || ev;
2233             return ev.charCode || ev.keyCode || 0;
2234         },
2235
2236
2237         _getCacheIndex: function(el, eventName, fn) {
2238             for (var i = 0,len = listeners.length; i < len; ++i) {
2239                 var li = listeners[i];
2240                 if (li &&
2241                     li[this.FN] == fn &&
2242                     li[this.EL] == el &&
2243                     li[this.TYPE] == eventName) {
2244                     return i;
2245                 }
2246             }
2247
2248             return -1;
2249         },
2250
2251
2252         elCache: {},
2253
2254
2255         getEl: function(id) {
2256             return document.getElementById(id);
2257         },
2258
2259
2260         clearCache: function() {
2261         },
2262
2263
2264         _load: function(e) {
2265             loadComplete = true;
2266             var EU = Roo.lib.Event;
2267
2268
2269             if (Roo.isIE) {
2270                 EU.doRemove(window, "load", EU._load);
2271             }
2272         },
2273
2274
2275         _tryPreloadAttach: function() {
2276
2277             if (this.locked) {
2278                 return false;
2279             }
2280
2281             this.locked = true;
2282
2283
2284             var tryAgain = !loadComplete;
2285             if (!tryAgain) {
2286                 tryAgain = (retryCount > 0);
2287             }
2288
2289
2290             var notAvail = [];
2291             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292                 var item = onAvailStack[i];
2293                 if (item) {
2294                     var el = this.getEl(item.id);
2295
2296                     if (el) {
2297                         if (!item.checkReady ||
2298                             loadComplete ||
2299                             el.nextSibling ||
2300                             (document && document.body)) {
2301
2302                             var scope = el;
2303                             if (item.override) {
2304                                 if (item.override === true) {
2305                                     scope = item.obj;
2306                                 } else {
2307                                     scope = item.override;
2308                                 }
2309                             }
2310                             item.fn.call(scope, item.obj);
2311                             onAvailStack[i] = null;
2312                         }
2313                     } else {
2314                         notAvail.push(item);
2315                     }
2316                 }
2317             }
2318
2319             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2320
2321             if (tryAgain) {
2322
2323                 this.startInterval();
2324             } else {
2325                 clearInterval(this._interval);
2326                 this._interval = null;
2327             }
2328
2329             this.locked = false;
2330
2331             return true;
2332
2333         },
2334
2335
2336         purgeElement: function(el, recurse, eventName) {
2337             var elListeners = this.getListeners(el, eventName);
2338             if (elListeners) {
2339                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340                     var l = elListeners[i];
2341                     this.removeListener(el, l.type, l.fn);
2342                 }
2343             }
2344
2345             if (recurse && el && el.childNodes) {
2346                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347                     this.purgeElement(el.childNodes[i], recurse, eventName);
2348                 }
2349             }
2350         },
2351
2352
2353         getListeners: function(el, eventName) {
2354             var results = [], searchLists;
2355             if (!eventName) {
2356                 searchLists = [listeners, unloadListeners];
2357             } else if (eventName == "unload") {
2358                 searchLists = [unloadListeners];
2359             } else {
2360                 searchLists = [listeners];
2361             }
2362
2363             for (var j = 0; j < searchLists.length; ++j) {
2364                 var searchList = searchLists[j];
2365                 if (searchList && searchList.length > 0) {
2366                     for (var i = 0,len = searchList.length; i < len; ++i) {
2367                         var l = searchList[i];
2368                         if (l && l[this.EL] === el &&
2369                             (!eventName || eventName === l[this.TYPE])) {
2370                             results.push({
2371                                 type:   l[this.TYPE],
2372                                 fn:     l[this.FN],
2373                                 obj:    l[this.OBJ],
2374                                 adjust: l[this.ADJ_SCOPE],
2375                                 index:  i
2376                             });
2377                         }
2378                     }
2379                 }
2380             }
2381
2382             return (results.length) ? results : null;
2383         },
2384
2385
2386         _unload: function(e) {
2387
2388             var EU = Roo.lib.Event, i, j, l, len, index;
2389
2390             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391                 l = unloadListeners[i];
2392                 if (l) {
2393                     var scope = window;
2394                     if (l[EU.ADJ_SCOPE]) {
2395                         if (l[EU.ADJ_SCOPE] === true) {
2396                             scope = l[EU.OBJ];
2397                         } else {
2398                             scope = l[EU.ADJ_SCOPE];
2399                         }
2400                     }
2401                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402                     unloadListeners[i] = null;
2403                     l = null;
2404                     scope = null;
2405                 }
2406             }
2407
2408             unloadListeners = null;
2409
2410             if (listeners && listeners.length > 0) {
2411                 j = listeners.length;
2412                 while (j) {
2413                     index = j - 1;
2414                     l = listeners[index];
2415                     if (l) {
2416                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2417                                 l[EU.FN], index);
2418                     }
2419                     j = j - 1;
2420                 }
2421                 l = null;
2422
2423                 EU.clearCache();
2424             }
2425
2426             EU.doRemove(window, "unload", EU._unload);
2427
2428         },
2429
2430
2431         getScroll: function() {
2432             var dd = document.documentElement, db = document.body;
2433             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434                 return [dd.scrollTop, dd.scrollLeft];
2435             } else if (db) {
2436                 return [db.scrollTop, db.scrollLeft];
2437             } else {
2438                 return [0, 0];
2439             }
2440         },
2441
2442
2443         doAdd: function () {
2444             if (window.addEventListener) {
2445                 return function(el, eventName, fn, capture) {
2446                     el.addEventListener(eventName, fn, (capture));
2447                 };
2448             } else if (window.attachEvent) {
2449                 return function(el, eventName, fn, capture) {
2450                     el.attachEvent("on" + eventName, fn);
2451                 };
2452             } else {
2453                 return function() {
2454                 };
2455             }
2456         }(),
2457
2458
2459         doRemove: function() {
2460             if (window.removeEventListener) {
2461                 return function (el, eventName, fn, capture) {
2462                     el.removeEventListener(eventName, fn, (capture));
2463                 };
2464             } else if (window.detachEvent) {
2465                 return function (el, eventName, fn) {
2466                     el.detachEvent("on" + eventName, fn);
2467                 };
2468             } else {
2469                 return function() {
2470                 };
2471             }
2472         }()
2473     };
2474     
2475 }();
2476 (function() {     
2477    
2478     var E = Roo.lib.Event;
2479     E.on = E.addListener;
2480     E.un = E.removeListener;
2481
2482     if (document && document.body) {
2483         E._load();
2484     } else {
2485         E.doAdd(window, "load", E._load);
2486     }
2487     E.doAdd(window, "unload", E._unload);
2488     E._tryPreloadAttach();
2489 })();
2490
2491 /*
2492  * Portions of this file are based on pieces of Yahoo User Interface Library
2493  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494  * YUI licensed under the BSD License:
2495  * http://developer.yahoo.net/yui/license.txt
2496  * <script type="text/javascript">
2497  *
2498  */
2499
2500 (function() {
2501     /**
2502      * @class Roo.lib.Ajax
2503      *
2504      */
2505     Roo.lib.Ajax = {
2506         /**
2507          * @static 
2508          */
2509         request : function(method, uri, cb, data, options) {
2510             if(options){
2511                 var hs = options.headers;
2512                 if(hs){
2513                     for(var h in hs){
2514                         if(hs.hasOwnProperty(h)){
2515                             this.initHeader(h, hs[h], false);
2516                         }
2517                     }
2518                 }
2519                 if(options.xmlData){
2520                     this.initHeader('Content-Type', 'text/xml', false);
2521                     method = 'POST';
2522                     data = options.xmlData;
2523                 }
2524             }
2525
2526             return this.asyncRequest(method, uri, cb, data);
2527         },
2528
2529         serializeForm : function(form) {
2530             if(typeof form == 'string') {
2531                 form = (document.getElementById(form) || document.forms[form]);
2532             }
2533
2534             var el, name, val, disabled, data = '', hasSubmit = false;
2535             for (var i = 0; i < form.elements.length; i++) {
2536                 el = form.elements[i];
2537                 disabled = form.elements[i].disabled;
2538                 name = form.elements[i].name;
2539                 val = form.elements[i].value;
2540
2541                 if (!disabled && name){
2542                     switch (el.type)
2543                             {
2544                         case 'select-one':
2545                         case 'select-multiple':
2546                             for (var j = 0; j < el.options.length; j++) {
2547                                 if (el.options[j].selected) {
2548                                     if (Roo.isIE) {
2549                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2550                                     }
2551                                     else {
2552                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2553                                     }
2554                                 }
2555                             }
2556                             break;
2557                         case 'radio':
2558                         case 'checkbox':
2559                             if (el.checked) {
2560                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2561                             }
2562                             break;
2563                         case 'file':
2564
2565                         case undefined:
2566
2567                         case 'reset':
2568
2569                         case 'button':
2570
2571                             break;
2572                         case 'submit':
2573                             if(hasSubmit == false) {
2574                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2575                                 hasSubmit = true;
2576                             }
2577                             break;
2578                         default:
2579                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2580                             break;
2581                     }
2582                 }
2583             }
2584             data = data.substr(0, data.length - 1);
2585             return data;
2586         },
2587
2588         headers:{},
2589
2590         hasHeaders:false,
2591
2592         useDefaultHeader:true,
2593
2594         defaultPostHeader:'application/x-www-form-urlencoded',
2595
2596         useDefaultXhrHeader:true,
2597
2598         defaultXhrHeader:'XMLHttpRequest',
2599
2600         hasDefaultHeaders:true,
2601
2602         defaultHeaders:{},
2603
2604         poll:{},
2605
2606         timeout:{},
2607
2608         pollInterval:50,
2609
2610         transactionId:0,
2611
2612         setProgId:function(id)
2613         {
2614             this.activeX.unshift(id);
2615         },
2616
2617         setDefaultPostHeader:function(b)
2618         {
2619             this.useDefaultHeader = b;
2620         },
2621
2622         setDefaultXhrHeader:function(b)
2623         {
2624             this.useDefaultXhrHeader = b;
2625         },
2626
2627         setPollingInterval:function(i)
2628         {
2629             if (typeof i == 'number' && isFinite(i)) {
2630                 this.pollInterval = i;
2631             }
2632         },
2633
2634         createXhrObject:function(transactionId)
2635         {
2636             var obj,http;
2637             try
2638             {
2639
2640                 http = new XMLHttpRequest();
2641
2642                 obj = { conn:http, tId:transactionId };
2643             }
2644             catch(e)
2645             {
2646                 for (var i = 0; i < this.activeX.length; ++i) {
2647                     try
2648                     {
2649
2650                         http = new ActiveXObject(this.activeX[i]);
2651
2652                         obj = { conn:http, tId:transactionId };
2653                         break;
2654                     }
2655                     catch(e) {
2656                     }
2657                 }
2658             }
2659             finally
2660             {
2661                 return obj;
2662             }
2663         },
2664
2665         getConnectionObject:function()
2666         {
2667             var o;
2668             var tId = this.transactionId;
2669
2670             try
2671             {
2672                 o = this.createXhrObject(tId);
2673                 if (o) {
2674                     this.transactionId++;
2675                 }
2676             }
2677             catch(e) {
2678             }
2679             finally
2680             {
2681                 return o;
2682             }
2683         },
2684
2685         asyncRequest:function(method, uri, callback, postData)
2686         {
2687             var o = this.getConnectionObject();
2688
2689             if (!o) {
2690                 return null;
2691             }
2692             else {
2693                 o.conn.open(method, uri, true);
2694
2695                 if (this.useDefaultXhrHeader) {
2696                     if (!this.defaultHeaders['X-Requested-With']) {
2697                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2698                     }
2699                 }
2700
2701                 if(postData && this.useDefaultHeader){
2702                     this.initHeader('Content-Type', this.defaultPostHeader);
2703                 }
2704
2705                  if (this.hasDefaultHeaders || this.hasHeaders) {
2706                     this.setHeader(o);
2707                 }
2708
2709                 this.handleReadyState(o, callback);
2710                 o.conn.send(postData || null);
2711
2712                 return o;
2713             }
2714         },
2715
2716         handleReadyState:function(o, callback)
2717         {
2718             var oConn = this;
2719
2720             if (callback && callback.timeout) {
2721                 
2722                 this.timeout[o.tId] = window.setTimeout(function() {
2723                     oConn.abort(o, callback, true);
2724                 }, callback.timeout);
2725             }
2726
2727             this.poll[o.tId] = window.setInterval(
2728                     function() {
2729                         if (o.conn && o.conn.readyState == 4) {
2730                             window.clearInterval(oConn.poll[o.tId]);
2731                             delete oConn.poll[o.tId];
2732
2733                             if(callback && callback.timeout) {
2734                                 window.clearTimeout(oConn.timeout[o.tId]);
2735                                 delete oConn.timeout[o.tId];
2736                             }
2737
2738                             oConn.handleTransactionResponse(o, callback);
2739                         }
2740                     }
2741                     , this.pollInterval);
2742         },
2743
2744         handleTransactionResponse:function(o, callback, isAbort)
2745         {
2746
2747             if (!callback) {
2748                 this.releaseObject(o);
2749                 return;
2750             }
2751
2752             var httpStatus, responseObject;
2753
2754             try
2755             {
2756                 if (o.conn.status !== undefined && o.conn.status != 0) {
2757                     httpStatus = o.conn.status;
2758                 }
2759                 else {
2760                     httpStatus = 13030;
2761                 }
2762             }
2763             catch(e) {
2764
2765
2766                 httpStatus = 13030;
2767             }
2768
2769             if (httpStatus >= 200 && httpStatus < 300) {
2770                 responseObject = this.createResponseObject(o, callback.argument);
2771                 if (callback.success) {
2772                     if (!callback.scope) {
2773                         callback.success(responseObject);
2774                     }
2775                     else {
2776
2777
2778                         callback.success.apply(callback.scope, [responseObject]);
2779                     }
2780                 }
2781             }
2782             else {
2783                 switch (httpStatus) {
2784
2785                     case 12002:
2786                     case 12029:
2787                     case 12030:
2788                     case 12031:
2789                     case 12152:
2790                     case 13030:
2791                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792                         if (callback.failure) {
2793                             if (!callback.scope) {
2794                                 callback.failure(responseObject);
2795                             }
2796                             else {
2797                                 callback.failure.apply(callback.scope, [responseObject]);
2798                             }
2799                         }
2800                         break;
2801                     default:
2802                         responseObject = this.createResponseObject(o, callback.argument);
2803                         if (callback.failure) {
2804                             if (!callback.scope) {
2805                                 callback.failure(responseObject);
2806                             }
2807                             else {
2808                                 callback.failure.apply(callback.scope, [responseObject]);
2809                             }
2810                         }
2811                 }
2812             }
2813
2814             this.releaseObject(o);
2815             responseObject = null;
2816         },
2817
2818         createResponseObject:function(o, callbackArg)
2819         {
2820             var obj = {};
2821             var headerObj = {};
2822
2823             try
2824             {
2825                 var headerStr = o.conn.getAllResponseHeaders();
2826                 var header = headerStr.split('\n');
2827                 for (var i = 0; i < header.length; i++) {
2828                     var delimitPos = header[i].indexOf(':');
2829                     if (delimitPos != -1) {
2830                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2831                     }
2832                 }
2833             }
2834             catch(e) {
2835             }
2836
2837             obj.tId = o.tId;
2838             obj.status = o.conn.status;
2839             obj.statusText = o.conn.statusText;
2840             obj.getResponseHeader = headerObj;
2841             obj.getAllResponseHeaders = headerStr;
2842             obj.responseText = o.conn.responseText;
2843             obj.responseXML = o.conn.responseXML;
2844
2845             if (typeof callbackArg !== undefined) {
2846                 obj.argument = callbackArg;
2847             }
2848
2849             return obj;
2850         },
2851
2852         createExceptionObject:function(tId, callbackArg, isAbort)
2853         {
2854             var COMM_CODE = 0;
2855             var COMM_ERROR = 'communication failure';
2856             var ABORT_CODE = -1;
2857             var ABORT_ERROR = 'transaction aborted';
2858
2859             var obj = {};
2860
2861             obj.tId = tId;
2862             if (isAbort) {
2863                 obj.status = ABORT_CODE;
2864                 obj.statusText = ABORT_ERROR;
2865             }
2866             else {
2867                 obj.status = COMM_CODE;
2868                 obj.statusText = COMM_ERROR;
2869             }
2870
2871             if (callbackArg) {
2872                 obj.argument = callbackArg;
2873             }
2874
2875             return obj;
2876         },
2877
2878         initHeader:function(label, value, isDefault)
2879         {
2880             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2881
2882             if (headerObj[label] === undefined) {
2883                 headerObj[label] = value;
2884             }
2885             else {
2886
2887
2888                 headerObj[label] = value + "," + headerObj[label];
2889             }
2890
2891             if (isDefault) {
2892                 this.hasDefaultHeaders = true;
2893             }
2894             else {
2895                 this.hasHeaders = true;
2896             }
2897         },
2898
2899
2900         setHeader:function(o)
2901         {
2902             if (this.hasDefaultHeaders) {
2903                 for (var prop in this.defaultHeaders) {
2904                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2905                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2906                     }
2907                 }
2908             }
2909
2910             if (this.hasHeaders) {
2911                 for (var prop in this.headers) {
2912                     if (this.headers.hasOwnProperty(prop)) {
2913                         o.conn.setRequestHeader(prop, this.headers[prop]);
2914                     }
2915                 }
2916                 this.headers = {};
2917                 this.hasHeaders = false;
2918             }
2919         },
2920
2921         resetDefaultHeaders:function() {
2922             delete this.defaultHeaders;
2923             this.defaultHeaders = {};
2924             this.hasDefaultHeaders = false;
2925         },
2926
2927         abort:function(o, callback, isTimeout)
2928         {
2929             if(this.isCallInProgress(o)) {
2930                 o.conn.abort();
2931                 window.clearInterval(this.poll[o.tId]);
2932                 delete this.poll[o.tId];
2933                 if (isTimeout) {
2934                     delete this.timeout[o.tId];
2935                 }
2936
2937                 this.handleTransactionResponse(o, callback, true);
2938
2939                 return true;
2940             }
2941             else {
2942                 return false;
2943             }
2944         },
2945
2946
2947         isCallInProgress:function(o)
2948         {
2949             if (o && o.conn) {
2950                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2951             }
2952             else {
2953
2954                 return false;
2955             }
2956         },
2957
2958
2959         releaseObject:function(o)
2960         {
2961
2962             o.conn = null;
2963
2964             o = null;
2965         },
2966
2967         activeX:[
2968         'MSXML2.XMLHTTP.3.0',
2969         'MSXML2.XMLHTTP',
2970         'Microsoft.XMLHTTP'
2971         ]
2972
2973
2974     };
2975 })();/*
2976  * Portions of this file are based on pieces of Yahoo User Interface Library
2977  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978  * YUI licensed under the BSD License:
2979  * http://developer.yahoo.net/yui/license.txt
2980  * <script type="text/javascript">
2981  *
2982  */
2983
2984 Roo.lib.Region = function(t, r, b, l) {
2985     this.top = t;
2986     this[1] = t;
2987     this.right = r;
2988     this.bottom = b;
2989     this.left = l;
2990     this[0] = l;
2991 };
2992
2993
2994 Roo.lib.Region.prototype = {
2995     contains : function(region) {
2996         return ( region.left >= this.left &&
2997                  region.right <= this.right &&
2998                  region.top >= this.top &&
2999                  region.bottom <= this.bottom    );
3000
3001     },
3002
3003     getArea : function() {
3004         return ( (this.bottom - this.top) * (this.right - this.left) );
3005     },
3006
3007     intersect : function(region) {
3008         var t = Math.max(this.top, region.top);
3009         var r = Math.min(this.right, region.right);
3010         var b = Math.min(this.bottom, region.bottom);
3011         var l = Math.max(this.left, region.left);
3012
3013         if (b >= t && r >= l) {
3014             return new Roo.lib.Region(t, r, b, l);
3015         } else {
3016             return null;
3017         }
3018     },
3019     union : function(region) {
3020         var t = Math.min(this.top, region.top);
3021         var r = Math.max(this.right, region.right);
3022         var b = Math.max(this.bottom, region.bottom);
3023         var l = Math.min(this.left, region.left);
3024
3025         return new Roo.lib.Region(t, r, b, l);
3026     },
3027
3028     adjust : function(t, l, b, r) {
3029         this.top += t;
3030         this.left += l;
3031         this.right += r;
3032         this.bottom += b;
3033         return this;
3034     }
3035 };
3036
3037 Roo.lib.Region.getRegion = function(el) {
3038     var p = Roo.lib.Dom.getXY(el);
3039
3040     var t = p[1];
3041     var r = p[0] + el.offsetWidth;
3042     var b = p[1] + el.offsetHeight;
3043     var l = p[0];
3044
3045     return new Roo.lib.Region(t, r, b, l);
3046 };
3047 /*
3048  * Portions of this file are based on pieces of Yahoo User Interface Library
3049  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050  * YUI licensed under the BSD License:
3051  * http://developer.yahoo.net/yui/license.txt
3052  * <script type="text/javascript">
3053  *
3054  */
3055 //@@dep Roo.lib.Region
3056
3057
3058 Roo.lib.Point = function(x, y) {
3059     if (x instanceof Array) {
3060         y = x[1];
3061         x = x[0];
3062     }
3063     this.x = this.right = this.left = this[0] = x;
3064     this.y = this.top = this.bottom = this[1] = y;
3065 };
3066
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3068 /*
3069  * Portions of this file are based on pieces of Yahoo User Interface Library
3070  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071  * YUI licensed under the BSD License:
3072  * http://developer.yahoo.net/yui/license.txt
3073  * <script type="text/javascript">
3074  *
3075  */
3076  
3077 (function() {   
3078
3079     Roo.lib.Anim = {
3080         scroll : function(el, args, duration, easing, cb, scope) {
3081             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3082         },
3083
3084         motion : function(el, args, duration, easing, cb, scope) {
3085             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3086         },
3087
3088         color : function(el, args, duration, easing, cb, scope) {
3089             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3090         },
3091
3092         run : function(el, args, duration, easing, cb, scope, type) {
3093             type = type || Roo.lib.AnimBase;
3094             if (typeof easing == "string") {
3095                 easing = Roo.lib.Easing[easing];
3096             }
3097             var anim = new type(el, args, duration, easing);
3098             anim.animateX(function() {
3099                 Roo.callback(cb, scope);
3100             });
3101             return anim;
3102         }
3103     };
3104 })();/*
3105  * Portions of this file are based on pieces of Yahoo User Interface Library
3106  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107  * YUI licensed under the BSD License:
3108  * http://developer.yahoo.net/yui/license.txt
3109  * <script type="text/javascript">
3110  *
3111  */
3112
3113 (function() {    
3114     var libFlyweight;
3115     
3116     function fly(el) {
3117         if (!libFlyweight) {
3118             libFlyweight = new Roo.Element.Flyweight();
3119         }
3120         libFlyweight.dom = el;
3121         return libFlyweight;
3122     }
3123
3124     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3125     
3126    
3127     
3128     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3129         if (el) {
3130             this.init(el, attributes, duration, method);
3131         }
3132     };
3133
3134     Roo.lib.AnimBase.fly = fly;
3135     
3136     
3137     
3138     Roo.lib.AnimBase.prototype = {
3139
3140         toString: function() {
3141             var el = this.getEl();
3142             var id = el.id || el.tagName;
3143             return ("Anim " + id);
3144         },
3145
3146         patterns: {
3147             noNegatives:        /width|height|opacity|padding/i,
3148             offsetAttribute:  /^((width|height)|(top|left))$/,
3149             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3150             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3151         },
3152
3153
3154         doMethod: function(attr, start, end) {
3155             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3156         },
3157
3158
3159         setAttribute: function(attr, val, unit) {
3160             if (this.patterns.noNegatives.test(attr)) {
3161                 val = (val > 0) ? val : 0;
3162             }
3163
3164             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3165         },
3166
3167
3168         getAttribute: function(attr) {
3169             var el = this.getEl();
3170             var val = fly(el).getStyle(attr);
3171
3172             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173                 return parseFloat(val);
3174             }
3175
3176             var a = this.patterns.offsetAttribute.exec(attr) || [];
3177             var pos = !!( a[3] );
3178             var box = !!( a[2] );
3179
3180
3181             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3183             } else {
3184                 val = 0;
3185             }
3186
3187             return val;
3188         },
3189
3190
3191         getDefaultUnit: function(attr) {
3192             if (this.patterns.defaultUnit.test(attr)) {
3193                 return 'px';
3194             }
3195
3196             return '';
3197         },
3198
3199         animateX : function(callback, scope) {
3200             var f = function() {
3201                 this.onComplete.removeListener(f);
3202                 if (typeof callback == "function") {
3203                     callback.call(scope || this, this);
3204                 }
3205             };
3206             this.onComplete.addListener(f, this);
3207             this.animate();
3208         },
3209
3210
3211         setRuntimeAttribute: function(attr) {
3212             var start;
3213             var end;
3214             var attributes = this.attributes;
3215
3216             this.runtimeAttributes[attr] = {};
3217
3218             var isset = function(prop) {
3219                 return (typeof prop !== 'undefined');
3220             };
3221
3222             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3223                 return false;
3224             }
3225
3226             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3227
3228
3229             if (isset(attributes[attr]['to'])) {
3230                 end = attributes[attr]['to'];
3231             } else if (isset(attributes[attr]['by'])) {
3232                 if (start.constructor == Array) {
3233                     end = [];
3234                     for (var i = 0, len = start.length; i < len; ++i) {
3235                         end[i] = start[i] + attributes[attr]['by'][i];
3236                     }
3237                 } else {
3238                     end = start + attributes[attr]['by'];
3239                 }
3240             }
3241
3242             this.runtimeAttributes[attr].start = start;
3243             this.runtimeAttributes[attr].end = end;
3244
3245
3246             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3247         },
3248
3249
3250         init: function(el, attributes, duration, method) {
3251
3252             var isAnimated = false;
3253
3254
3255             var startTime = null;
3256
3257
3258             var actualFrames = 0;
3259
3260
3261             el = Roo.getDom(el);
3262
3263
3264             this.attributes = attributes || {};
3265
3266
3267             this.duration = duration || 1;
3268
3269
3270             this.method = method || Roo.lib.Easing.easeNone;
3271
3272
3273             this.useSeconds = true;
3274
3275
3276             this.currentFrame = 0;
3277
3278
3279             this.totalFrames = Roo.lib.AnimMgr.fps;
3280
3281
3282             this.getEl = function() {
3283                 return el;
3284             };
3285
3286
3287             this.isAnimated = function() {
3288                 return isAnimated;
3289             };
3290
3291
3292             this.getStartTime = function() {
3293                 return startTime;
3294             };
3295
3296             this.runtimeAttributes = {};
3297
3298
3299             this.animate = function() {
3300                 if (this.isAnimated()) {
3301                     return false;
3302                 }
3303
3304                 this.currentFrame = 0;
3305
3306                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3307
3308                 Roo.lib.AnimMgr.registerElement(this);
3309             };
3310
3311
3312             this.stop = function(finish) {
3313                 if (finish) {
3314                     this.currentFrame = this.totalFrames;
3315                     this._onTween.fire();
3316                 }
3317                 Roo.lib.AnimMgr.stop(this);
3318             };
3319
3320             var onStart = function() {
3321                 this.onStart.fire();
3322
3323                 this.runtimeAttributes = {};
3324                 for (var attr in this.attributes) {
3325                     this.setRuntimeAttribute(attr);
3326                 }
3327
3328                 isAnimated = true;
3329                 actualFrames = 0;
3330                 startTime = new Date();
3331             };
3332
3333
3334             var onTween = function() {
3335                 var data = {
3336                     duration: new Date() - this.getStartTime(),
3337                     currentFrame: this.currentFrame
3338                 };
3339
3340                 data.toString = function() {
3341                     return (
3342                             'duration: ' + data.duration +
3343                             ', currentFrame: ' + data.currentFrame
3344                             );
3345                 };
3346
3347                 this.onTween.fire(data);
3348
3349                 var runtimeAttributes = this.runtimeAttributes;
3350
3351                 for (var attr in runtimeAttributes) {
3352                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3353                 }
3354
3355                 actualFrames += 1;
3356             };
3357
3358             var onComplete = function() {
3359                 var actual_duration = (new Date() - startTime) / 1000 ;
3360
3361                 var data = {
3362                     duration: actual_duration,
3363                     frames: actualFrames,
3364                     fps: actualFrames / actual_duration
3365                 };
3366
3367                 data.toString = function() {
3368                     return (
3369                             'duration: ' + data.duration +
3370                             ', frames: ' + data.frames +
3371                             ', fps: ' + data.fps
3372                             );
3373                 };
3374
3375                 isAnimated = false;
3376                 actualFrames = 0;
3377                 this.onComplete.fire(data);
3378             };
3379
3380
3381             this._onStart = new Roo.util.Event(this);
3382             this.onStart = new Roo.util.Event(this);
3383             this.onTween = new Roo.util.Event(this);
3384             this._onTween = new Roo.util.Event(this);
3385             this.onComplete = new Roo.util.Event(this);
3386             this._onComplete = new Roo.util.Event(this);
3387             this._onStart.addListener(onStart);
3388             this._onTween.addListener(onTween);
3389             this._onComplete.addListener(onComplete);
3390         }
3391     };
3392 })();
3393 /*
3394  * Portions of this file are based on pieces of Yahoo User Interface Library
3395  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396  * YUI licensed under the BSD License:
3397  * http://developer.yahoo.net/yui/license.txt
3398  * <script type="text/javascript">
3399  *
3400  */
3401
3402 Roo.lib.AnimMgr = new function() {
3403
3404     var thread = null;
3405
3406
3407     var queue = [];
3408
3409
3410     var tweenCount = 0;
3411
3412
3413     this.fps = 1000;
3414
3415
3416     this.delay = 1;
3417
3418
3419     this.registerElement = function(tween) {
3420         queue[queue.length] = tween;
3421         tweenCount += 1;
3422         tween._onStart.fire();
3423         this.start();
3424     };
3425
3426
3427     this.unRegister = function(tween, index) {
3428         tween._onComplete.fire();
3429         index = index || getIndex(tween);
3430         if (index != -1) {
3431             queue.splice(index, 1);
3432         }
3433
3434         tweenCount -= 1;
3435         if (tweenCount <= 0) {
3436             this.stop();
3437         }
3438     };
3439
3440
3441     this.start = function() {
3442         if (thread === null) {
3443             thread = setInterval(this.run, this.delay);
3444         }
3445     };
3446
3447
3448     this.stop = function(tween) {
3449         if (!tween) {
3450             clearInterval(thread);
3451
3452             for (var i = 0, len = queue.length; i < len; ++i) {
3453                 if (queue[0].isAnimated()) {
3454                     this.unRegister(queue[0], 0);
3455                 }
3456             }
3457
3458             queue = [];
3459             thread = null;
3460             tweenCount = 0;
3461         }
3462         else {
3463             this.unRegister(tween);
3464         }
3465     };
3466
3467
3468     this.run = function() {
3469         for (var i = 0, len = queue.length; i < len; ++i) {
3470             var tween = queue[i];
3471             if (!tween || !tween.isAnimated()) {
3472                 continue;
3473             }
3474
3475             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3476             {
3477                 tween.currentFrame += 1;
3478
3479                 if (tween.useSeconds) {
3480                     correctFrame(tween);
3481                 }
3482                 tween._onTween.fire();
3483             }
3484             else {
3485                 Roo.lib.AnimMgr.stop(tween, i);
3486             }
3487         }
3488     };
3489
3490     var getIndex = function(anim) {
3491         for (var i = 0, len = queue.length; i < len; ++i) {
3492             if (queue[i] == anim) {
3493                 return i;
3494             }
3495         }
3496         return -1;
3497     };
3498
3499
3500     var correctFrame = function(tween) {
3501         var frames = tween.totalFrames;
3502         var frame = tween.currentFrame;
3503         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504         var elapsed = (new Date() - tween.getStartTime());
3505         var tweak = 0;
3506
3507         if (elapsed < tween.duration * 1000) {
3508             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3509         } else {
3510             tweak = frames - (frame + 1);
3511         }
3512         if (tweak > 0 && isFinite(tweak)) {
3513             if (tween.currentFrame + tweak >= frames) {
3514                 tweak = frames - (frame + 1);
3515             }
3516
3517             tween.currentFrame += tweak;
3518         }
3519     };
3520 };
3521
3522     /*
3523  * Portions of this file are based on pieces of Yahoo User Interface Library
3524  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525  * YUI licensed under the BSD License:
3526  * http://developer.yahoo.net/yui/license.txt
3527  * <script type="text/javascript">
3528  *
3529  */
3530 Roo.lib.Bezier = new function() {
3531
3532         this.getPosition = function(points, t) {
3533             var n = points.length;
3534             var tmp = [];
3535
3536             for (var i = 0; i < n; ++i) {
3537                 tmp[i] = [points[i][0], points[i][1]];
3538             }
3539
3540             for (var j = 1; j < n; ++j) {
3541                 for (i = 0; i < n - j; ++i) {
3542                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3544                 }
3545             }
3546
3547             return [ tmp[0][0], tmp[0][1] ];
3548
3549         };
3550     };/*
3551  * Portions of this file are based on pieces of Yahoo User Interface Library
3552  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553  * YUI licensed under the BSD License:
3554  * http://developer.yahoo.net/yui/license.txt
3555  * <script type="text/javascript">
3556  *
3557  */
3558 (function() {
3559
3560     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3562     };
3563
3564     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3565
3566     var fly = Roo.lib.AnimBase.fly;
3567     var Y = Roo.lib;
3568     var superclass = Y.ColorAnim.superclass;
3569     var proto = Y.ColorAnim.prototype;
3570
3571     proto.toString = function() {
3572         var el = this.getEl();
3573         var id = el.id || el.tagName;
3574         return ("ColorAnim " + id);
3575     };
3576
3577     proto.patterns.color = /color$/i;
3578     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3582
3583
3584     proto.parseColor = function(s) {
3585         if (s.length == 3) {
3586             return s;
3587         }
3588
3589         var c = this.patterns.hex.exec(s);
3590         if (c && c.length == 4) {
3591             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3592         }
3593
3594         c = this.patterns.rgb.exec(s);
3595         if (c && c.length == 4) {
3596             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3597         }
3598
3599         c = this.patterns.hex3.exec(s);
3600         if (c && c.length == 4) {
3601             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3602         }
3603
3604         return null;
3605     };
3606     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607     proto.getAttribute = function(attr) {
3608         var el = this.getEl();
3609         if (this.patterns.color.test(attr)) {
3610             var val = fly(el).getStyle(attr);
3611
3612             if (this.patterns.transparent.test(val)) {
3613                 var parent = el.parentNode;
3614                 val = fly(parent).getStyle(attr);
3615
3616                 while (parent && this.patterns.transparent.test(val)) {
3617                     parent = parent.parentNode;
3618                     val = fly(parent).getStyle(attr);
3619                     if (parent.tagName.toUpperCase() == 'HTML') {
3620                         val = '#fff';
3621                     }
3622                 }
3623             }
3624         } else {
3625             val = superclass.getAttribute.call(this, attr);
3626         }
3627
3628         return val;
3629     };
3630     proto.getAttribute = function(attr) {
3631         var el = this.getEl();
3632         if (this.patterns.color.test(attr)) {
3633             var val = fly(el).getStyle(attr);
3634
3635             if (this.patterns.transparent.test(val)) {
3636                 var parent = el.parentNode;
3637                 val = fly(parent).getStyle(attr);
3638
3639                 while (parent && this.patterns.transparent.test(val)) {
3640                     parent = parent.parentNode;
3641                     val = fly(parent).getStyle(attr);
3642                     if (parent.tagName.toUpperCase() == 'HTML') {
3643                         val = '#fff';
3644                     }
3645                 }
3646             }
3647         } else {
3648             val = superclass.getAttribute.call(this, attr);
3649         }
3650
3651         return val;
3652     };
3653
3654     proto.doMethod = function(attr, start, end) {
3655         var val;
3656
3657         if (this.patterns.color.test(attr)) {
3658             val = [];
3659             for (var i = 0, len = start.length; i < len; ++i) {
3660                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3661             }
3662
3663             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3664         }
3665         else {
3666             val = superclass.doMethod.call(this, attr, start, end);
3667         }
3668
3669         return val;
3670     };
3671
3672     proto.setRuntimeAttribute = function(attr) {
3673         superclass.setRuntimeAttribute.call(this, attr);
3674
3675         if (this.patterns.color.test(attr)) {
3676             var attributes = this.attributes;
3677             var start = this.parseColor(this.runtimeAttributes[attr].start);
3678             var end = this.parseColor(this.runtimeAttributes[attr].end);
3679
3680             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681                 end = this.parseColor(attributes[attr].by);
3682
3683                 for (var i = 0, len = start.length; i < len; ++i) {
3684                     end[i] = start[i] + end[i];
3685                 }
3686             }
3687
3688             this.runtimeAttributes[attr].start = start;
3689             this.runtimeAttributes[attr].end = end;
3690         }
3691     };
3692 })();
3693
3694 /*
3695  * Portions of this file are based on pieces of Yahoo User Interface Library
3696  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697  * YUI licensed under the BSD License:
3698  * http://developer.yahoo.net/yui/license.txt
3699  * <script type="text/javascript">
3700  *
3701  */
3702 Roo.lib.Easing = {
3703
3704
3705     easeNone: function (t, b, c, d) {
3706         return c * t / d + b;
3707     },
3708
3709
3710     easeIn: function (t, b, c, d) {
3711         return c * (t /= d) * t + b;
3712     },
3713
3714
3715     easeOut: function (t, b, c, d) {
3716         return -c * (t /= d) * (t - 2) + b;
3717     },
3718
3719
3720     easeBoth: function (t, b, c, d) {
3721         if ((t /= d / 2) < 1) {
3722             return c / 2 * t * t + b;
3723         }
3724
3725         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3726     },
3727
3728
3729     easeInStrong: function (t, b, c, d) {
3730         return c * (t /= d) * t * t * t + b;
3731     },
3732
3733
3734     easeOutStrong: function (t, b, c, d) {
3735         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3736     },
3737
3738
3739     easeBothStrong: function (t, b, c, d) {
3740         if ((t /= d / 2) < 1) {
3741             return c / 2 * t * t * t * t + b;
3742         }
3743
3744         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3745     },
3746
3747
3748
3749     elasticIn: function (t, b, c, d, a, p) {
3750         if (t == 0) {
3751             return b;
3752         }
3753         if ((t /= d) == 1) {
3754             return b + c;
3755         }
3756         if (!p) {
3757             p = d * .3;
3758         }
3759
3760         if (!a || a < Math.abs(c)) {
3761             a = c;
3762             var s = p / 4;
3763         }
3764         else {
3765             var s = p / (2 * Math.PI) * Math.asin(c / a);
3766         }
3767
3768         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3769     },
3770
3771
3772     elasticOut: function (t, b, c, d, a, p) {
3773         if (t == 0) {
3774             return b;
3775         }
3776         if ((t /= d) == 1) {
3777             return b + c;
3778         }
3779         if (!p) {
3780             p = d * .3;
3781         }
3782
3783         if (!a || a < Math.abs(c)) {
3784             a = c;
3785             var s = p / 4;
3786         }
3787         else {
3788             var s = p / (2 * Math.PI) * Math.asin(c / a);
3789         }
3790
3791         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3792     },
3793
3794
3795     elasticBoth: function (t, b, c, d, a, p) {
3796         if (t == 0) {
3797             return b;
3798         }
3799
3800         if ((t /= d / 2) == 2) {
3801             return b + c;
3802         }
3803
3804         if (!p) {
3805             p = d * (.3 * 1.5);
3806         }
3807
3808         if (!a || a < Math.abs(c)) {
3809             a = c;
3810             var s = p / 4;
3811         }
3812         else {
3813             var s = p / (2 * Math.PI) * Math.asin(c / a);
3814         }
3815
3816         if (t < 1) {
3817             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3819         }
3820         return a * Math.pow(2, -10 * (t -= 1)) *
3821                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3822     },
3823
3824
3825
3826     backIn: function (t, b, c, d, s) {
3827         if (typeof s == 'undefined') {
3828             s = 1.70158;
3829         }
3830         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3831     },
3832
3833
3834     backOut: function (t, b, c, d, s) {
3835         if (typeof s == 'undefined') {
3836             s = 1.70158;
3837         }
3838         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3839     },
3840
3841
3842     backBoth: function (t, b, c, d, s) {
3843         if (typeof s == 'undefined') {
3844             s = 1.70158;
3845         }
3846
3847         if ((t /= d / 2 ) < 1) {
3848             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3849         }
3850         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3851     },
3852
3853
3854     bounceIn: function (t, b, c, d) {
3855         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3856     },
3857
3858
3859     bounceOut: function (t, b, c, d) {
3860         if ((t /= d) < (1 / 2.75)) {
3861             return c * (7.5625 * t * t) + b;
3862         } else if (t < (2 / 2.75)) {
3863             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864         } else if (t < (2.5 / 2.75)) {
3865             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3866         }
3867         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3868     },
3869
3870
3871     bounceBoth: function (t, b, c, d) {
3872         if (t < d / 2) {
3873             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3874         }
3875         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3876     }
3877 };/*
3878  * Portions of this file are based on pieces of Yahoo User Interface Library
3879  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880  * YUI licensed under the BSD License:
3881  * http://developer.yahoo.net/yui/license.txt
3882  * <script type="text/javascript">
3883  *
3884  */
3885     (function() {
3886         Roo.lib.Motion = function(el, attributes, duration, method) {
3887             if (el) {
3888                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3889             }
3890         };
3891
3892         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3893
3894
3895         var Y = Roo.lib;
3896         var superclass = Y.Motion.superclass;
3897         var proto = Y.Motion.prototype;
3898
3899         proto.toString = function() {
3900             var el = this.getEl();
3901             var id = el.id || el.tagName;
3902             return ("Motion " + id);
3903         };
3904
3905         proto.patterns.points = /^points$/i;
3906
3907         proto.setAttribute = function(attr, val, unit) {
3908             if (this.patterns.points.test(attr)) {
3909                 unit = unit || 'px';
3910                 superclass.setAttribute.call(this, 'left', val[0], unit);
3911                 superclass.setAttribute.call(this, 'top', val[1], unit);
3912             } else {
3913                 superclass.setAttribute.call(this, attr, val, unit);
3914             }
3915         };
3916
3917         proto.getAttribute = function(attr) {
3918             if (this.patterns.points.test(attr)) {
3919                 var val = [
3920                         superclass.getAttribute.call(this, 'left'),
3921                         superclass.getAttribute.call(this, 'top')
3922                         ];
3923             } else {
3924                 val = superclass.getAttribute.call(this, attr);
3925             }
3926
3927             return val;
3928         };
3929
3930         proto.doMethod = function(attr, start, end) {
3931             var val = null;
3932
3933             if (this.patterns.points.test(attr)) {
3934                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3936             } else {
3937                 val = superclass.doMethod.call(this, attr, start, end);
3938             }
3939             return val;
3940         };
3941
3942         proto.setRuntimeAttribute = function(attr) {
3943             if (this.patterns.points.test(attr)) {
3944                 var el = this.getEl();
3945                 var attributes = this.attributes;
3946                 var start;
3947                 var control = attributes['points']['control'] || [];
3948                 var end;
3949                 var i, len;
3950
3951                 if (control.length > 0 && !(control[0] instanceof Array)) {
3952                     control = [control];
3953                 } else {
3954                     var tmp = [];
3955                     for (i = 0,len = control.length; i < len; ++i) {
3956                         tmp[i] = control[i];
3957                     }
3958                     control = tmp;
3959                 }
3960
3961                 Roo.fly(el).position();
3962
3963                 if (isset(attributes['points']['from'])) {
3964                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3965                 }
3966                 else {
3967                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3968                 }
3969
3970                 start = this.getAttribute('points');
3971
3972
3973                 if (isset(attributes['points']['to'])) {
3974                     end = translateValues.call(this, attributes['points']['to'], start);
3975
3976                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977                     for (i = 0,len = control.length; i < len; ++i) {
3978                         control[i] = translateValues.call(this, control[i], start);
3979                     }
3980
3981
3982                 } else if (isset(attributes['points']['by'])) {
3983                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3984
3985                     for (i = 0,len = control.length; i < len; ++i) {
3986                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3987                     }
3988                 }
3989
3990                 this.runtimeAttributes[attr] = [start];
3991
3992                 if (control.length > 0) {
3993                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3994                 }
3995
3996                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3997             }
3998             else {
3999                 superclass.setRuntimeAttribute.call(this, attr);
4000             }
4001         };
4002
4003         var translateValues = function(val, start) {
4004             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4006
4007             return val;
4008         };
4009
4010         var isset = function(prop) {
4011             return (typeof prop !== 'undefined');
4012         };
4013     })();
4014 /*
4015  * Portions of this file are based on pieces of Yahoo User Interface Library
4016  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017  * YUI licensed under the BSD License:
4018  * http://developer.yahoo.net/yui/license.txt
4019  * <script type="text/javascript">
4020  *
4021  */
4022     (function() {
4023         Roo.lib.Scroll = function(el, attributes, duration, method) {
4024             if (el) {
4025                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4026             }
4027         };
4028
4029         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4030
4031
4032         var Y = Roo.lib;
4033         var superclass = Y.Scroll.superclass;
4034         var proto = Y.Scroll.prototype;
4035
4036         proto.toString = function() {
4037             var el = this.getEl();
4038             var id = el.id || el.tagName;
4039             return ("Scroll " + id);
4040         };
4041
4042         proto.doMethod = function(attr, start, end) {
4043             var val = null;
4044
4045             if (attr == 'scroll') {
4046                 val = [
4047                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4049                         ];
4050
4051             } else {
4052                 val = superclass.doMethod.call(this, attr, start, end);
4053             }
4054             return val;
4055         };
4056
4057         proto.getAttribute = function(attr) {
4058             var val = null;
4059             var el = this.getEl();
4060
4061             if (attr == 'scroll') {
4062                 val = [ el.scrollLeft, el.scrollTop ];
4063             } else {
4064                 val = superclass.getAttribute.call(this, attr);
4065             }
4066
4067             return val;
4068         };
4069
4070         proto.setAttribute = function(attr, val, unit) {
4071             var el = this.getEl();
4072
4073             if (attr == 'scroll') {
4074                 el.scrollLeft = val[0];
4075                 el.scrollTop = val[1];
4076             } else {
4077                 superclass.setAttribute.call(this, attr, val, unit);
4078             }
4079         };
4080     })();
4081 /*
4082  * Based on:
4083  * Ext JS Library 1.1.1
4084  * Copyright(c) 2006-2007, Ext JS, LLC.
4085  *
4086  * Originally Released Under LGPL - original licence link has changed is not relivant.
4087  *
4088  * Fork - LGPL
4089  * <script type="text/javascript">
4090  */
4091
4092
4093 // nasty IE9 hack - what a pile of crap that is..
4094
4095  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096     Range.prototype.createContextualFragment = function (html) {
4097         var doc = window.document;
4098         var container = doc.createElement("div");
4099         container.innerHTML = html;
4100         var frag = doc.createDocumentFragment(), n;
4101         while ((n = container.firstChild)) {
4102             frag.appendChild(n);
4103         }
4104         return frag;
4105     };
4106 }
4107
4108 /**
4109  * @class Roo.DomHelper
4110  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4112  * @singleton
4113  */
4114 Roo.DomHelper = function(){
4115     var tempTableEl = null;
4116     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117     var tableRe = /^table|tbody|tr|td$/i;
4118     var xmlns = {};
4119     // build as innerHTML where available
4120     /** @ignore */
4121     var createHtml = function(o){
4122         if(typeof o == 'string'){
4123             return o;
4124         }
4125         var b = "";
4126         if(!o.tag){
4127             o.tag = "div";
4128         }
4129         b += "<" + o.tag;
4130         for(var attr in o){
4131             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132             if(attr == "style"){
4133                 var s = o["style"];
4134                 if(typeof s == "function"){
4135                     s = s.call();
4136                 }
4137                 if(typeof s == "string"){
4138                     b += ' style="' + s + '"';
4139                 }else if(typeof s == "object"){
4140                     b += ' style="';
4141                     for(var key in s){
4142                         if(typeof s[key] != "function"){
4143                             b += key + ":" + s[key] + ";";
4144                         }
4145                     }
4146                     b += '"';
4147                 }
4148             }else{
4149                 if(attr == "cls"){
4150                     b += ' class="' + o["cls"] + '"';
4151                 }else if(attr == "htmlFor"){
4152                     b += ' for="' + o["htmlFor"] + '"';
4153                 }else{
4154                     b += " " + attr + '="' + o[attr] + '"';
4155                 }
4156             }
4157         }
4158         if(emptyTags.test(o.tag)){
4159             b += "/>";
4160         }else{
4161             b += ">";
4162             var cn = o.children || o.cn;
4163             if(cn){
4164                 //http://bugs.kde.org/show_bug.cgi?id=71506
4165                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166                     for(var i = 0, len = cn.length; i < len; i++) {
4167                         b += createHtml(cn[i], b);
4168                     }
4169                 }else{
4170                     b += createHtml(cn, b);
4171                 }
4172             }
4173             if(o.html){
4174                 b += o.html;
4175             }
4176             b += "</" + o.tag + ">";
4177         }
4178         return b;
4179     };
4180
4181     // build as dom
4182     /** @ignore */
4183     var createDom = function(o, parentNode){
4184          
4185         // defininition craeted..
4186         var ns = false;
4187         if (o.ns && o.ns != 'html') {
4188                
4189             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190                 xmlns[o.ns] = o.xmlns;
4191                 ns = o.xmlns;
4192             }
4193             if (typeof(xmlns[o.ns]) == 'undefined') {
4194                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4195             }
4196             ns = xmlns[o.ns];
4197         }
4198         
4199         
4200         if (typeof(o) == 'string') {
4201             return parentNode.appendChild(document.createTextNode(o));
4202         }
4203         o.tag = o.tag || div;
4204         if (o.ns && Roo.isIE) {
4205             ns = false;
4206             o.tag = o.ns + ':' + o.tag;
4207             
4208         }
4209         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4210         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4211         for(var attr in o){
4212             
4213             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4214                     attr == "style" || typeof o[attr] == "function") continue;
4215                     
4216             if(attr=="cls" && Roo.isIE){
4217                 el.className = o["cls"];
4218             }else{
4219                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220                 else el[attr] = o[attr];
4221             }
4222         }
4223         Roo.DomHelper.applyStyles(el, o.style);
4224         var cn = o.children || o.cn;
4225         if(cn){
4226             //http://bugs.kde.org/show_bug.cgi?id=71506
4227              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228                 for(var i = 0, len = cn.length; i < len; i++) {
4229                     createDom(cn[i], el);
4230                 }
4231             }else{
4232                 createDom(cn, el);
4233             }
4234         }
4235         if(o.html){
4236             el.innerHTML = o.html;
4237         }
4238         if(parentNode){
4239            parentNode.appendChild(el);
4240         }
4241         return el;
4242     };
4243
4244     var ieTable = function(depth, s, h, e){
4245         tempTableEl.innerHTML = [s, h, e].join('');
4246         var i = -1, el = tempTableEl;
4247         while(++i < depth){
4248             el = el.firstChild;
4249         }
4250         return el;
4251     };
4252
4253     // kill repeat to save bytes
4254     var ts = '<table>',
4255         te = '</table>',
4256         tbs = ts+'<tbody>',
4257         tbe = '</tbody>'+te,
4258         trs = tbs + '<tr>',
4259         tre = '</tr>'+tbe;
4260
4261     /**
4262      * @ignore
4263      * Nasty code for IE's broken table implementation
4264      */
4265     var insertIntoTable = function(tag, where, el, html){
4266         if(!tempTableEl){
4267             tempTableEl = document.createElement('div');
4268         }
4269         var node;
4270         var before = null;
4271         if(tag == 'td'){
4272             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4273                 return;
4274             }
4275             if(where == 'beforebegin'){
4276                 before = el;
4277                 el = el.parentNode;
4278             } else{
4279                 before = el.nextSibling;
4280                 el = el.parentNode;
4281             }
4282             node = ieTable(4, trs, html, tre);
4283         }
4284         else if(tag == 'tr'){
4285             if(where == 'beforebegin'){
4286                 before = el;
4287                 el = el.parentNode;
4288                 node = ieTable(3, tbs, html, tbe);
4289             } else if(where == 'afterend'){
4290                 before = el.nextSibling;
4291                 el = el.parentNode;
4292                 node = ieTable(3, tbs, html, tbe);
4293             } else{ // INTO a TR
4294                 if(where == 'afterbegin'){
4295                     before = el.firstChild;
4296                 }
4297                 node = ieTable(4, trs, html, tre);
4298             }
4299         } else if(tag == 'tbody'){
4300             if(where == 'beforebegin'){
4301                 before = el;
4302                 el = el.parentNode;
4303                 node = ieTable(2, ts, html, te);
4304             } else if(where == 'afterend'){
4305                 before = el.nextSibling;
4306                 el = el.parentNode;
4307                 node = ieTable(2, ts, html, te);
4308             } else{
4309                 if(where == 'afterbegin'){
4310                     before = el.firstChild;
4311                 }
4312                 node = ieTable(3, tbs, html, tbe);
4313             }
4314         } else{ // TABLE
4315             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4316                 return;
4317             }
4318             if(where == 'afterbegin'){
4319                 before = el.firstChild;
4320             }
4321             node = ieTable(2, ts, html, te);
4322         }
4323         el.insertBefore(node, before);
4324         return node;
4325     };
4326
4327     return {
4328     /** True to force the use of DOM instead of html fragments @type Boolean */
4329     useDom : false,
4330
4331     /**
4332      * Returns the markup for the passed Element(s) config
4333      * @param {Object} o The Dom object spec (and children)
4334      * @return {String}
4335      */
4336     markup : function(o){
4337         return createHtml(o);
4338     },
4339
4340     /**
4341      * Applies a style specification to an element
4342      * @param {String/HTMLElement} el The element to apply styles to
4343      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344      * a function which returns such a specification.
4345      */
4346     applyStyles : function(el, styles){
4347         if(styles){
4348            el = Roo.fly(el);
4349            if(typeof styles == "string"){
4350                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4351                var matches;
4352                while ((matches = re.exec(styles)) != null){
4353                    el.setStyle(matches[1], matches[2]);
4354                }
4355            }else if (typeof styles == "object"){
4356                for (var style in styles){
4357                   el.setStyle(style, styles[style]);
4358                }
4359            }else if (typeof styles == "function"){
4360                 Roo.DomHelper.applyStyles(el, styles.call());
4361            }
4362         }
4363     },
4364
4365     /**
4366      * Inserts an HTML fragment into the Dom
4367      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368      * @param {HTMLElement} el The context element
4369      * @param {String} html The HTML fragmenet
4370      * @return {HTMLElement} The new node
4371      */
4372     insertHtml : function(where, el, html){
4373         where = where.toLowerCase();
4374         if(el.insertAdjacentHTML){
4375             if(tableRe.test(el.tagName)){
4376                 var rs;
4377                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4378                     return rs;
4379                 }
4380             }
4381             switch(where){
4382                 case "beforebegin":
4383                     el.insertAdjacentHTML('BeforeBegin', html);
4384                     return el.previousSibling;
4385                 case "afterbegin":
4386                     el.insertAdjacentHTML('AfterBegin', html);
4387                     return el.firstChild;
4388                 case "beforeend":
4389                     el.insertAdjacentHTML('BeforeEnd', html);
4390                     return el.lastChild;
4391                 case "afterend":
4392                     el.insertAdjacentHTML('AfterEnd', html);
4393                     return el.nextSibling;
4394             }
4395             throw 'Illegal insertion point -> "' + where + '"';
4396         }
4397         var range = el.ownerDocument.createRange();
4398         var frag;
4399         switch(where){
4400              case "beforebegin":
4401                 range.setStartBefore(el);
4402                 frag = range.createContextualFragment(html);
4403                 el.parentNode.insertBefore(frag, el);
4404                 return el.previousSibling;
4405              case "afterbegin":
4406                 if(el.firstChild){
4407                     range.setStartBefore(el.firstChild);
4408                     frag = range.createContextualFragment(html);
4409                     el.insertBefore(frag, el.firstChild);
4410                     return el.firstChild;
4411                 }else{
4412                     el.innerHTML = html;
4413                     return el.firstChild;
4414                 }
4415             case "beforeend":
4416                 if(el.lastChild){
4417                     range.setStartAfter(el.lastChild);
4418                     frag = range.createContextualFragment(html);
4419                     el.appendChild(frag);
4420                     return el.lastChild;
4421                 }else{
4422                     el.innerHTML = html;
4423                     return el.lastChild;
4424                 }
4425             case "afterend":
4426                 range.setStartAfter(el);
4427                 frag = range.createContextualFragment(html);
4428                 el.parentNode.insertBefore(frag, el.nextSibling);
4429                 return el.nextSibling;
4430             }
4431             throw 'Illegal insertion point -> "' + where + '"';
4432     },
4433
4434     /**
4435      * Creates new Dom element(s) and inserts them before el
4436      * @param {String/HTMLElement/Element} el The context element
4437      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439      * @return {HTMLElement/Roo.Element} The new node
4440      */
4441     insertBefore : function(el, o, returnElement){
4442         return this.doInsert(el, o, returnElement, "beforeBegin");
4443     },
4444
4445     /**
4446      * Creates new Dom element(s) and inserts them after el
4447      * @param {String/HTMLElement/Element} el The context element
4448      * @param {Object} o The Dom object spec (and children)
4449      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450      * @return {HTMLElement/Roo.Element} The new node
4451      */
4452     insertAfter : function(el, o, returnElement){
4453         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4454     },
4455
4456     /**
4457      * Creates new Dom element(s) and inserts them as the first child of el
4458      * @param {String/HTMLElement/Element} el The context element
4459      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461      * @return {HTMLElement/Roo.Element} The new node
4462      */
4463     insertFirst : function(el, o, returnElement){
4464         return this.doInsert(el, o, returnElement, "afterBegin");
4465     },
4466
4467     // private
4468     doInsert : function(el, o, returnElement, pos, sibling){
4469         el = Roo.getDom(el);
4470         var newNode;
4471         if(this.useDom || o.ns){
4472             newNode = createDom(o, null);
4473             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4474         }else{
4475             var html = createHtml(o);
4476             newNode = this.insertHtml(pos, el, html);
4477         }
4478         return returnElement ? Roo.get(newNode, true) : newNode;
4479     },
4480
4481     /**
4482      * Creates new Dom element(s) and appends them to el
4483      * @param {String/HTMLElement/Element} el The context element
4484      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486      * @return {HTMLElement/Roo.Element} The new node
4487      */
4488     append : function(el, o, returnElement){
4489         el = Roo.getDom(el);
4490         var newNode;
4491         if(this.useDom || o.ns){
4492             newNode = createDom(o, null);
4493             el.appendChild(newNode);
4494         }else{
4495             var html = createHtml(o);
4496             newNode = this.insertHtml("beforeEnd", el, html);
4497         }
4498         return returnElement ? Roo.get(newNode, true) : newNode;
4499     },
4500
4501     /**
4502      * Creates new Dom element(s) and overwrites the contents of el with them
4503      * @param {String/HTMLElement/Element} el The context element
4504      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506      * @return {HTMLElement/Roo.Element} The new node
4507      */
4508     overwrite : function(el, o, returnElement){
4509         el = Roo.getDom(el);
4510         if (o.ns) {
4511           
4512             while (el.childNodes.length) {
4513                 el.removeChild(el.firstChild);
4514             }
4515             createDom(o, el);
4516         } else {
4517             el.innerHTML = createHtml(o);   
4518         }
4519         
4520         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4521     },
4522
4523     /**
4524      * Creates a new Roo.DomHelper.Template from the Dom object spec
4525      * @param {Object} o The Dom object spec (and children)
4526      * @return {Roo.DomHelper.Template} The new template
4527      */
4528     createTemplate : function(o){
4529         var html = createHtml(o);
4530         return new Roo.Template(html);
4531     }
4532     };
4533 }();
4534 /*
4535  * Based on:
4536  * Ext JS Library 1.1.1
4537  * Copyright(c) 2006-2007, Ext JS, LLC.
4538  *
4539  * Originally Released Under LGPL - original licence link has changed is not relivant.
4540  *
4541  * Fork - LGPL
4542  * <script type="text/javascript">
4543  */
4544  
4545 /**
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4549 * Usage:
4550 <pre><code>
4551 var t = new Roo.Template({
4552     html :  '&lt;div name="{id}"&gt;' + 
4553         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4554         '&lt;/div&gt;',
4555     myformat: function (value, allValues) {
4556         return 'XX' + value;
4557     }
4558 });
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4560 </code></pre>
4561 * For more information see this blog post with examples:
4562 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563      - Create Elements using DOM, HTML fragments and Templates</a>. 
4564 * @constructor
4565 * @param {Object} cfg - Configuration object.
4566 */
4567 Roo.Template = function(cfg){
4568     // BC!
4569     if(cfg instanceof Array){
4570         cfg = cfg.join("");
4571     }else if(arguments.length > 1){
4572         cfg = Array.prototype.join.call(arguments, "");
4573     }
4574     
4575     
4576     if (typeof(cfg) == 'object') {
4577         Roo.apply(this,cfg)
4578     } else {
4579         // bc
4580         this.html = cfg;
4581     }
4582     if (this.url) {
4583         this.load();
4584     }
4585     
4586 };
4587 Roo.Template.prototype = {
4588     
4589     /**
4590      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4591      *                    it should be fixed so that template is observable...
4592      */
4593     url : false,
4594     /**
4595      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4596      */
4597     html : '',
4598     /**
4599      * Returns an HTML fragment of this template with the specified values applied.
4600      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4601      * @return {String} The HTML fragment
4602      */
4603     applyTemplate : function(values){
4604         try {
4605            
4606             if(this.compiled){
4607                 return this.compiled(values);
4608             }
4609             var useF = this.disableFormats !== true;
4610             var fm = Roo.util.Format, tpl = this;
4611             var fn = function(m, name, format, args){
4612                 if(format && useF){
4613                     if(format.substr(0, 5) == "this."){
4614                         return tpl.call(format.substr(5), values[name], values);
4615                     }else{
4616                         if(args){
4617                             // quoted values are required for strings in compiled templates, 
4618                             // but for non compiled we need to strip them
4619                             // quoted reversed for jsmin
4620                             var re = /^\s*['"](.*)["']\s*$/;
4621                             args = args.split(',');
4622                             for(var i = 0, len = args.length; i < len; i++){
4623                                 args[i] = args[i].replace(re, "$1");
4624                             }
4625                             args = [values[name]].concat(args);
4626                         }else{
4627                             args = [values[name]];
4628                         }
4629                         return fm[format].apply(fm, args);
4630                     }
4631                 }else{
4632                     return values[name] !== undefined ? values[name] : "";
4633                 }
4634             };
4635             return this.html.replace(this.re, fn);
4636         } catch (e) {
4637             Roo.log(e);
4638             throw e;
4639         }
4640          
4641     },
4642     
4643     loading : false,
4644       
4645     load : function ()
4646     {
4647          
4648         if (this.loading) {
4649             return;
4650         }
4651         var _t = this;
4652         
4653         this.loading = true;
4654         this.compiled = false;
4655         
4656         var cx = new Roo.data.Connection();
4657         cx.request({
4658             url : this.url,
4659             method : 'GET',
4660             success : function (response) {
4661                 _t.loading = false;
4662                 _t.html = response.responseText;
4663                 _t.url = false;
4664                 _t.compile();
4665              },
4666             failure : function(response) {
4667                 Roo.log("Template failed to load from " + _t.url);
4668                 _t.loading = false;
4669             }
4670         });
4671     },
4672
4673     /**
4674      * Sets the HTML used as the template and optionally compiles it.
4675      * @param {String} html
4676      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677      * @return {Roo.Template} this
4678      */
4679     set : function(html, compile){
4680         this.html = html;
4681         this.compiled = null;
4682         if(compile){
4683             this.compile();
4684         }
4685         return this;
4686     },
4687     
4688     /**
4689      * True to disable format functions (defaults to false)
4690      * @type Boolean
4691      */
4692     disableFormats : false,
4693     
4694     /**
4695     * The regular expression used to match template variables 
4696     * @type RegExp
4697     * @property 
4698     */
4699     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4700     
4701     /**
4702      * Compiles the template into an internal function, eliminating the RegEx overhead.
4703      * @return {Roo.Template} this
4704      */
4705     compile : function(){
4706         var fm = Roo.util.Format;
4707         var useF = this.disableFormats !== true;
4708         var sep = Roo.isGecko ? "+" : ",";
4709         var fn = function(m, name, format, args){
4710             if(format && useF){
4711                 args = args ? ',' + args : "";
4712                 if(format.substr(0, 5) != "this."){
4713                     format = "fm." + format + '(';
4714                 }else{
4715                     format = 'this.call("'+ format.substr(5) + '", ';
4716                     args = ", values";
4717                 }
4718             }else{
4719                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4720             }
4721             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4722         };
4723         var body;
4724         // branched to use + in gecko and [].join() in others
4725         if(Roo.isGecko){
4726             body = "this.compiled = function(values){ return '" +
4727                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4728                     "';};";
4729         }else{
4730             body = ["this.compiled = function(values){ return ['"];
4731             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732             body.push("'].join('');};");
4733             body = body.join('');
4734         }
4735         /**
4736          * eval:var:values
4737          * eval:var:fm
4738          */
4739         eval(body);
4740         return this;
4741     },
4742     
4743     // private function used to call members
4744     call : function(fnName, value, allValues){
4745         return this[fnName](value, allValues);
4746     },
4747     
4748     /**
4749      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750      * @param {String/HTMLElement/Roo.Element} el The context element
4751      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753      * @return {HTMLElement/Roo.Element} The new node or Element
4754      */
4755     insertFirst: function(el, values, returnElement){
4756         return this.doInsert('afterBegin', el, values, returnElement);
4757     },
4758
4759     /**
4760      * Applies the supplied values to the template and inserts the new node(s) before el.
4761      * @param {String/HTMLElement/Roo.Element} el The context element
4762      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764      * @return {HTMLElement/Roo.Element} The new node or Element
4765      */
4766     insertBefore: function(el, values, returnElement){
4767         return this.doInsert('beforeBegin', el, values, returnElement);
4768     },
4769
4770     /**
4771      * Applies the supplied values to the template and inserts the new node(s) after el.
4772      * @param {String/HTMLElement/Roo.Element} el The context element
4773      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775      * @return {HTMLElement/Roo.Element} The new node or Element
4776      */
4777     insertAfter : function(el, values, returnElement){
4778         return this.doInsert('afterEnd', el, values, returnElement);
4779     },
4780     
4781     /**
4782      * Applies the supplied values to the template and appends the new node(s) to el.
4783      * @param {String/HTMLElement/Roo.Element} el The context element
4784      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4785      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786      * @return {HTMLElement/Roo.Element} The new node or Element
4787      */
4788     append : function(el, values, returnElement){
4789         return this.doInsert('beforeEnd', el, values, returnElement);
4790     },
4791
4792     doInsert : function(where, el, values, returnEl){
4793         el = Roo.getDom(el);
4794         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795         return returnEl ? Roo.get(newNode, true) : newNode;
4796     },
4797
4798     /**
4799      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800      * @param {String/HTMLElement/Roo.Element} el The context element
4801      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4802      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803      * @return {HTMLElement/Roo.Element} The new node or Element
4804      */
4805     overwrite : function(el, values, returnElement){
4806         el = Roo.getDom(el);
4807         el.innerHTML = this.applyTemplate(values);
4808         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4809     }
4810 };
4811 /**
4812  * Alias for {@link #applyTemplate}
4813  * @method
4814  */
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4816
4817 // backwards compat
4818 Roo.DomHelper.Template = Roo.Template;
4819
4820 /**
4821  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822  * @param {String/HTMLElement} el A DOM element or its id
4823  * @returns {Roo.Template} The created template
4824  * @static
4825  */
4826 Roo.Template.from = function(el){
4827     el = Roo.getDom(el);
4828     return new Roo.Template(el.value || el.innerHTML);
4829 };/*
4830  * Based on:
4831  * Ext JS Library 1.1.1
4832  * Copyright(c) 2006-2007, Ext JS, LLC.
4833  *
4834  * Originally Released Under LGPL - original licence link has changed is not relivant.
4835  *
4836  * Fork - LGPL
4837  * <script type="text/javascript">
4838  */
4839  
4840
4841 /*
4842  * This is code is also distributed under MIT license for use
4843  * with jQuery and prototype JavaScript libraries.
4844  */
4845 /**
4846  * @class Roo.DomQuery
4847 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4848 <p>
4849 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4850
4851 <p>
4852 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4853 </p>
4854 <h4>Element Selectors:</h4>
4855 <ul class="list">
4856     <li> <b>*</b> any element</li>
4857     <li> <b>E</b> an element with the tag E</li>
4858     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4862 </ul>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4865 <ul class="list">
4866     <li> <b>E[foo]</b> has an attribute "foo"</li>
4867     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4873 </ul>
4874 <h4>Pseudo Classes:</h4>
4875 <ul class="list">
4876     <li> <b>E:first-child</b> E is the first child of its parent</li>
4877     <li> <b>E:last-child</b> E is the last child of its parent</li>
4878     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4879     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881     <li> <b>E:only-child</b> E is the only child of its parent</li>
4882     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4883     <li> <b>E:first</b> the first E in the resultset</li>
4884     <li> <b>E:last</b> the last E in the resultset</li>
4885     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4894 </ul>
4895 <h4>CSS Value Selectors:</h4>
4896 <ul class="list">
4897     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4903 </ul>
4904  * @singleton
4905  */
4906 Roo.DomQuery = function(){
4907     var cache = {}, simpleCache = {}, valueCache = {};
4908     var nonSpace = /\S/;
4909     var trimRe = /^\s+|\s+$/g;
4910     var tplRe = /\{(\d+)\}/g;
4911     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912     var tagTokenRe = /^(#)?([\w-\*]+)/;
4913     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4914
4915     function child(p, index){
4916         var i = 0;
4917         var n = p.firstChild;
4918         while(n){
4919             if(n.nodeType == 1){
4920                if(++i == index){
4921                    return n;
4922                }
4923             }
4924             n = n.nextSibling;
4925         }
4926         return null;
4927     };
4928
4929     function next(n){
4930         while((n = n.nextSibling) && n.nodeType != 1);
4931         return n;
4932     };
4933
4934     function prev(n){
4935         while((n = n.previousSibling) && n.nodeType != 1);
4936         return n;
4937     };
4938
4939     function children(d){
4940         var n = d.firstChild, ni = -1;
4941             while(n){
4942                 var nx = n.nextSibling;
4943                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4944                     d.removeChild(n);
4945                 }else{
4946                     n.nodeIndex = ++ni;
4947                 }
4948                 n = nx;
4949             }
4950             return this;
4951         };
4952
4953     function byClassName(c, a, v){
4954         if(!v){
4955             return c;
4956         }
4957         var r = [], ri = -1, cn;
4958         for(var i = 0, ci; ci = c[i]; i++){
4959             if((' '+ci.className+' ').indexOf(v) != -1){
4960                 r[++ri] = ci;
4961             }
4962         }
4963         return r;
4964     };
4965
4966     function attrValue(n, attr){
4967         if(!n.tagName && typeof n.length != "undefined"){
4968             n = n[0];
4969         }
4970         if(!n){
4971             return null;
4972         }
4973         if(attr == "for"){
4974             return n.htmlFor;
4975         }
4976         if(attr == "class" || attr == "className"){
4977             return n.className;
4978         }
4979         return n.getAttribute(attr) || n[attr];
4980
4981     };
4982
4983     function getNodes(ns, mode, tagName){
4984         var result = [], ri = -1, cs;
4985         if(!ns){
4986             return result;
4987         }
4988         tagName = tagName || "*";
4989         if(typeof ns.getElementsByTagName != "undefined"){
4990             ns = [ns];
4991         }
4992         if(!mode){
4993             for(var i = 0, ni; ni = ns[i]; i++){
4994                 cs = ni.getElementsByTagName(tagName);
4995                 for(var j = 0, ci; ci = cs[j]; j++){
4996                     result[++ri] = ci;
4997                 }
4998             }
4999         }else if(mode == "/" || mode == ">"){
5000             var utag = tagName.toUpperCase();
5001             for(var i = 0, ni, cn; ni = ns[i]; i++){
5002                 cn = ni.children || ni.childNodes;
5003                 for(var j = 0, cj; cj = cn[j]; j++){
5004                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5005                         result[++ri] = cj;
5006                     }
5007                 }
5008             }
5009         }else if(mode == "+"){
5010             var utag = tagName.toUpperCase();
5011             for(var i = 0, n; n = ns[i]; i++){
5012                 while((n = n.nextSibling) && n.nodeType != 1);
5013                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5014                     result[++ri] = n;
5015                 }
5016             }
5017         }else if(mode == "~"){
5018             for(var i = 0, n; n = ns[i]; i++){
5019                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5020                 if(n){
5021                     result[++ri] = n;
5022                 }
5023             }
5024         }
5025         return result;
5026     };
5027
5028     function concat(a, b){
5029         if(b.slice){
5030             return a.concat(b);
5031         }
5032         for(var i = 0, l = b.length; i < l; i++){
5033             a[a.length] = b[i];
5034         }
5035         return a;
5036     }
5037
5038     function byTag(cs, tagName){
5039         if(cs.tagName || cs == document){
5040             cs = [cs];
5041         }
5042         if(!tagName){
5043             return cs;
5044         }
5045         var r = [], ri = -1;
5046         tagName = tagName.toLowerCase();
5047         for(var i = 0, ci; ci = cs[i]; i++){
5048             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5049                 r[++ri] = ci;
5050             }
5051         }
5052         return r;
5053     };
5054
5055     function byId(cs, attr, id){
5056         if(cs.tagName || cs == document){
5057             cs = [cs];
5058         }
5059         if(!id){
5060             return cs;
5061         }
5062         var r = [], ri = -1;
5063         for(var i = 0,ci; ci = cs[i]; i++){
5064             if(ci && ci.id == id){
5065                 r[++ri] = ci;
5066                 return r;
5067             }
5068         }
5069         return r;
5070     };
5071
5072     function byAttribute(cs, attr, value, op, custom){
5073         var r = [], ri = -1, st = custom=="{";
5074         var f = Roo.DomQuery.operators[op];
5075         for(var i = 0, ci; ci = cs[i]; i++){
5076             var a;
5077             if(st){
5078                 a = Roo.DomQuery.getStyle(ci, attr);
5079             }
5080             else if(attr == "class" || attr == "className"){
5081                 a = ci.className;
5082             }else if(attr == "for"){
5083                 a = ci.htmlFor;
5084             }else if(attr == "href"){
5085                 a = ci.getAttribute("href", 2);
5086             }else{
5087                 a = ci.getAttribute(attr);
5088             }
5089             if((f && f(a, value)) || (!f && a)){
5090                 r[++ri] = ci;
5091             }
5092         }
5093         return r;
5094     };
5095
5096     function byPseudo(cs, name, value){
5097         return Roo.DomQuery.pseudos[name](cs, value);
5098     };
5099
5100     // This is for IE MSXML which does not support expandos.
5101     // IE runs the same speed using setAttribute, however FF slows way down
5102     // and Safari completely fails so they need to continue to use expandos.
5103     var isIE = window.ActiveXObject ? true : false;
5104
5105     // this eval is stop the compressor from
5106     // renaming the variable to something shorter
5107     
5108     /** eval:var:batch */
5109     var batch = 30803; 
5110
5111     var key = 30803;
5112
5113     function nodupIEXml(cs){
5114         var d = ++key;
5115         cs[0].setAttribute("_nodup", d);
5116         var r = [cs[0]];
5117         for(var i = 1, len = cs.length; i < len; i++){
5118             var c = cs[i];
5119             if(!c.getAttribute("_nodup") != d){
5120                 c.setAttribute("_nodup", d);
5121                 r[r.length] = c;
5122             }
5123         }
5124         for(var i = 0, len = cs.length; i < len; i++){
5125             cs[i].removeAttribute("_nodup");
5126         }
5127         return r;
5128     }
5129
5130     function nodup(cs){
5131         if(!cs){
5132             return [];
5133         }
5134         var len = cs.length, c, i, r = cs, cj, ri = -1;
5135         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5136             return cs;
5137         }
5138         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139             return nodupIEXml(cs);
5140         }
5141         var d = ++key;
5142         cs[0]._nodup = d;
5143         for(i = 1; c = cs[i]; i++){
5144             if(c._nodup != d){
5145                 c._nodup = d;
5146             }else{
5147                 r = [];
5148                 for(var j = 0; j < i; j++){
5149                     r[++ri] = cs[j];
5150                 }
5151                 for(j = i+1; cj = cs[j]; j++){
5152                     if(cj._nodup != d){
5153                         cj._nodup = d;
5154                         r[++ri] = cj;
5155                     }
5156                 }
5157                 return r;
5158             }
5159         }
5160         return r;
5161     }
5162
5163     function quickDiffIEXml(c1, c2){
5164         var d = ++key;
5165         for(var i = 0, len = c1.length; i < len; i++){
5166             c1[i].setAttribute("_qdiff", d);
5167         }
5168         var r = [];
5169         for(var i = 0, len = c2.length; i < len; i++){
5170             if(c2[i].getAttribute("_qdiff") != d){
5171                 r[r.length] = c2[i];
5172             }
5173         }
5174         for(var i = 0, len = c1.length; i < len; i++){
5175            c1[i].removeAttribute("_qdiff");
5176         }
5177         return r;
5178     }
5179
5180     function quickDiff(c1, c2){
5181         var len1 = c1.length;
5182         if(!len1){
5183             return c2;
5184         }
5185         if(isIE && c1[0].selectSingleNode){
5186             return quickDiffIEXml(c1, c2);
5187         }
5188         var d = ++key;
5189         for(var i = 0; i < len1; i++){
5190             c1[i]._qdiff = d;
5191         }
5192         var r = [];
5193         for(var i = 0, len = c2.length; i < len; i++){
5194             if(c2[i]._qdiff != d){
5195                 r[r.length] = c2[i];
5196             }
5197         }
5198         return r;
5199     }
5200
5201     function quickId(ns, mode, root, id){
5202         if(ns == root){
5203            var d = root.ownerDocument || root;
5204            return d.getElementById(id);
5205         }
5206         ns = getNodes(ns, mode, "*");
5207         return byId(ns, null, id);
5208     }
5209
5210     return {
5211         getStyle : function(el, name){
5212             return Roo.fly(el).getStyle(name);
5213         },
5214         /**
5215          * Compiles a selector/xpath query into a reusable function. The returned function
5216          * takes one parameter "root" (optional), which is the context node from where the query should start.
5217          * @param {String} selector The selector/xpath query
5218          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219          * @return {Function}
5220          */
5221         compile : function(path, type){
5222             type = type || "select";
5223             
5224             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225             var q = path, mode, lq;
5226             var tk = Roo.DomQuery.matchers;
5227             var tklen = tk.length;
5228             var mm;
5229             Roo.log('path!!!');
5230             Roo.log(path)
5231             
5232             Roo.log('compile!!!');
5233             Roo.log(q);
5234             // accept leading mode switch
5235             Roo.log('modeRe');
5236             Roo.log(modeRe);
5237             var lmode = q.match(modeRe);
5238             
5239             Roo.log('lmode');
5240             Roo.log(lmode);
5241             
5242             if(lmode && lmode[1]){
5243                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5244                 q = q.replace(lmode[1], "");
5245             }
5246             // strip leading slashes
5247             while(path.substr(0, 1)=="/"){
5248                 path = path.substr(1);
5249             }
5250             Roo.log('lg!!!');
5251             Roo.log(lq);
5252             while(q && lq != q){
5253                 lq = q;
5254                 var tm = q.match(tagTokenRe);
5255                 if(type == "select"){
5256                     if(tm){
5257                         if(tm[1] == "#"){
5258                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5259                         }else{
5260                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5261                         }
5262                         q = q.replace(tm[0], "");
5263                     }else if(q.substr(0, 1) != '@'){
5264                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5265                     }
5266                 }else{
5267                     if(tm){
5268                         if(tm[1] == "#"){
5269                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5270                         }else{
5271                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5272                         }
5273                         q = q.replace(tm[0], "");
5274                     }
5275                 }
5276                 while(!(mm = q.match(modeRe))){
5277                     var matched = false;
5278                     for(var j = 0; j < tklen; j++){
5279                         var t = tk[j];
5280                         var m = q.match(t.re);
5281                         if(m){
5282                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5283                                                     return m[i];
5284                                                 });
5285                             q = q.replace(m[0], "");
5286                             matched = true;
5287                             break;
5288                         }
5289                     }
5290                     // prevent infinite loop on bad selector
5291                     if(!matched){
5292                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5293                     }
5294                 }
5295                 if(mm[1]){
5296                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5297                     q = q.replace(mm[1], "");
5298                 }
5299             }
5300             fn[fn.length] = "return nodup(n);\n}";
5301             
5302              /** 
5303               * list of variables that need from compression as they are used by eval.
5304              *  eval:var:batch 
5305              *  eval:var:nodup
5306              *  eval:var:byTag
5307              *  eval:var:ById
5308              *  eval:var:getNodes
5309              *  eval:var:quickId
5310              *  eval:var:mode
5311              *  eval:var:root
5312              *  eval:var:n
5313              *  eval:var:byClassName
5314              *  eval:var:byPseudo
5315              *  eval:var:byAttribute
5316              *  eval:var:attrValue
5317              * 
5318              **/ 
5319             eval(fn.join(""));
5320             return f;
5321         },
5322
5323         /**
5324          * Selects a group of elements.
5325          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5326          * @param {Node} root (optional) The start of the query (defaults to document).
5327          * @return {Array}
5328          */
5329         select : function(path, root, type){
5330             if(!root || root == document){
5331                 root = document;
5332             }
5333             if(typeof root == "string"){
5334                 root = document.getElementById(root);
5335             }
5336             var paths = path.split(",");
5337             var results = [];
5338             for(var i = 0, len = paths.length; i < len; i++){
5339                 var p = paths[i].replace(trimRe, "");
5340                 if(!cache[p]){
5341                     Roo.log('p!!!');
5342                     Roo.log(p);
5343                     cache[p] = Roo.DomQuery.compile(p);
5344                     if(!cache[p]){
5345                         throw p + " is not a valid selector";
5346                     }
5347                 }
5348                 var result = cache[p](root);
5349                 if(result && result != document){
5350                     results = results.concat(result);
5351                 }
5352             }
5353             if(paths.length > 1){
5354                 return nodup(results);
5355             }
5356             return results;
5357         },
5358
5359         /**
5360          * Selects a single element.
5361          * @param {String} selector The selector/xpath query
5362          * @param {Node} root (optional) The start of the query (defaults to document).
5363          * @return {Element}
5364          */
5365         selectNode : function(path, root){
5366             return Roo.DomQuery.select(path, root)[0];
5367         },
5368
5369         /**
5370          * Selects the value of a node, optionally replacing null with the defaultValue.
5371          * @param {String} selector The selector/xpath query
5372          * @param {Node} root (optional) The start of the query (defaults to document).
5373          * @param {String} defaultValue
5374          */
5375         selectValue : function(path, root, defaultValue){
5376             path = path.replace(trimRe, "");
5377             if(!valueCache[path]){
5378                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5379             }
5380             var n = valueCache[path](root);
5381             n = n[0] ? n[0] : n;
5382             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5383             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5384         },
5385
5386         /**
5387          * Selects the value of a node, parsing integers and floats.
5388          * @param {String} selector The selector/xpath query
5389          * @param {Node} root (optional) The start of the query (defaults to document).
5390          * @param {Number} defaultValue
5391          * @return {Number}
5392          */
5393         selectNumber : function(path, root, defaultValue){
5394             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5395             return parseFloat(v);
5396         },
5397
5398         /**
5399          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5400          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5401          * @param {String} selector The simple selector to test
5402          * @return {Boolean}
5403          */
5404         is : function(el, ss){
5405             if(typeof el == "string"){
5406                 el = document.getElementById(el);
5407             }
5408             var isArray = (el instanceof Array);
5409             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5410             return isArray ? (result.length == el.length) : (result.length > 0);
5411         },
5412
5413         /**
5414          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5415          * @param {Array} el An array of elements to filter
5416          * @param {String} selector The simple selector to test
5417          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5418          * the selector instead of the ones that match
5419          * @return {Array}
5420          */
5421         filter : function(els, ss, nonMatches){
5422             ss = ss.replace(trimRe, "");
5423             if(!simpleCache[ss]){
5424                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5425             }
5426             var result = simpleCache[ss](els);
5427             return nonMatches ? quickDiff(result, els) : result;
5428         },
5429
5430         /**
5431          * Collection of matching regular expressions and code snippets.
5432          */
5433         matchers : [{
5434                 re: /^\.([\w-]+)/,
5435                 select: 'n = byClassName(n, null, " {1} ");'
5436             }, {
5437                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5438                 select: 'n = byPseudo(n, "{1}", "{2}");'
5439             },{
5440                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5441                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5442             }, {
5443                 re: /^#([\w-]+)/,
5444                 select: 'n = byId(n, null, "{1}");'
5445             },{
5446                 re: /^@([\w-]+)/,
5447                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5448             }
5449         ],
5450
5451         /**
5452          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5453          * 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;.
5454          */
5455         operators : {
5456             "=" : function(a, v){
5457                 return a == v;
5458             },
5459             "!=" : function(a, v){
5460                 return a != v;
5461             },
5462             "^=" : function(a, v){
5463                 return a && a.substr(0, v.length) == v;
5464             },
5465             "$=" : function(a, v){
5466                 return a && a.substr(a.length-v.length) == v;
5467             },
5468             "*=" : function(a, v){
5469                 return a && a.indexOf(v) !== -1;
5470             },
5471             "%=" : function(a, v){
5472                 return (a % v) == 0;
5473             },
5474             "|=" : function(a, v){
5475                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5476             },
5477             "~=" : function(a, v){
5478                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5479             }
5480         },
5481
5482         /**
5483          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5484          * and the argument (if any) supplied in the selector.
5485          */
5486         pseudos : {
5487             "first-child" : function(c){
5488                 var r = [], ri = -1, n;
5489                 for(var i = 0, ci; ci = n = c[i]; i++){
5490                     while((n = n.previousSibling) && n.nodeType != 1);
5491                     if(!n){
5492                         r[++ri] = ci;
5493                     }
5494                 }
5495                 return r;
5496             },
5497
5498             "last-child" : function(c){
5499                 var r = [], ri = -1, n;
5500                 for(var i = 0, ci; ci = n = c[i]; i++){
5501                     while((n = n.nextSibling) && n.nodeType != 1);
5502                     if(!n){
5503                         r[++ri] = ci;
5504                     }
5505                 }
5506                 return r;
5507             },
5508
5509             "nth-child" : function(c, a) {
5510                 var r = [], ri = -1;
5511                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5512                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5513                 for(var i = 0, n; n = c[i]; i++){
5514                     var pn = n.parentNode;
5515                     if (batch != pn._batch) {
5516                         var j = 0;
5517                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5518                             if(cn.nodeType == 1){
5519                                cn.nodeIndex = ++j;
5520                             }
5521                         }
5522                         pn._batch = batch;
5523                     }
5524                     if (f == 1) {
5525                         if (l == 0 || n.nodeIndex == l){
5526                             r[++ri] = n;
5527                         }
5528                     } else if ((n.nodeIndex + l) % f == 0){
5529                         r[++ri] = n;
5530                     }
5531                 }
5532
5533                 return r;
5534             },
5535
5536             "only-child" : function(c){
5537                 var r = [], ri = -1;;
5538                 for(var i = 0, ci; ci = c[i]; i++){
5539                     if(!prev(ci) && !next(ci)){
5540                         r[++ri] = ci;
5541                     }
5542                 }
5543                 return r;
5544             },
5545
5546             "empty" : function(c){
5547                 var r = [], ri = -1;
5548                 for(var i = 0, ci; ci = c[i]; i++){
5549                     var cns = ci.childNodes, j = 0, cn, empty = true;
5550                     while(cn = cns[j]){
5551                         ++j;
5552                         if(cn.nodeType == 1 || cn.nodeType == 3){
5553                             empty = false;
5554                             break;
5555                         }
5556                     }
5557                     if(empty){
5558                         r[++ri] = ci;
5559                     }
5560                 }
5561                 return r;
5562             },
5563
5564             "contains" : function(c, v){
5565                 var r = [], ri = -1;
5566                 for(var i = 0, ci; ci = c[i]; i++){
5567                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5568                         r[++ri] = ci;
5569                     }
5570                 }
5571                 return r;
5572             },
5573
5574             "nodeValue" : function(c, v){
5575                 var r = [], ri = -1;
5576                 for(var i = 0, ci; ci = c[i]; i++){
5577                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5578                         r[++ri] = ci;
5579                     }
5580                 }
5581                 return r;
5582             },
5583
5584             "checked" : function(c){
5585                 var r = [], ri = -1;
5586                 for(var i = 0, ci; ci = c[i]; i++){
5587                     if(ci.checked == true){
5588                         r[++ri] = ci;
5589                     }
5590                 }
5591                 return r;
5592             },
5593
5594             "not" : function(c, ss){
5595                 return Roo.DomQuery.filter(c, ss, true);
5596             },
5597
5598             "odd" : function(c){
5599                 return this["nth-child"](c, "odd");
5600             },
5601
5602             "even" : function(c){
5603                 return this["nth-child"](c, "even");
5604             },
5605
5606             "nth" : function(c, a){
5607                 return c[a-1] || [];
5608             },
5609
5610             "first" : function(c){
5611                 return c[0] || [];
5612             },
5613
5614             "last" : function(c){
5615                 return c[c.length-1] || [];
5616             },
5617
5618             "has" : function(c, ss){
5619                 var s = Roo.DomQuery.select;
5620                 var r = [], ri = -1;
5621                 for(var i = 0, ci; ci = c[i]; i++){
5622                     if(s(ss, ci).length > 0){
5623                         r[++ri] = ci;
5624                     }
5625                 }
5626                 return r;
5627             },
5628
5629             "next" : function(c, ss){
5630                 var is = Roo.DomQuery.is;
5631                 var r = [], ri = -1;
5632                 for(var i = 0, ci; ci = c[i]; i++){
5633                     var n = next(ci);
5634                     if(n && is(n, ss)){
5635                         r[++ri] = ci;
5636                     }
5637                 }
5638                 return r;
5639             },
5640
5641             "prev" : function(c, ss){
5642                 var is = Roo.DomQuery.is;
5643                 var r = [], ri = -1;
5644                 for(var i = 0, ci; ci = c[i]; i++){
5645                     var n = prev(ci);
5646                     if(n && is(n, ss)){
5647                         r[++ri] = ci;
5648                     }
5649                 }
5650                 return r;
5651             }
5652         }
5653     };
5654 }();
5655
5656 /**
5657  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5658  * @param {String} path The selector/xpath query
5659  * @param {Node} root (optional) The start of the query (defaults to document).
5660  * @return {Array}
5661  * @member Roo
5662  * @method query
5663  */
5664 Roo.query = Roo.DomQuery.select;
5665 /*
5666  * Based on:
5667  * Ext JS Library 1.1.1
5668  * Copyright(c) 2006-2007, Ext JS, LLC.
5669  *
5670  * Originally Released Under LGPL - original licence link has changed is not relivant.
5671  *
5672  * Fork - LGPL
5673  * <script type="text/javascript">
5674  */
5675
5676 /**
5677  * @class Roo.util.Observable
5678  * Base class that provides a common interface for publishing events. Subclasses are expected to
5679  * to have a property "events" with all the events defined.<br>
5680  * For example:
5681  * <pre><code>
5682  Employee = function(name){
5683     this.name = name;
5684     this.addEvents({
5685         "fired" : true,
5686         "quit" : true
5687     });
5688  }
5689  Roo.extend(Employee, Roo.util.Observable);
5690 </code></pre>
5691  * @param {Object} config properties to use (incuding events / listeners)
5692  */
5693
5694 Roo.util.Observable = function(cfg){
5695     
5696     cfg = cfg|| {};
5697     this.addEvents(cfg.events || {});
5698     if (cfg.events) {
5699         delete cfg.events; // make sure
5700     }
5701      
5702     Roo.apply(this, cfg);
5703     
5704     if(this.listeners){
5705         this.on(this.listeners);
5706         delete this.listeners;
5707     }
5708 };
5709 Roo.util.Observable.prototype = {
5710     /** 
5711  * @cfg {Object} listeners  list of events and functions to call for this object, 
5712  * For example :
5713  * <pre><code>
5714     listeners :  { 
5715        'click' : function(e) {
5716            ..... 
5717         } ,
5718         .... 
5719     } 
5720   </code></pre>
5721  */
5722     
5723     
5724     /**
5725      * Fires the specified event with the passed parameters (minus the event name).
5726      * @param {String} eventName
5727      * @param {Object...} args Variable number of parameters are passed to handlers
5728      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5729      */
5730     fireEvent : function(){
5731         var ce = this.events[arguments[0].toLowerCase()];
5732         if(typeof ce == "object"){
5733             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5734         }else{
5735             return true;
5736         }
5737     },
5738
5739     // private
5740     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5741
5742     /**
5743      * Appends an event handler to this component
5744      * @param {String}   eventName The type of event to listen for
5745      * @param {Function} handler The method the event invokes
5746      * @param {Object}   scope (optional) The scope in which to execute the handler
5747      * function. The handler function's "this" context.
5748      * @param {Object}   options (optional) An object containing handler configuration
5749      * properties. This may contain any of the following properties:<ul>
5750      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5751      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5752      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5753      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5754      * by the specified number of milliseconds. If the event fires again within that time, the original
5755      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5756      * </ul><br>
5757      * <p>
5758      * <b>Combining Options</b><br>
5759      * Using the options argument, it is possible to combine different types of listeners:<br>
5760      * <br>
5761      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5762                 <pre><code>
5763                 el.on('click', this.onClick, this, {
5764                         single: true,
5765                 delay: 100,
5766                 forumId: 4
5767                 });
5768                 </code></pre>
5769      * <p>
5770      * <b>Attaching multiple handlers in 1 call</b><br>
5771      * The method also allows for a single argument to be passed which is a config object containing properties
5772      * which specify multiple handlers.
5773      * <pre><code>
5774                 el.on({
5775                         'click': {
5776                         fn: this.onClick,
5777                         scope: this,
5778                         delay: 100
5779                 }, 
5780                 'mouseover': {
5781                         fn: this.onMouseOver,
5782                         scope: this
5783                 },
5784                 'mouseout': {
5785                         fn: this.onMouseOut,
5786                         scope: this
5787                 }
5788                 });
5789                 </code></pre>
5790      * <p>
5791      * Or a shorthand syntax which passes the same scope object to all handlers:
5792         <pre><code>
5793                 el.on({
5794                         'click': this.onClick,
5795                 'mouseover': this.onMouseOver,
5796                 'mouseout': this.onMouseOut,
5797                 scope: this
5798                 });
5799                 </code></pre>
5800      */
5801     addListener : function(eventName, fn, scope, o){
5802         if(typeof eventName == "object"){
5803             o = eventName;
5804             for(var e in o){
5805                 if(this.filterOptRe.test(e)){
5806                     continue;
5807                 }
5808                 if(typeof o[e] == "function"){
5809                     // shared options
5810                     this.addListener(e, o[e], o.scope,  o);
5811                 }else{
5812                     // individual options
5813                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5814                 }
5815             }
5816             return;
5817         }
5818         o = (!o || typeof o == "boolean") ? {} : o;
5819         eventName = eventName.toLowerCase();
5820         var ce = this.events[eventName] || true;
5821         if(typeof ce == "boolean"){
5822             ce = new Roo.util.Event(this, eventName);
5823             this.events[eventName] = ce;
5824         }
5825         ce.addListener(fn, scope, o);
5826     },
5827
5828     /**
5829      * Removes a listener
5830      * @param {String}   eventName     The type of event to listen for
5831      * @param {Function} handler        The handler to remove
5832      * @param {Object}   scope  (optional) The scope (this object) for the handler
5833      */
5834     removeListener : function(eventName, fn, scope){
5835         var ce = this.events[eventName.toLowerCase()];
5836         if(typeof ce == "object"){
5837             ce.removeListener(fn, scope);
5838         }
5839     },
5840
5841     /**
5842      * Removes all listeners for this object
5843      */
5844     purgeListeners : function(){
5845         for(var evt in this.events){
5846             if(typeof this.events[evt] == "object"){
5847                  this.events[evt].clearListeners();
5848             }
5849         }
5850     },
5851
5852     relayEvents : function(o, events){
5853         var createHandler = function(ename){
5854             return function(){
5855                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5856             };
5857         };
5858         for(var i = 0, len = events.length; i < len; i++){
5859             var ename = events[i];
5860             if(!this.events[ename]){ this.events[ename] = true; };
5861             o.on(ename, createHandler(ename), this);
5862         }
5863     },
5864
5865     /**
5866      * Used to define events on this Observable
5867      * @param {Object} object The object with the events defined
5868      */
5869     addEvents : function(o){
5870         if(!this.events){
5871             this.events = {};
5872         }
5873         Roo.applyIf(this.events, o);
5874     },
5875
5876     /**
5877      * Checks to see if this object has any listeners for a specified event
5878      * @param {String} eventName The name of the event to check for
5879      * @return {Boolean} True if the event is being listened for, else false
5880      */
5881     hasListener : function(eventName){
5882         var e = this.events[eventName];
5883         return typeof e == "object" && e.listeners.length > 0;
5884     }
5885 };
5886 /**
5887  * Appends an event handler to this element (shorthand for addListener)
5888  * @param {String}   eventName     The type of event to listen for
5889  * @param {Function} handler        The method the event invokes
5890  * @param {Object}   scope (optional) The scope in which to execute the handler
5891  * function. The handler function's "this" context.
5892  * @param {Object}   options  (optional)
5893  * @method
5894  */
5895 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5896 /**
5897  * Removes a listener (shorthand for removeListener)
5898  * @param {String}   eventName     The type of event to listen for
5899  * @param {Function} handler        The handler to remove
5900  * @param {Object}   scope  (optional) The scope (this object) for the handler
5901  * @method
5902  */
5903 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5904
5905 /**
5906  * Starts capture on the specified Observable. All events will be passed
5907  * to the supplied function with the event name + standard signature of the event
5908  * <b>before</b> the event is fired. If the supplied function returns false,
5909  * the event will not fire.
5910  * @param {Observable} o The Observable to capture
5911  * @param {Function} fn The function to call
5912  * @param {Object} scope (optional) The scope (this object) for the fn
5913  * @static
5914  */
5915 Roo.util.Observable.capture = function(o, fn, scope){
5916     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5917 };
5918
5919 /**
5920  * Removes <b>all</b> added captures from the Observable.
5921  * @param {Observable} o The Observable to release
5922  * @static
5923  */
5924 Roo.util.Observable.releaseCapture = function(o){
5925     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5926 };
5927
5928 (function(){
5929
5930     var createBuffered = function(h, o, scope){
5931         var task = new Roo.util.DelayedTask();
5932         return function(){
5933             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5934         };
5935     };
5936
5937     var createSingle = function(h, e, fn, scope){
5938         return function(){
5939             e.removeListener(fn, scope);
5940             return h.apply(scope, arguments);
5941         };
5942     };
5943
5944     var createDelayed = function(h, o, scope){
5945         return function(){
5946             var args = Array.prototype.slice.call(arguments, 0);
5947             setTimeout(function(){
5948                 h.apply(scope, args);
5949             }, o.delay || 10);
5950         };
5951     };
5952
5953     Roo.util.Event = function(obj, name){
5954         this.name = name;
5955         this.obj = obj;
5956         this.listeners = [];
5957     };
5958
5959     Roo.util.Event.prototype = {
5960         addListener : function(fn, scope, options){
5961             var o = options || {};
5962             scope = scope || this.obj;
5963             if(!this.isListening(fn, scope)){
5964                 var l = {fn: fn, scope: scope, options: o};
5965                 var h = fn;
5966                 if(o.delay){
5967                     h = createDelayed(h, o, scope);
5968                 }
5969                 if(o.single){
5970                     h = createSingle(h, this, fn, scope);
5971                 }
5972                 if(o.buffer){
5973                     h = createBuffered(h, o, scope);
5974                 }
5975                 l.fireFn = h;
5976                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5977                     this.listeners.push(l);
5978                 }else{
5979                     this.listeners = this.listeners.slice(0);
5980                     this.listeners.push(l);
5981                 }
5982             }
5983         },
5984
5985         findListener : function(fn, scope){
5986             scope = scope || this.obj;
5987             var ls = this.listeners;
5988             for(var i = 0, len = ls.length; i < len; i++){
5989                 var l = ls[i];
5990                 if(l.fn == fn && l.scope == scope){
5991                     return i;
5992                 }
5993             }
5994             return -1;
5995         },
5996
5997         isListening : function(fn, scope){
5998             return this.findListener(fn, scope) != -1;
5999         },
6000
6001         removeListener : function(fn, scope){
6002             var index;
6003             if((index = this.findListener(fn, scope)) != -1){
6004                 if(!this.firing){
6005                     this.listeners.splice(index, 1);
6006                 }else{
6007                     this.listeners = this.listeners.slice(0);
6008                     this.listeners.splice(index, 1);
6009                 }
6010                 return true;
6011             }
6012             return false;
6013         },
6014
6015         clearListeners : function(){
6016             this.listeners = [];
6017         },
6018
6019         fire : function(){
6020             var ls = this.listeners, scope, len = ls.length;
6021             if(len > 0){
6022                 this.firing = true;
6023                 var args = Array.prototype.slice.call(arguments, 0);
6024                 for(var i = 0; i < len; i++){
6025                     var l = ls[i];
6026                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6027                         this.firing = false;
6028                         return false;
6029                     }
6030                 }
6031                 this.firing = false;
6032             }
6033             return true;
6034         }
6035     };
6036 })();/*
6037  * Based on:
6038  * Ext JS Library 1.1.1
6039  * Copyright(c) 2006-2007, Ext JS, LLC.
6040  *
6041  * Originally Released Under LGPL - original licence link has changed is not relivant.
6042  *
6043  * Fork - LGPL
6044  * <script type="text/javascript">
6045  */
6046
6047 /**
6048  * @class Roo.EventManager
6049  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6050  * several useful events directly.
6051  * See {@link Roo.EventObject} for more details on normalized event objects.
6052  * @singleton
6053  */
6054 Roo.EventManager = function(){
6055     var docReadyEvent, docReadyProcId, docReadyState = false;
6056     var resizeEvent, resizeTask, textEvent, textSize;
6057     var E = Roo.lib.Event;
6058     var D = Roo.lib.Dom;
6059
6060
6061     var fireDocReady = function(){
6062         if(!docReadyState){
6063             docReadyState = true;
6064             Roo.isReady = true;
6065             if(docReadyProcId){
6066                 clearInterval(docReadyProcId);
6067             }
6068             if(Roo.isGecko || Roo.isOpera) {
6069                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6070             }
6071             if(Roo.isIE){
6072                 var defer = document.getElementById("ie-deferred-loader");
6073                 if(defer){
6074                     defer.onreadystatechange = null;
6075                     defer.parentNode.removeChild(defer);
6076                 }
6077             }
6078             if(docReadyEvent){
6079                 docReadyEvent.fire();
6080                 docReadyEvent.clearListeners();
6081             }
6082         }
6083     };
6084     
6085     var initDocReady = function(){
6086         docReadyEvent = new Roo.util.Event();
6087         if(Roo.isGecko || Roo.isOpera) {
6088             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6089         }else if(Roo.isIE){
6090             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6091             var defer = document.getElementById("ie-deferred-loader");
6092             defer.onreadystatechange = function(){
6093                 if(this.readyState == "complete"){
6094                     fireDocReady();
6095                 }
6096             };
6097         }else if(Roo.isSafari){ 
6098             docReadyProcId = setInterval(function(){
6099                 var rs = document.readyState;
6100                 if(rs == "complete") {
6101                     fireDocReady();     
6102                  }
6103             }, 10);
6104         }
6105         // no matter what, make sure it fires on load
6106         E.on(window, "load", fireDocReady);
6107     };
6108
6109     var createBuffered = function(h, o){
6110         var task = new Roo.util.DelayedTask(h);
6111         return function(e){
6112             // create new event object impl so new events don't wipe out properties
6113             e = new Roo.EventObjectImpl(e);
6114             task.delay(o.buffer, h, null, [e]);
6115         };
6116     };
6117
6118     var createSingle = function(h, el, ename, fn){
6119         return function(e){
6120             Roo.EventManager.removeListener(el, ename, fn);
6121             h(e);
6122         };
6123     };
6124
6125     var createDelayed = function(h, o){
6126         return function(e){
6127             // create new event object impl so new events don't wipe out properties
6128             e = new Roo.EventObjectImpl(e);
6129             setTimeout(function(){
6130                 h(e);
6131             }, o.delay || 10);
6132         };
6133     };
6134
6135     var listen = function(element, ename, opt, fn, scope){
6136         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6137         fn = fn || o.fn; scope = scope || o.scope;
6138         var el = Roo.getDom(element);
6139         if(!el){
6140             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6141         }
6142         var h = function(e){
6143             e = Roo.EventObject.setEvent(e);
6144             var t;
6145             if(o.delegate){
6146                 t = e.getTarget(o.delegate, el);
6147                 if(!t){
6148                     return;
6149                 }
6150             }else{
6151                 t = e.target;
6152             }
6153             if(o.stopEvent === true){
6154                 e.stopEvent();
6155             }
6156             if(o.preventDefault === true){
6157                e.preventDefault();
6158             }
6159             if(o.stopPropagation === true){
6160                 e.stopPropagation();
6161             }
6162
6163             if(o.normalized === false){
6164                 e = e.browserEvent;
6165             }
6166
6167             fn.call(scope || el, e, t, o);
6168         };
6169         if(o.delay){
6170             h = createDelayed(h, o);
6171         }
6172         if(o.single){
6173             h = createSingle(h, el, ename, fn);
6174         }
6175         if(o.buffer){
6176             h = createBuffered(h, o);
6177         }
6178         fn._handlers = fn._handlers || [];
6179         fn._handlers.push([Roo.id(el), ename, h]);
6180
6181         E.on(el, ename, h);
6182         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6183             el.addEventListener("DOMMouseScroll", h, false);
6184             E.on(window, 'unload', function(){
6185                 el.removeEventListener("DOMMouseScroll", h, false);
6186             });
6187         }
6188         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6189             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6190         }
6191         return h;
6192     };
6193
6194     var stopListening = function(el, ename, fn){
6195         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6196         if(hds){
6197             for(var i = 0, len = hds.length; i < len; i++){
6198                 var h = hds[i];
6199                 if(h[0] == id && h[1] == ename){
6200                     hd = h[2];
6201                     hds.splice(i, 1);
6202                     break;
6203                 }
6204             }
6205         }
6206         E.un(el, ename, hd);
6207         el = Roo.getDom(el);
6208         if(ename == "mousewheel" && el.addEventListener){
6209             el.removeEventListener("DOMMouseScroll", hd, false);
6210         }
6211         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6212             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6213         }
6214     };
6215
6216     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6217     
6218     var pub = {
6219         
6220         
6221         /** 
6222          * Fix for doc tools
6223          * @scope Roo.EventManager
6224          */
6225         
6226         
6227         /** 
6228          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6229          * object with a Roo.EventObject
6230          * @param {Function} fn        The method the event invokes
6231          * @param {Object}   scope    An object that becomes the scope of the handler
6232          * @param {boolean}  override If true, the obj passed in becomes
6233          *                             the execution scope of the listener
6234          * @return {Function} The wrapped function
6235          * @deprecated
6236          */
6237         wrap : function(fn, scope, override){
6238             return function(e){
6239                 Roo.EventObject.setEvent(e);
6240                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6241             };
6242         },
6243         
6244         /**
6245      * Appends an event handler to an element (shorthand for addListener)
6246      * @param {String/HTMLElement}   element        The html element or id to assign the
6247      * @param {String}   eventName The type of event to listen for
6248      * @param {Function} handler The method the event invokes
6249      * @param {Object}   scope (optional) The scope in which to execute the handler
6250      * function. The handler function's "this" context.
6251      * @param {Object}   options (optional) An object containing handler configuration
6252      * properties. This may contain any of the following properties:<ul>
6253      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6254      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6255      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6256      * <li>preventDefault {Boolean} True to prevent the default action</li>
6257      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6258      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6259      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6260      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6261      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6262      * by the specified number of milliseconds. If the event fires again within that time, the original
6263      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6264      * </ul><br>
6265      * <p>
6266      * <b>Combining Options</b><br>
6267      * Using the options argument, it is possible to combine different types of listeners:<br>
6268      * <br>
6269      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6270      * Code:<pre><code>
6271 el.on('click', this.onClick, this, {
6272     single: true,
6273     delay: 100,
6274     stopEvent : true,
6275     forumId: 4
6276 });</code></pre>
6277      * <p>
6278      * <b>Attaching multiple handlers in 1 call</b><br>
6279       * The method also allows for a single argument to be passed which is a config object containing properties
6280      * which specify multiple handlers.
6281      * <p>
6282      * Code:<pre><code>
6283 el.on({
6284     'click' : {
6285         fn: this.onClick
6286         scope: this,
6287         delay: 100
6288     },
6289     'mouseover' : {
6290         fn: this.onMouseOver
6291         scope: this
6292     },
6293     'mouseout' : {
6294         fn: this.onMouseOut
6295         scope: this
6296     }
6297 });</code></pre>
6298      * <p>
6299      * Or a shorthand syntax:<br>
6300      * Code:<pre><code>
6301 el.on({
6302     'click' : this.onClick,
6303     'mouseover' : this.onMouseOver,
6304     'mouseout' : this.onMouseOut
6305     scope: this
6306 });</code></pre>
6307      */
6308         addListener : function(element, eventName, fn, scope, options){
6309             if(typeof eventName == "object"){
6310                 var o = eventName;
6311                 for(var e in o){
6312                     if(propRe.test(e)){
6313                         continue;
6314                     }
6315                     if(typeof o[e] == "function"){
6316                         // shared options
6317                         listen(element, e, o, o[e], o.scope);
6318                     }else{
6319                         // individual options
6320                         listen(element, e, o[e]);
6321                     }
6322                 }
6323                 return;
6324             }
6325             return listen(element, eventName, options, fn, scope);
6326         },
6327         
6328         /**
6329          * Removes an event handler
6330          *
6331          * @param {String/HTMLElement}   element        The id or html element to remove the 
6332          *                             event from
6333          * @param {String}   eventName     The type of event
6334          * @param {Function} fn
6335          * @return {Boolean} True if a listener was actually removed
6336          */
6337         removeListener : function(element, eventName, fn){
6338             return stopListening(element, eventName, fn);
6339         },
6340         
6341         /**
6342          * Fires when the document is ready (before onload and before images are loaded). Can be 
6343          * accessed shorthanded Roo.onReady().
6344          * @param {Function} fn        The method the event invokes
6345          * @param {Object}   scope    An  object that becomes the scope of the handler
6346          * @param {boolean}  options
6347          */
6348         onDocumentReady : function(fn, scope, options){
6349             if(docReadyState){ // if it already fired
6350                 docReadyEvent.addListener(fn, scope, options);
6351                 docReadyEvent.fire();
6352                 docReadyEvent.clearListeners();
6353                 return;
6354             }
6355             if(!docReadyEvent){
6356                 initDocReady();
6357             }
6358             docReadyEvent.addListener(fn, scope, options);
6359         },
6360         
6361         /**
6362          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6363          * @param {Function} fn        The method the event invokes
6364          * @param {Object}   scope    An object that becomes the scope of the handler
6365          * @param {boolean}  options
6366          */
6367         onWindowResize : function(fn, scope, options){
6368             if(!resizeEvent){
6369                 resizeEvent = new Roo.util.Event();
6370                 resizeTask = new Roo.util.DelayedTask(function(){
6371                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6372                 });
6373                 E.on(window, "resize", function(){
6374                     if(Roo.isIE){
6375                         resizeTask.delay(50);
6376                     }else{
6377                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6378                     }
6379                 });
6380             }
6381             resizeEvent.addListener(fn, scope, options);
6382         },
6383
6384         /**
6385          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6386          * @param {Function} fn        The method the event invokes
6387          * @param {Object}   scope    An object that becomes the scope of the handler
6388          * @param {boolean}  options
6389          */
6390         onTextResize : function(fn, scope, options){
6391             if(!textEvent){
6392                 textEvent = new Roo.util.Event();
6393                 var textEl = new Roo.Element(document.createElement('div'));
6394                 textEl.dom.className = 'x-text-resize';
6395                 textEl.dom.innerHTML = 'X';
6396                 textEl.appendTo(document.body);
6397                 textSize = textEl.dom.offsetHeight;
6398                 setInterval(function(){
6399                     if(textEl.dom.offsetHeight != textSize){
6400                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6401                     }
6402                 }, this.textResizeInterval);
6403             }
6404             textEvent.addListener(fn, scope, options);
6405         },
6406
6407         /**
6408          * Removes the passed window resize listener.
6409          * @param {Function} fn        The method the event invokes
6410          * @param {Object}   scope    The scope of handler
6411          */
6412         removeResizeListener : function(fn, scope){
6413             if(resizeEvent){
6414                 resizeEvent.removeListener(fn, scope);
6415             }
6416         },
6417
6418         // private
6419         fireResize : function(){
6420             if(resizeEvent){
6421                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6422             }   
6423         },
6424         /**
6425          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6426          */
6427         ieDeferSrc : false,
6428         /**
6429          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6430          */
6431         textResizeInterval : 50
6432     };
6433     
6434     /**
6435      * Fix for doc tools
6436      * @scopeAlias pub=Roo.EventManager
6437      */
6438     
6439      /**
6440      * Appends an event handler to an element (shorthand for addListener)
6441      * @param {String/HTMLElement}   element        The html element or id to assign the
6442      * @param {String}   eventName The type of event to listen for
6443      * @param {Function} handler The method the event invokes
6444      * @param {Object}   scope (optional) The scope in which to execute the handler
6445      * function. The handler function's "this" context.
6446      * @param {Object}   options (optional) An object containing handler configuration
6447      * properties. This may contain any of the following properties:<ul>
6448      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6449      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6450      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6451      * <li>preventDefault {Boolean} True to prevent the default action</li>
6452      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6453      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6454      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6455      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6456      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6457      * by the specified number of milliseconds. If the event fires again within that time, the original
6458      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6459      * </ul><br>
6460      * <p>
6461      * <b>Combining Options</b><br>
6462      * Using the options argument, it is possible to combine different types of listeners:<br>
6463      * <br>
6464      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6465      * Code:<pre><code>
6466 el.on('click', this.onClick, this, {
6467     single: true,
6468     delay: 100,
6469     stopEvent : true,
6470     forumId: 4
6471 });</code></pre>
6472      * <p>
6473      * <b>Attaching multiple handlers in 1 call</b><br>
6474       * The method also allows for a single argument to be passed which is a config object containing properties
6475      * which specify multiple handlers.
6476      * <p>
6477      * Code:<pre><code>
6478 el.on({
6479     'click' : {
6480         fn: this.onClick
6481         scope: this,
6482         delay: 100
6483     },
6484     'mouseover' : {
6485         fn: this.onMouseOver
6486         scope: this
6487     },
6488     'mouseout' : {
6489         fn: this.onMouseOut
6490         scope: this
6491     }
6492 });</code></pre>
6493      * <p>
6494      * Or a shorthand syntax:<br>
6495      * Code:<pre><code>
6496 el.on({
6497     'click' : this.onClick,
6498     'mouseover' : this.onMouseOver,
6499     'mouseout' : this.onMouseOut
6500     scope: this
6501 });</code></pre>
6502      */
6503     pub.on = pub.addListener;
6504     pub.un = pub.removeListener;
6505
6506     pub.stoppedMouseDownEvent = new Roo.util.Event();
6507     return pub;
6508 }();
6509 /**
6510   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6511   * @param {Function} fn        The method the event invokes
6512   * @param {Object}   scope    An  object that becomes the scope of the handler
6513   * @param {boolean}  override If true, the obj passed in becomes
6514   *                             the execution scope of the listener
6515   * @member Roo
6516   * @method onReady
6517  */
6518 Roo.onReady = Roo.EventManager.onDocumentReady;
6519
6520 Roo.onReady(function(){
6521     var bd = Roo.get(document.body);
6522     if(!bd){ return; }
6523
6524     var cls = [
6525             Roo.isIE ? "roo-ie"
6526             : Roo.isGecko ? "roo-gecko"
6527             : Roo.isOpera ? "roo-opera"
6528             : Roo.isSafari ? "roo-safari" : ""];
6529
6530     if(Roo.isMac){
6531         cls.push("roo-mac");
6532     }
6533     if(Roo.isLinux){
6534         cls.push("roo-linux");
6535     }
6536     if(Roo.isBorderBox){
6537         cls.push('roo-border-box');
6538     }
6539     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6540         var p = bd.dom.parentNode;
6541         if(p){
6542             p.className += ' roo-strict';
6543         }
6544     }
6545     bd.addClass(cls.join(' '));
6546 });
6547
6548 /**
6549  * @class Roo.EventObject
6550  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6551  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6552  * Example:
6553  * <pre><code>
6554  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6555     e.preventDefault();
6556     var target = e.getTarget();
6557     ...
6558  }
6559  var myDiv = Roo.get("myDiv");
6560  myDiv.on("click", handleClick);
6561  //or
6562  Roo.EventManager.on("myDiv", 'click', handleClick);
6563  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6564  </code></pre>
6565  * @singleton
6566  */
6567 Roo.EventObject = function(){
6568     
6569     var E = Roo.lib.Event;
6570     
6571     // safari keypress events for special keys return bad keycodes
6572     var safariKeys = {
6573         63234 : 37, // left
6574         63235 : 39, // right
6575         63232 : 38, // up
6576         63233 : 40, // down
6577         63276 : 33, // page up
6578         63277 : 34, // page down
6579         63272 : 46, // delete
6580         63273 : 36, // home
6581         63275 : 35  // end
6582     };
6583
6584     // normalize button clicks
6585     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6586                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6587
6588     Roo.EventObjectImpl = function(e){
6589         if(e){
6590             this.setEvent(e.browserEvent || e);
6591         }
6592     };
6593     Roo.EventObjectImpl.prototype = {
6594         /**
6595          * Used to fix doc tools.
6596          * @scope Roo.EventObject.prototype
6597          */
6598             
6599
6600         
6601         
6602         /** The normal browser event */
6603         browserEvent : null,
6604         /** The button pressed in a mouse event */
6605         button : -1,
6606         /** True if the shift key was down during the event */
6607         shiftKey : false,
6608         /** True if the control key was down during the event */
6609         ctrlKey : false,
6610         /** True if the alt key was down during the event */
6611         altKey : false,
6612
6613         /** Key constant 
6614         * @type Number */
6615         BACKSPACE : 8,
6616         /** Key constant 
6617         * @type Number */
6618         TAB : 9,
6619         /** Key constant 
6620         * @type Number */
6621         RETURN : 13,
6622         /** Key constant 
6623         * @type Number */
6624         ENTER : 13,
6625         /** Key constant 
6626         * @type Number */
6627         SHIFT : 16,
6628         /** Key constant 
6629         * @type Number */
6630         CONTROL : 17,
6631         /** Key constant 
6632         * @type Number */
6633         ESC : 27,
6634         /** Key constant 
6635         * @type Number */
6636         SPACE : 32,
6637         /** Key constant 
6638         * @type Number */
6639         PAGEUP : 33,
6640         /** Key constant 
6641         * @type Number */
6642         PAGEDOWN : 34,
6643         /** Key constant 
6644         * @type Number */
6645         END : 35,
6646         /** Key constant 
6647         * @type Number */
6648         HOME : 36,
6649         /** Key constant 
6650         * @type Number */
6651         LEFT : 37,
6652         /** Key constant 
6653         * @type Number */
6654         UP : 38,
6655         /** Key constant 
6656         * @type Number */
6657         RIGHT : 39,
6658         /** Key constant 
6659         * @type Number */
6660         DOWN : 40,
6661         /** Key constant 
6662         * @type Number */
6663         DELETE : 46,
6664         /** Key constant 
6665         * @type Number */
6666         F5 : 116,
6667
6668            /** @private */
6669         setEvent : function(e){
6670             if(e == this || (e && e.browserEvent)){ // already wrapped
6671                 return e;
6672             }
6673             this.browserEvent = e;
6674             if(e){
6675                 // normalize buttons
6676                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6677                 if(e.type == 'click' && this.button == -1){
6678                     this.button = 0;
6679                 }
6680                 this.type = e.type;
6681                 this.shiftKey = e.shiftKey;
6682                 // mac metaKey behaves like ctrlKey
6683                 this.ctrlKey = e.ctrlKey || e.metaKey;
6684                 this.altKey = e.altKey;
6685                 // in getKey these will be normalized for the mac
6686                 this.keyCode = e.keyCode;
6687                 // keyup warnings on firefox.
6688                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6689                 // cache the target for the delayed and or buffered events
6690                 this.target = E.getTarget(e);
6691                 // same for XY
6692                 this.xy = E.getXY(e);
6693             }else{
6694                 this.button = -1;
6695                 this.shiftKey = false;
6696                 this.ctrlKey = false;
6697                 this.altKey = false;
6698                 this.keyCode = 0;
6699                 this.charCode =0;
6700                 this.target = null;
6701                 this.xy = [0, 0];
6702             }
6703             return this;
6704         },
6705
6706         /**
6707          * Stop the event (preventDefault and stopPropagation)
6708          */
6709         stopEvent : function(){
6710             if(this.browserEvent){
6711                 if(this.browserEvent.type == 'mousedown'){
6712                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6713                 }
6714                 E.stopEvent(this.browserEvent);
6715             }
6716         },
6717
6718         /**
6719          * Prevents the browsers default handling of the event.
6720          */
6721         preventDefault : function(){
6722             if(this.browserEvent){
6723                 E.preventDefault(this.browserEvent);
6724             }
6725         },
6726
6727         /** @private */
6728         isNavKeyPress : function(){
6729             var k = this.keyCode;
6730             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6731             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6732         },
6733
6734         isSpecialKey : function(){
6735             var k = this.keyCode;
6736             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6737             (k == 16) || (k == 17) ||
6738             (k >= 18 && k <= 20) ||
6739             (k >= 33 && k <= 35) ||
6740             (k >= 36 && k <= 39) ||
6741             (k >= 44 && k <= 45);
6742         },
6743         /**
6744          * Cancels bubbling of the event.
6745          */
6746         stopPropagation : function(){
6747             if(this.browserEvent){
6748                 if(this.type == 'mousedown'){
6749                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6750                 }
6751                 E.stopPropagation(this.browserEvent);
6752             }
6753         },
6754
6755         /**
6756          * Gets the key code for the event.
6757          * @return {Number}
6758          */
6759         getCharCode : function(){
6760             return this.charCode || this.keyCode;
6761         },
6762
6763         /**
6764          * Returns a normalized keyCode for the event.
6765          * @return {Number} The key code
6766          */
6767         getKey : function(){
6768             var k = this.keyCode || this.charCode;
6769             return Roo.isSafari ? (safariKeys[k] || k) : k;
6770         },
6771
6772         /**
6773          * Gets the x coordinate of the event.
6774          * @return {Number}
6775          */
6776         getPageX : function(){
6777             return this.xy[0];
6778         },
6779
6780         /**
6781          * Gets the y coordinate of the event.
6782          * @return {Number}
6783          */
6784         getPageY : function(){
6785             return this.xy[1];
6786         },
6787
6788         /**
6789          * Gets the time of the event.
6790          * @return {Number}
6791          */
6792         getTime : function(){
6793             if(this.browserEvent){
6794                 return E.getTime(this.browserEvent);
6795             }
6796             return null;
6797         },
6798
6799         /**
6800          * Gets the page coordinates of the event.
6801          * @return {Array} The xy values like [x, y]
6802          */
6803         getXY : function(){
6804             return this.xy;
6805         },
6806
6807         /**
6808          * Gets the target for the event.
6809          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6810          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6811                 search as a number or element (defaults to 10 || document.body)
6812          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6813          * @return {HTMLelement}
6814          */
6815         getTarget : function(selector, maxDepth, returnEl){
6816             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6817         },
6818         /**
6819          * Gets the related target.
6820          * @return {HTMLElement}
6821          */
6822         getRelatedTarget : function(){
6823             if(this.browserEvent){
6824                 return E.getRelatedTarget(this.browserEvent);
6825             }
6826             return null;
6827         },
6828
6829         /**
6830          * Normalizes mouse wheel delta across browsers
6831          * @return {Number} The delta
6832          */
6833         getWheelDelta : function(){
6834             var e = this.browserEvent;
6835             var delta = 0;
6836             if(e.wheelDelta){ /* IE/Opera. */
6837                 delta = e.wheelDelta/120;
6838             }else if(e.detail){ /* Mozilla case. */
6839                 delta = -e.detail/3;
6840             }
6841             return delta;
6842         },
6843
6844         /**
6845          * Returns true if the control, meta, shift or alt key was pressed during this event.
6846          * @return {Boolean}
6847          */
6848         hasModifier : function(){
6849             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6850         },
6851
6852         /**
6853          * Returns true if the target of this event equals el or is a child of el
6854          * @param {String/HTMLElement/Element} el
6855          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6856          * @return {Boolean}
6857          */
6858         within : function(el, related){
6859             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6860             return t && Roo.fly(el).contains(t);
6861         },
6862
6863         getPoint : function(){
6864             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6865         }
6866     };
6867
6868     return new Roo.EventObjectImpl();
6869 }();
6870             
6871     /*
6872  * Based on:
6873  * Ext JS Library 1.1.1
6874  * Copyright(c) 2006-2007, Ext JS, LLC.
6875  *
6876  * Originally Released Under LGPL - original licence link has changed is not relivant.
6877  *
6878  * Fork - LGPL
6879  * <script type="text/javascript">
6880  */
6881
6882  
6883 // was in Composite Element!??!?!
6884  
6885 (function(){
6886     var D = Roo.lib.Dom;
6887     var E = Roo.lib.Event;
6888     var A = Roo.lib.Anim;
6889
6890     // local style camelizing for speed
6891     var propCache = {};
6892     var camelRe = /(-[a-z])/gi;
6893     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6894     var view = document.defaultView;
6895
6896 /**
6897  * @class Roo.Element
6898  * Represents an Element in the DOM.<br><br>
6899  * Usage:<br>
6900 <pre><code>
6901 var el = Roo.get("my-div");
6902
6903 // or with getEl
6904 var el = getEl("my-div");
6905
6906 // or with a DOM element
6907 var el = Roo.get(myDivElement);
6908 </code></pre>
6909  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6910  * each call instead of constructing a new one.<br><br>
6911  * <b>Animations</b><br />
6912  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6913  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6914 <pre>
6915 Option    Default   Description
6916 --------- --------  ---------------------------------------------
6917 duration  .35       The duration of the animation in seconds
6918 easing    easeOut   The YUI easing method
6919 callback  none      A function to execute when the anim completes
6920 scope     this      The scope (this) of the callback function
6921 </pre>
6922 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6923 * manipulate the animation. Here's an example:
6924 <pre><code>
6925 var el = Roo.get("my-div");
6926
6927 // no animation
6928 el.setWidth(100);
6929
6930 // default animation
6931 el.setWidth(100, true);
6932
6933 // animation with some options set
6934 el.setWidth(100, {
6935     duration: 1,
6936     callback: this.foo,
6937     scope: this
6938 });
6939
6940 // using the "anim" property to get the Anim object
6941 var opt = {
6942     duration: 1,
6943     callback: this.foo,
6944     scope: this
6945 };
6946 el.setWidth(100, opt);
6947 ...
6948 if(opt.anim.isAnimated()){
6949     opt.anim.stop();
6950 }
6951 </code></pre>
6952 * <b> Composite (Collections of) Elements</b><br />
6953  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6954  * @constructor Create a new Element directly.
6955  * @param {String/HTMLElement} element
6956  * @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).
6957  */
6958     Roo.Element = function(element, forceNew){
6959         var dom = typeof element == "string" ?
6960                 document.getElementById(element) : element;
6961         if(!dom){ // invalid id/element
6962             return null;
6963         }
6964         var id = dom.id;
6965         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6966             return Roo.Element.cache[id];
6967         }
6968
6969         /**
6970          * The DOM element
6971          * @type HTMLElement
6972          */
6973         this.dom = dom;
6974
6975         /**
6976          * The DOM element ID
6977          * @type String
6978          */
6979         this.id = id || Roo.id(dom);
6980     };
6981
6982     var El = Roo.Element;
6983
6984     El.prototype = {
6985         /**
6986          * The element's default display mode  (defaults to "")
6987          * @type String
6988          */
6989         originalDisplay : "",
6990
6991         visibilityMode : 1,
6992         /**
6993          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6994          * @type String
6995          */
6996         defaultUnit : "px",
6997         /**
6998          * Sets the element's visibility mode. When setVisible() is called it
6999          * will use this to determine whether to set the visibility or the display property.
7000          * @param visMode Element.VISIBILITY or Element.DISPLAY
7001          * @return {Roo.Element} this
7002          */
7003         setVisibilityMode : function(visMode){
7004             this.visibilityMode = visMode;
7005             return this;
7006         },
7007         /**
7008          * Convenience method for setVisibilityMode(Element.DISPLAY)
7009          * @param {String} display (optional) What to set display to when visible
7010          * @return {Roo.Element} this
7011          */
7012         enableDisplayMode : function(display){
7013             this.setVisibilityMode(El.DISPLAY);
7014             if(typeof display != "undefined") this.originalDisplay = display;
7015             return this;
7016         },
7017
7018         /**
7019          * 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)
7020          * @param {String} selector The simple selector to test
7021          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7022                 search as a number or element (defaults to 10 || document.body)
7023          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7024          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7025          */
7026         findParent : function(simpleSelector, maxDepth, returnEl){
7027             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7028             maxDepth = maxDepth || 50;
7029             if(typeof maxDepth != "number"){
7030                 stopEl = Roo.getDom(maxDepth);
7031                 maxDepth = 10;
7032             }
7033             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7034                 if(dq.is(p, simpleSelector)){
7035                     return returnEl ? Roo.get(p) : p;
7036                 }
7037                 depth++;
7038                 p = p.parentNode;
7039             }
7040             return null;
7041         },
7042
7043
7044         /**
7045          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7046          * @param {String} selector The simple selector to test
7047          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7048                 search as a number or element (defaults to 10 || document.body)
7049          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7050          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7051          */
7052         findParentNode : function(simpleSelector, maxDepth, returnEl){
7053             var p = Roo.fly(this.dom.parentNode, '_internal');
7054             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7055         },
7056
7057         /**
7058          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7059          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7060          * @param {String} selector The simple selector to test
7061          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7062                 search as a number or element (defaults to 10 || document.body)
7063          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7064          */
7065         up : function(simpleSelector, maxDepth){
7066             return this.findParentNode(simpleSelector, maxDepth, true);
7067         },
7068
7069
7070
7071         /**
7072          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7073          * @param {String} selector The simple selector to test
7074          * @return {Boolean} True if this element matches the selector, else false
7075          */
7076         is : function(simpleSelector){
7077             return Roo.DomQuery.is(this.dom, simpleSelector);
7078         },
7079
7080         /**
7081          * Perform animation on this element.
7082          * @param {Object} args The YUI animation control args
7083          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7084          * @param {Function} onComplete (optional) Function to call when animation completes
7085          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7086          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7087          * @return {Roo.Element} this
7088          */
7089         animate : function(args, duration, onComplete, easing, animType){
7090             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7091             return this;
7092         },
7093
7094         /*
7095          * @private Internal animation call
7096          */
7097         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7098             animType = animType || 'run';
7099             opt = opt || {};
7100             var anim = Roo.lib.Anim[animType](
7101                 this.dom, args,
7102                 (opt.duration || defaultDur) || .35,
7103                 (opt.easing || defaultEase) || 'easeOut',
7104                 function(){
7105                     Roo.callback(cb, this);
7106                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7107                 },
7108                 this
7109             );
7110             opt.anim = anim;
7111             return anim;
7112         },
7113
7114         // private legacy anim prep
7115         preanim : function(a, i){
7116             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7117         },
7118
7119         /**
7120          * Removes worthless text nodes
7121          * @param {Boolean} forceReclean (optional) By default the element
7122          * keeps track if it has been cleaned already so
7123          * you can call this over and over. However, if you update the element and
7124          * need to force a reclean, you can pass true.
7125          */
7126         clean : function(forceReclean){
7127             if(this.isCleaned && forceReclean !== true){
7128                 return this;
7129             }
7130             var ns = /\S/;
7131             var d = this.dom, n = d.firstChild, ni = -1;
7132             while(n){
7133                 var nx = n.nextSibling;
7134                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7135                     d.removeChild(n);
7136                 }else{
7137                     n.nodeIndex = ++ni;
7138                 }
7139                 n = nx;
7140             }
7141             this.isCleaned = true;
7142             return this;
7143         },
7144
7145         // private
7146         calcOffsetsTo : function(el){
7147             el = Roo.get(el);
7148             var d = el.dom;
7149             var restorePos = false;
7150             if(el.getStyle('position') == 'static'){
7151                 el.position('relative');
7152                 restorePos = true;
7153             }
7154             var x = 0, y =0;
7155             var op = this.dom;
7156             while(op && op != d && op.tagName != 'HTML'){
7157                 x+= op.offsetLeft;
7158                 y+= op.offsetTop;
7159                 op = op.offsetParent;
7160             }
7161             if(restorePos){
7162                 el.position('static');
7163             }
7164             return [x, y];
7165         },
7166
7167         /**
7168          * Scrolls this element into view within the passed container.
7169          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7170          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7171          * @return {Roo.Element} this
7172          */
7173         scrollIntoView : function(container, hscroll){
7174             var c = Roo.getDom(container) || document.body;
7175             var el = this.dom;
7176
7177             var o = this.calcOffsetsTo(c),
7178                 l = o[0],
7179                 t = o[1],
7180                 b = t+el.offsetHeight,
7181                 r = l+el.offsetWidth;
7182
7183             var ch = c.clientHeight;
7184             var ct = parseInt(c.scrollTop, 10);
7185             var cl = parseInt(c.scrollLeft, 10);
7186             var cb = ct + ch;
7187             var cr = cl + c.clientWidth;
7188
7189             if(t < ct){
7190                 c.scrollTop = t;
7191             }else if(b > cb){
7192                 c.scrollTop = b-ch;
7193             }
7194
7195             if(hscroll !== false){
7196                 if(l < cl){
7197                     c.scrollLeft = l;
7198                 }else if(r > cr){
7199                     c.scrollLeft = r-c.clientWidth;
7200                 }
7201             }
7202             return this;
7203         },
7204
7205         // private
7206         scrollChildIntoView : function(child, hscroll){
7207             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7208         },
7209
7210         /**
7211          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7212          * the new height may not be available immediately.
7213          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7214          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7215          * @param {Function} onComplete (optional) Function to call when animation completes
7216          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7217          * @return {Roo.Element} this
7218          */
7219         autoHeight : function(animate, duration, onComplete, easing){
7220             var oldHeight = this.getHeight();
7221             this.clip();
7222             this.setHeight(1); // force clipping
7223             setTimeout(function(){
7224                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7225                 if(!animate){
7226                     this.setHeight(height);
7227                     this.unclip();
7228                     if(typeof onComplete == "function"){
7229                         onComplete();
7230                     }
7231                 }else{
7232                     this.setHeight(oldHeight); // restore original height
7233                     this.setHeight(height, animate, duration, function(){
7234                         this.unclip();
7235                         if(typeof onComplete == "function") onComplete();
7236                     }.createDelegate(this), easing);
7237                 }
7238             }.createDelegate(this), 0);
7239             return this;
7240         },
7241
7242         /**
7243          * Returns true if this element is an ancestor of the passed element
7244          * @param {HTMLElement/String} el The element to check
7245          * @return {Boolean} True if this element is an ancestor of el, else false
7246          */
7247         contains : function(el){
7248             if(!el){return false;}
7249             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7250         },
7251
7252         /**
7253          * Checks whether the element is currently visible using both visibility and display properties.
7254          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7255          * @return {Boolean} True if the element is currently visible, else false
7256          */
7257         isVisible : function(deep) {
7258             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7259             if(deep !== true || !vis){
7260                 return vis;
7261             }
7262             var p = this.dom.parentNode;
7263             while(p && p.tagName.toLowerCase() != "body"){
7264                 if(!Roo.fly(p, '_isVisible').isVisible()){
7265                     return false;
7266                 }
7267                 p = p.parentNode;
7268             }
7269             return true;
7270         },
7271
7272         /**
7273          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7274          * @param {String} selector The CSS selector
7275          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7276          * @return {CompositeElement/CompositeElementLite} The composite element
7277          */
7278         select : function(selector, unique){
7279             return El.select(selector, unique, this.dom);
7280         },
7281
7282         /**
7283          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7284          * @param {String} selector The CSS selector
7285          * @return {Array} An array of the matched nodes
7286          */
7287         query : function(selector, unique){
7288             return Roo.DomQuery.select(selector, this.dom);
7289         },
7290
7291         /**
7292          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7293          * @param {String} selector The CSS selector
7294          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7295          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7296          */
7297         child : function(selector, returnDom){
7298             var n = Roo.DomQuery.selectNode(selector, this.dom);
7299             return returnDom ? n : Roo.get(n);
7300         },
7301
7302         /**
7303          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7304          * @param {String} selector The CSS selector
7305          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7306          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7307          */
7308         down : function(selector, returnDom){
7309             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7310             return returnDom ? n : Roo.get(n);
7311         },
7312
7313         /**
7314          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7315          * @param {String} group The group the DD object is member of
7316          * @param {Object} config The DD config object
7317          * @param {Object} overrides An object containing methods to override/implement on the DD object
7318          * @return {Roo.dd.DD} The DD object
7319          */
7320         initDD : function(group, config, overrides){
7321             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7322             return Roo.apply(dd, overrides);
7323         },
7324
7325         /**
7326          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7327          * @param {String} group The group the DDProxy object is member of
7328          * @param {Object} config The DDProxy config object
7329          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7330          * @return {Roo.dd.DDProxy} The DDProxy object
7331          */
7332         initDDProxy : function(group, config, overrides){
7333             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7334             return Roo.apply(dd, overrides);
7335         },
7336
7337         /**
7338          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7339          * @param {String} group The group the DDTarget object is member of
7340          * @param {Object} config The DDTarget config object
7341          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7342          * @return {Roo.dd.DDTarget} The DDTarget object
7343          */
7344         initDDTarget : function(group, config, overrides){
7345             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7346             return Roo.apply(dd, overrides);
7347         },
7348
7349         /**
7350          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7351          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7352          * @param {Boolean} visible Whether the element is visible
7353          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7354          * @return {Roo.Element} this
7355          */
7356          setVisible : function(visible, animate){
7357             if(!animate || !A){
7358                 if(this.visibilityMode == El.DISPLAY){
7359                     this.setDisplayed(visible);
7360                 }else{
7361                     this.fixDisplay();
7362                     this.dom.style.visibility = visible ? "visible" : "hidden";
7363                 }
7364             }else{
7365                 // closure for composites
7366                 var dom = this.dom;
7367                 var visMode = this.visibilityMode;
7368                 if(visible){
7369                     this.setOpacity(.01);
7370                     this.setVisible(true);
7371                 }
7372                 this.anim({opacity: { to: (visible?1:0) }},
7373                       this.preanim(arguments, 1),
7374                       null, .35, 'easeIn', function(){
7375                          if(!visible){
7376                              if(visMode == El.DISPLAY){
7377                                  dom.style.display = "none";
7378                              }else{
7379                                  dom.style.visibility = "hidden";
7380                              }
7381                              Roo.get(dom).setOpacity(1);
7382                          }
7383                      });
7384             }
7385             return this;
7386         },
7387
7388         /**
7389          * Returns true if display is not "none"
7390          * @return {Boolean}
7391          */
7392         isDisplayed : function() {
7393             return this.getStyle("display") != "none";
7394         },
7395
7396         /**
7397          * Toggles the element's visibility or display, depending on visibility mode.
7398          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7399          * @return {Roo.Element} this
7400          */
7401         toggle : function(animate){
7402             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7403             return this;
7404         },
7405
7406         /**
7407          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7408          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7409          * @return {Roo.Element} this
7410          */
7411         setDisplayed : function(value) {
7412             if(typeof value == "boolean"){
7413                value = value ? this.originalDisplay : "none";
7414             }
7415             this.setStyle("display", value);
7416             return this;
7417         },
7418
7419         /**
7420          * Tries to focus the element. Any exceptions are caught and ignored.
7421          * @return {Roo.Element} this
7422          */
7423         focus : function() {
7424             try{
7425                 this.dom.focus();
7426             }catch(e){}
7427             return this;
7428         },
7429
7430         /**
7431          * Tries to blur the element. Any exceptions are caught and ignored.
7432          * @return {Roo.Element} this
7433          */
7434         blur : function() {
7435             try{
7436                 this.dom.blur();
7437             }catch(e){}
7438             return this;
7439         },
7440
7441         /**
7442          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7443          * @param {String/Array} className The CSS class to add, or an array of classes
7444          * @return {Roo.Element} this
7445          */
7446         addClass : function(className){
7447             if(className instanceof Array){
7448                 for(var i = 0, len = className.length; i < len; i++) {
7449                     this.addClass(className[i]);
7450                 }
7451             }else{
7452                 if(className && !this.hasClass(className)){
7453                     this.dom.className = this.dom.className + " " + className;
7454                 }
7455             }
7456             return this;
7457         },
7458
7459         /**
7460          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7461          * @param {String/Array} className The CSS class to add, or an array of classes
7462          * @return {Roo.Element} this
7463          */
7464         radioClass : function(className){
7465             var siblings = this.dom.parentNode.childNodes;
7466             for(var i = 0; i < siblings.length; i++) {
7467                 var s = siblings[i];
7468                 if(s.nodeType == 1){
7469                     Roo.get(s).removeClass(className);
7470                 }
7471             }
7472             this.addClass(className);
7473             return this;
7474         },
7475
7476         /**
7477          * Removes one or more CSS classes from the element.
7478          * @param {String/Array} className The CSS class to remove, or an array of classes
7479          * @return {Roo.Element} this
7480          */
7481         removeClass : function(className){
7482             if(!className || !this.dom.className){
7483                 return this;
7484             }
7485             if(className instanceof Array){
7486                 for(var i = 0, len = className.length; i < len; i++) {
7487                     this.removeClass(className[i]);
7488                 }
7489             }else{
7490                 if(this.hasClass(className)){
7491                     var re = this.classReCache[className];
7492                     if (!re) {
7493                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7494                        this.classReCache[className] = re;
7495                     }
7496                     this.dom.className =
7497                         this.dom.className.replace(re, " ");
7498                 }
7499             }
7500             return this;
7501         },
7502
7503         // private
7504         classReCache: {},
7505
7506         /**
7507          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7508          * @param {String} className The CSS class to toggle
7509          * @return {Roo.Element} this
7510          */
7511         toggleClass : function(className){
7512             if(this.hasClass(className)){
7513                 this.removeClass(className);
7514             }else{
7515                 this.addClass(className);
7516             }
7517             return this;
7518         },
7519
7520         /**
7521          * Checks if the specified CSS class exists on this element's DOM node.
7522          * @param {String} className The CSS class to check for
7523          * @return {Boolean} True if the class exists, else false
7524          */
7525         hasClass : function(className){
7526             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7527         },
7528
7529         /**
7530          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7531          * @param {String} oldClassName The CSS class to replace
7532          * @param {String} newClassName The replacement CSS class
7533          * @return {Roo.Element} this
7534          */
7535         replaceClass : function(oldClassName, newClassName){
7536             this.removeClass(oldClassName);
7537             this.addClass(newClassName);
7538             return this;
7539         },
7540
7541         /**
7542          * Returns an object with properties matching the styles requested.
7543          * For example, el.getStyles('color', 'font-size', 'width') might return
7544          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7545          * @param {String} style1 A style name
7546          * @param {String} style2 A style name
7547          * @param {String} etc.
7548          * @return {Object} The style object
7549          */
7550         getStyles : function(){
7551             var a = arguments, len = a.length, r = {};
7552             for(var i = 0; i < len; i++){
7553                 r[a[i]] = this.getStyle(a[i]);
7554             }
7555             return r;
7556         },
7557
7558         /**
7559          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7560          * @param {String} property The style property whose value is returned.
7561          * @return {String} The current value of the style property for this element.
7562          */
7563         getStyle : function(){
7564             return view && view.getComputedStyle ?
7565                 function(prop){
7566                     var el = this.dom, v, cs, camel;
7567                     if(prop == 'float'){
7568                         prop = "cssFloat";
7569                     }
7570                     if(el.style && (v = el.style[prop])){
7571                         return v;
7572                     }
7573                     if(cs = view.getComputedStyle(el, "")){
7574                         if(!(camel = propCache[prop])){
7575                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7576                         }
7577                         return cs[camel];
7578                     }
7579                     return null;
7580                 } :
7581                 function(prop){
7582                     var el = this.dom, v, cs, camel;
7583                     if(prop == 'opacity'){
7584                         if(typeof el.style.filter == 'string'){
7585                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7586                             if(m){
7587                                 var fv = parseFloat(m[1]);
7588                                 if(!isNaN(fv)){
7589                                     return fv ? fv / 100 : 0;
7590                                 }
7591                             }
7592                         }
7593                         return 1;
7594                     }else if(prop == 'float'){
7595                         prop = "styleFloat";
7596                     }
7597                     if(!(camel = propCache[prop])){
7598                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7599                     }
7600                     if(v = el.style[camel]){
7601                         return v;
7602                     }
7603                     if(cs = el.currentStyle){
7604                         return cs[camel];
7605                     }
7606                     return null;
7607                 };
7608         }(),
7609
7610         /**
7611          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7612          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7613          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7614          * @return {Roo.Element} this
7615          */
7616         setStyle : function(prop, value){
7617             if(typeof prop == "string"){
7618                 
7619                 if (prop == 'float') {
7620                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7621                     return this;
7622                 }
7623                 
7624                 var camel;
7625                 if(!(camel = propCache[prop])){
7626                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7627                 }
7628                 
7629                 if(camel == 'opacity') {
7630                     this.setOpacity(value);
7631                 }else{
7632                     this.dom.style[camel] = value;
7633                 }
7634             }else{
7635                 for(var style in prop){
7636                     if(typeof prop[style] != "function"){
7637                        this.setStyle(style, prop[style]);
7638                     }
7639                 }
7640             }
7641             return this;
7642         },
7643
7644         /**
7645          * More flexible version of {@link #setStyle} for setting style properties.
7646          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7647          * a function which returns such a specification.
7648          * @return {Roo.Element} this
7649          */
7650         applyStyles : function(style){
7651             Roo.DomHelper.applyStyles(this.dom, style);
7652             return this;
7653         },
7654
7655         /**
7656           * 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).
7657           * @return {Number} The X position of the element
7658           */
7659         getX : function(){
7660             return D.getX(this.dom);
7661         },
7662
7663         /**
7664           * 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).
7665           * @return {Number} The Y position of the element
7666           */
7667         getY : function(){
7668             return D.getY(this.dom);
7669         },
7670
7671         /**
7672           * 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).
7673           * @return {Array} The XY position of the element
7674           */
7675         getXY : function(){
7676             return D.getXY(this.dom);
7677         },
7678
7679         /**
7680          * 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).
7681          * @param {Number} The X position of the element
7682          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7683          * @return {Roo.Element} this
7684          */
7685         setX : function(x, animate){
7686             if(!animate || !A){
7687                 D.setX(this.dom, x);
7688             }else{
7689                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7690             }
7691             return this;
7692         },
7693
7694         /**
7695          * 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).
7696          * @param {Number} The Y position of the element
7697          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7698          * @return {Roo.Element} this
7699          */
7700         setY : function(y, animate){
7701             if(!animate || !A){
7702                 D.setY(this.dom, y);
7703             }else{
7704                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7705             }
7706             return this;
7707         },
7708
7709         /**
7710          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7711          * @param {String} left The left CSS property value
7712          * @return {Roo.Element} this
7713          */
7714         setLeft : function(left){
7715             this.setStyle("left", this.addUnits(left));
7716             return this;
7717         },
7718
7719         /**
7720          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7721          * @param {String} top The top CSS property value
7722          * @return {Roo.Element} this
7723          */
7724         setTop : function(top){
7725             this.setStyle("top", this.addUnits(top));
7726             return this;
7727         },
7728
7729         /**
7730          * Sets the element's CSS right style.
7731          * @param {String} right The right CSS property value
7732          * @return {Roo.Element} this
7733          */
7734         setRight : function(right){
7735             this.setStyle("right", this.addUnits(right));
7736             return this;
7737         },
7738
7739         /**
7740          * Sets the element's CSS bottom style.
7741          * @param {String} bottom The bottom CSS property value
7742          * @return {Roo.Element} this
7743          */
7744         setBottom : function(bottom){
7745             this.setStyle("bottom", this.addUnits(bottom));
7746             return this;
7747         },
7748
7749         /**
7750          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7751          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7752          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7753          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7754          * @return {Roo.Element} this
7755          */
7756         setXY : function(pos, animate){
7757             if(!animate || !A){
7758                 D.setXY(this.dom, pos);
7759             }else{
7760                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7761             }
7762             return this;
7763         },
7764
7765         /**
7766          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7767          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7768          * @param {Number} x X value for new position (coordinates are page-based)
7769          * @param {Number} y Y value for new position (coordinates are page-based)
7770          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7771          * @return {Roo.Element} this
7772          */
7773         setLocation : function(x, y, animate){
7774             this.setXY([x, y], this.preanim(arguments, 2));
7775             return this;
7776         },
7777
7778         /**
7779          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7780          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7781          * @param {Number} x X value for new position (coordinates are page-based)
7782          * @param {Number} y Y value for new position (coordinates are page-based)
7783          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7784          * @return {Roo.Element} this
7785          */
7786         moveTo : function(x, y, animate){
7787             this.setXY([x, y], this.preanim(arguments, 2));
7788             return this;
7789         },
7790
7791         /**
7792          * Returns the region of the given element.
7793          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7794          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7795          */
7796         getRegion : function(){
7797             return D.getRegion(this.dom);
7798         },
7799
7800         /**
7801          * Returns the offset height of the element
7802          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7803          * @return {Number} The element's height
7804          */
7805         getHeight : function(contentHeight){
7806             var h = this.dom.offsetHeight || 0;
7807             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7808         },
7809
7810         /**
7811          * Returns the offset width of the element
7812          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7813          * @return {Number} The element's width
7814          */
7815         getWidth : function(contentWidth){
7816             var w = this.dom.offsetWidth || 0;
7817             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7818         },
7819
7820         /**
7821          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7822          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7823          * if a height has not been set using CSS.
7824          * @return {Number}
7825          */
7826         getComputedHeight : function(){
7827             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7828             if(!h){
7829                 h = parseInt(this.getStyle('height'), 10) || 0;
7830                 if(!this.isBorderBox()){
7831                     h += this.getFrameWidth('tb');
7832                 }
7833             }
7834             return h;
7835         },
7836
7837         /**
7838          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7839          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7840          * if a width has not been set using CSS.
7841          * @return {Number}
7842          */
7843         getComputedWidth : function(){
7844             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7845             if(!w){
7846                 w = parseInt(this.getStyle('width'), 10) || 0;
7847                 if(!this.isBorderBox()){
7848                     w += this.getFrameWidth('lr');
7849                 }
7850             }
7851             return w;
7852         },
7853
7854         /**
7855          * Returns the size of the element.
7856          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7857          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7858          */
7859         getSize : function(contentSize){
7860             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7861         },
7862
7863         /**
7864          * Returns the width and height of the viewport.
7865          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7866          */
7867         getViewSize : function(){
7868             var d = this.dom, doc = document, aw = 0, ah = 0;
7869             if(d == doc || d == doc.body){
7870                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7871             }else{
7872                 return {
7873                     width : d.clientWidth,
7874                     height: d.clientHeight
7875                 };
7876             }
7877         },
7878
7879         /**
7880          * Returns the value of the "value" attribute
7881          * @param {Boolean} asNumber true to parse the value as a number
7882          * @return {String/Number}
7883          */
7884         getValue : function(asNumber){
7885             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7886         },
7887
7888         // private
7889         adjustWidth : function(width){
7890             if(typeof width == "number"){
7891                 if(this.autoBoxAdjust && !this.isBorderBox()){
7892                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7893                 }
7894                 if(width < 0){
7895                     width = 0;
7896                 }
7897             }
7898             return width;
7899         },
7900
7901         // private
7902         adjustHeight : function(height){
7903             if(typeof height == "number"){
7904                if(this.autoBoxAdjust && !this.isBorderBox()){
7905                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7906                }
7907                if(height < 0){
7908                    height = 0;
7909                }
7910             }
7911             return height;
7912         },
7913
7914         /**
7915          * Set the width of the element
7916          * @param {Number} width The new width
7917          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7918          * @return {Roo.Element} this
7919          */
7920         setWidth : function(width, animate){
7921             width = this.adjustWidth(width);
7922             if(!animate || !A){
7923                 this.dom.style.width = this.addUnits(width);
7924             }else{
7925                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7926             }
7927             return this;
7928         },
7929
7930         /**
7931          * Set the height of the element
7932          * @param {Number} height The new height
7933          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7934          * @return {Roo.Element} this
7935          */
7936          setHeight : function(height, animate){
7937             height = this.adjustHeight(height);
7938             if(!animate || !A){
7939                 this.dom.style.height = this.addUnits(height);
7940             }else{
7941                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7942             }
7943             return this;
7944         },
7945
7946         /**
7947          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7948          * @param {Number} width The new width
7949          * @param {Number} height The new height
7950          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7951          * @return {Roo.Element} this
7952          */
7953          setSize : function(width, height, animate){
7954             if(typeof width == "object"){ // in case of object from getSize()
7955                 height = width.height; width = width.width;
7956             }
7957             width = this.adjustWidth(width); height = this.adjustHeight(height);
7958             if(!animate || !A){
7959                 this.dom.style.width = this.addUnits(width);
7960                 this.dom.style.height = this.addUnits(height);
7961             }else{
7962                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7963             }
7964             return this;
7965         },
7966
7967         /**
7968          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7969          * @param {Number} x X value for new position (coordinates are page-based)
7970          * @param {Number} y Y value for new position (coordinates are page-based)
7971          * @param {Number} width The new width
7972          * @param {Number} height The new height
7973          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7974          * @return {Roo.Element} this
7975          */
7976         setBounds : function(x, y, width, height, animate){
7977             if(!animate || !A){
7978                 this.setSize(width, height);
7979                 this.setLocation(x, y);
7980             }else{
7981                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7982                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7983                               this.preanim(arguments, 4), 'motion');
7984             }
7985             return this;
7986         },
7987
7988         /**
7989          * 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.
7990          * @param {Roo.lib.Region} region The region to fill
7991          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7992          * @return {Roo.Element} this
7993          */
7994         setRegion : function(region, animate){
7995             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7996             return this;
7997         },
7998
7999         /**
8000          * Appends an event handler
8001          *
8002          * @param {String}   eventName     The type of event to append
8003          * @param {Function} fn        The method the event invokes
8004          * @param {Object} scope       (optional) The scope (this object) of the fn
8005          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8006          */
8007         addListener : function(eventName, fn, scope, options){
8008             if (this.dom) {
8009                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8010             }
8011         },
8012
8013         /**
8014          * Removes an event handler from this element
8015          * @param {String} eventName the type of event to remove
8016          * @param {Function} fn the method the event invokes
8017          * @return {Roo.Element} this
8018          */
8019         removeListener : function(eventName, fn){
8020             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8021             return this;
8022         },
8023
8024         /**
8025          * Removes all previous added listeners from this element
8026          * @return {Roo.Element} this
8027          */
8028         removeAllListeners : function(){
8029             E.purgeElement(this.dom);
8030             return this;
8031         },
8032
8033         relayEvent : function(eventName, observable){
8034             this.on(eventName, function(e){
8035                 observable.fireEvent(eventName, e);
8036             });
8037         },
8038
8039         /**
8040          * Set the opacity of the element
8041          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8042          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8043          * @return {Roo.Element} this
8044          */
8045          setOpacity : function(opacity, animate){
8046             if(!animate || !A){
8047                 var s = this.dom.style;
8048                 if(Roo.isIE){
8049                     s.zoom = 1;
8050                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8051                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8052                 }else{
8053                     s.opacity = opacity;
8054                 }
8055             }else{
8056                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8057             }
8058             return this;
8059         },
8060
8061         /**
8062          * Gets the left X coordinate
8063          * @param {Boolean} local True to get the local css position instead of page coordinate
8064          * @return {Number}
8065          */
8066         getLeft : function(local){
8067             if(!local){
8068                 return this.getX();
8069             }else{
8070                 return parseInt(this.getStyle("left"), 10) || 0;
8071             }
8072         },
8073
8074         /**
8075          * Gets the right X coordinate of the element (element X position + element width)
8076          * @param {Boolean} local True to get the local css position instead of page coordinate
8077          * @return {Number}
8078          */
8079         getRight : function(local){
8080             if(!local){
8081                 return this.getX() + this.getWidth();
8082             }else{
8083                 return (this.getLeft(true) + this.getWidth()) || 0;
8084             }
8085         },
8086
8087         /**
8088          * Gets the top Y coordinate
8089          * @param {Boolean} local True to get the local css position instead of page coordinate
8090          * @return {Number}
8091          */
8092         getTop : function(local) {
8093             if(!local){
8094                 return this.getY();
8095             }else{
8096                 return parseInt(this.getStyle("top"), 10) || 0;
8097             }
8098         },
8099
8100         /**
8101          * Gets the bottom Y coordinate of the element (element Y position + element height)
8102          * @param {Boolean} local True to get the local css position instead of page coordinate
8103          * @return {Number}
8104          */
8105         getBottom : function(local){
8106             if(!local){
8107                 return this.getY() + this.getHeight();
8108             }else{
8109                 return (this.getTop(true) + this.getHeight()) || 0;
8110             }
8111         },
8112
8113         /**
8114         * Initializes positioning on this element. If a desired position is not passed, it will make the
8115         * the element positioned relative IF it is not already positioned.
8116         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8117         * @param {Number} zIndex (optional) The zIndex to apply
8118         * @param {Number} x (optional) Set the page X position
8119         * @param {Number} y (optional) Set the page Y position
8120         */
8121         position : function(pos, zIndex, x, y){
8122             if(!pos){
8123                if(this.getStyle('position') == 'static'){
8124                    this.setStyle('position', 'relative');
8125                }
8126             }else{
8127                 this.setStyle("position", pos);
8128             }
8129             if(zIndex){
8130                 this.setStyle("z-index", zIndex);
8131             }
8132             if(x !== undefined && y !== undefined){
8133                 this.setXY([x, y]);
8134             }else if(x !== undefined){
8135                 this.setX(x);
8136             }else if(y !== undefined){
8137                 this.setY(y);
8138             }
8139         },
8140
8141         /**
8142         * Clear positioning back to the default when the document was loaded
8143         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8144         * @return {Roo.Element} this
8145          */
8146         clearPositioning : function(value){
8147             value = value ||'';
8148             this.setStyle({
8149                 "left": value,
8150                 "right": value,
8151                 "top": value,
8152                 "bottom": value,
8153                 "z-index": "",
8154                 "position" : "static"
8155             });
8156             return this;
8157         },
8158
8159         /**
8160         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8161         * snapshot before performing an update and then restoring the element.
8162         * @return {Object}
8163         */
8164         getPositioning : function(){
8165             var l = this.getStyle("left");
8166             var t = this.getStyle("top");
8167             return {
8168                 "position" : this.getStyle("position"),
8169                 "left" : l,
8170                 "right" : l ? "" : this.getStyle("right"),
8171                 "top" : t,
8172                 "bottom" : t ? "" : this.getStyle("bottom"),
8173                 "z-index" : this.getStyle("z-index")
8174             };
8175         },
8176
8177         /**
8178          * Gets the width of the border(s) for the specified side(s)
8179          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8180          * passing lr would get the border (l)eft width + the border (r)ight width.
8181          * @return {Number} The width of the sides passed added together
8182          */
8183         getBorderWidth : function(side){
8184             return this.addStyles(side, El.borders);
8185         },
8186
8187         /**
8188          * Gets the width of the padding(s) for the specified side(s)
8189          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8190          * passing lr would get the padding (l)eft + the padding (r)ight.
8191          * @return {Number} The padding of the sides passed added together
8192          */
8193         getPadding : function(side){
8194             return this.addStyles(side, El.paddings);
8195         },
8196
8197         /**
8198         * Set positioning with an object returned by getPositioning().
8199         * @param {Object} posCfg
8200         * @return {Roo.Element} this
8201          */
8202         setPositioning : function(pc){
8203             this.applyStyles(pc);
8204             if(pc.right == "auto"){
8205                 this.dom.style.right = "";
8206             }
8207             if(pc.bottom == "auto"){
8208                 this.dom.style.bottom = "";
8209             }
8210             return this;
8211         },
8212
8213         // private
8214         fixDisplay : function(){
8215             if(this.getStyle("display") == "none"){
8216                 this.setStyle("visibility", "hidden");
8217                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8218                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8219                     this.setStyle("display", "block");
8220                 }
8221             }
8222         },
8223
8224         /**
8225          * Quick set left and top adding default units
8226          * @param {String} left The left CSS property value
8227          * @param {String} top The top CSS property value
8228          * @return {Roo.Element} this
8229          */
8230          setLeftTop : function(left, top){
8231             this.dom.style.left = this.addUnits(left);
8232             this.dom.style.top = this.addUnits(top);
8233             return this;
8234         },
8235
8236         /**
8237          * Move this element relative to its current position.
8238          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8239          * @param {Number} distance How far to move the element in pixels
8240          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8241          * @return {Roo.Element} this
8242          */
8243          move : function(direction, distance, animate){
8244             var xy = this.getXY();
8245             direction = direction.toLowerCase();
8246             switch(direction){
8247                 case "l":
8248                 case "left":
8249                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8250                     break;
8251                case "r":
8252                case "right":
8253                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8254                     break;
8255                case "t":
8256                case "top":
8257                case "up":
8258                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8259                     break;
8260                case "b":
8261                case "bottom":
8262                case "down":
8263                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8264                     break;
8265             }
8266             return this;
8267         },
8268
8269         /**
8270          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8271          * @return {Roo.Element} this
8272          */
8273         clip : function(){
8274             if(!this.isClipped){
8275                this.isClipped = true;
8276                this.originalClip = {
8277                    "o": this.getStyle("overflow"),
8278                    "x": this.getStyle("overflow-x"),
8279                    "y": this.getStyle("overflow-y")
8280                };
8281                this.setStyle("overflow", "hidden");
8282                this.setStyle("overflow-x", "hidden");
8283                this.setStyle("overflow-y", "hidden");
8284             }
8285             return this;
8286         },
8287
8288         /**
8289          *  Return clipping (overflow) to original clipping before clip() was called
8290          * @return {Roo.Element} this
8291          */
8292         unclip : function(){
8293             if(this.isClipped){
8294                 this.isClipped = false;
8295                 var o = this.originalClip;
8296                 if(o.o){this.setStyle("overflow", o.o);}
8297                 if(o.x){this.setStyle("overflow-x", o.x);}
8298                 if(o.y){this.setStyle("overflow-y", o.y);}
8299             }
8300             return this;
8301         },
8302
8303
8304         /**
8305          * Gets the x,y coordinates specified by the anchor position on the element.
8306          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8307          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8308          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8309          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8310          * @return {Array} [x, y] An array containing the element's x and y coordinates
8311          */
8312         getAnchorXY : function(anchor, local, s){
8313             //Passing a different size is useful for pre-calculating anchors,
8314             //especially for anchored animations that change the el size.
8315
8316             var w, h, vp = false;
8317             if(!s){
8318                 var d = this.dom;
8319                 if(d == document.body || d == document){
8320                     vp = true;
8321                     w = D.getViewWidth(); h = D.getViewHeight();
8322                 }else{
8323                     w = this.getWidth(); h = this.getHeight();
8324                 }
8325             }else{
8326                 w = s.width;  h = s.height;
8327             }
8328             var x = 0, y = 0, r = Math.round;
8329             switch((anchor || "tl").toLowerCase()){
8330                 case "c":
8331                     x = r(w*.5);
8332                     y = r(h*.5);
8333                 break;
8334                 case "t":
8335                     x = r(w*.5);
8336                     y = 0;
8337                 break;
8338                 case "l":
8339                     x = 0;
8340                     y = r(h*.5);
8341                 break;
8342                 case "r":
8343                     x = w;
8344                     y = r(h*.5);
8345                 break;
8346                 case "b":
8347                     x = r(w*.5);
8348                     y = h;
8349                 break;
8350                 case "tl":
8351                     x = 0;
8352                     y = 0;
8353                 break;
8354                 case "bl":
8355                     x = 0;
8356                     y = h;
8357                 break;
8358                 case "br":
8359                     x = w;
8360                     y = h;
8361                 break;
8362                 case "tr":
8363                     x = w;
8364                     y = 0;
8365                 break;
8366             }
8367             if(local === true){
8368                 return [x, y];
8369             }
8370             if(vp){
8371                 var sc = this.getScroll();
8372                 return [x + sc.left, y + sc.top];
8373             }
8374             //Add the element's offset xy
8375             var o = this.getXY();
8376             return [x+o[0], y+o[1]];
8377         },
8378
8379         /**
8380          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8381          * supported position values.
8382          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8383          * @param {String} position The position to align to.
8384          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8385          * @return {Array} [x, y]
8386          */
8387         getAlignToXY : function(el, p, o){
8388             el = Roo.get(el);
8389             var d = this.dom;
8390             if(!el.dom){
8391                 throw "Element.alignTo with an element that doesn't exist";
8392             }
8393             var c = false; //constrain to viewport
8394             var p1 = "", p2 = "";
8395             o = o || [0,0];
8396
8397             if(!p){
8398                 p = "tl-bl";
8399             }else if(p == "?"){
8400                 p = "tl-bl?";
8401             }else if(p.indexOf("-") == -1){
8402                 p = "tl-" + p;
8403             }
8404             p = p.toLowerCase();
8405             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8406             if(!m){
8407                throw "Element.alignTo with an invalid alignment " + p;
8408             }
8409             p1 = m[1]; p2 = m[2]; c = !!m[3];
8410
8411             //Subtract the aligned el's internal xy from the target's offset xy
8412             //plus custom offset to get the aligned el's new offset xy
8413             var a1 = this.getAnchorXY(p1, true);
8414             var a2 = el.getAnchorXY(p2, false);
8415             var x = a2[0] - a1[0] + o[0];
8416             var y = a2[1] - a1[1] + o[1];
8417             if(c){
8418                 //constrain the aligned el to viewport if necessary
8419                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8420                 // 5px of margin for ie
8421                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8422
8423                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8424                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8425                 //otherwise swap the aligned el to the opposite border of the target.
8426                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8427                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8428                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8429                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8430
8431                var doc = document;
8432                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8433                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8434
8435                if((x+w) > dw + scrollX){
8436                     x = swapX ? r.left-w : dw+scrollX-w;
8437                 }
8438                if(x < scrollX){
8439                    x = swapX ? r.right : scrollX;
8440                }
8441                if((y+h) > dh + scrollY){
8442                     y = swapY ? r.top-h : dh+scrollY-h;
8443                 }
8444                if (y < scrollY){
8445                    y = swapY ? r.bottom : scrollY;
8446                }
8447             }
8448             return [x,y];
8449         },
8450
8451         // private
8452         getConstrainToXY : function(){
8453             var os = {top:0, left:0, bottom:0, right: 0};
8454
8455             return function(el, local, offsets, proposedXY){
8456                 el = Roo.get(el);
8457                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8458
8459                 var vw, vh, vx = 0, vy = 0;
8460                 if(el.dom == document.body || el.dom == document){
8461                     vw = Roo.lib.Dom.getViewWidth();
8462                     vh = Roo.lib.Dom.getViewHeight();
8463                 }else{
8464                     vw = el.dom.clientWidth;
8465                     vh = el.dom.clientHeight;
8466                     if(!local){
8467                         var vxy = el.getXY();
8468                         vx = vxy[0];
8469                         vy = vxy[1];
8470                     }
8471                 }
8472
8473                 var s = el.getScroll();
8474
8475                 vx += offsets.left + s.left;
8476                 vy += offsets.top + s.top;
8477
8478                 vw -= offsets.right;
8479                 vh -= offsets.bottom;
8480
8481                 var vr = vx+vw;
8482                 var vb = vy+vh;
8483
8484                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8485                 var x = xy[0], y = xy[1];
8486                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8487
8488                 // only move it if it needs it
8489                 var moved = false;
8490
8491                 // first validate right/bottom
8492                 if((x + w) > vr){
8493                     x = vr - w;
8494                     moved = true;
8495                 }
8496                 if((y + h) > vb){
8497                     y = vb - h;
8498                     moved = true;
8499                 }
8500                 // then make sure top/left isn't negative
8501                 if(x < vx){
8502                     x = vx;
8503                     moved = true;
8504                 }
8505                 if(y < vy){
8506                     y = vy;
8507                     moved = true;
8508                 }
8509                 return moved ? [x, y] : false;
8510             };
8511         }(),
8512
8513         // private
8514         adjustForConstraints : function(xy, parent, offsets){
8515             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8516         },
8517
8518         /**
8519          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8520          * document it aligns it to the viewport.
8521          * The position parameter is optional, and can be specified in any one of the following formats:
8522          * <ul>
8523          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8524          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8525          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8526          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8527          *   <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
8528          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8529          * </ul>
8530          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8531          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8532          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8533          * that specified in order to enforce the viewport constraints.
8534          * Following are all of the supported anchor positions:
8535     <pre>
8536     Value  Description
8537     -----  -----------------------------
8538     tl     The top left corner (default)
8539     t      The center of the top edge
8540     tr     The top right corner
8541     l      The center of the left edge
8542     c      In the center of the element
8543     r      The center of the right edge
8544     bl     The bottom left corner
8545     b      The center of the bottom edge
8546     br     The bottom right corner
8547     </pre>
8548     Example Usage:
8549     <pre><code>
8550     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8551     el.alignTo("other-el");
8552
8553     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8554     el.alignTo("other-el", "tr?");
8555
8556     // align the bottom right corner of el with the center left edge of other-el
8557     el.alignTo("other-el", "br-l?");
8558
8559     // align the center of el with the bottom left corner of other-el and
8560     // adjust the x position by -6 pixels (and the y position by 0)
8561     el.alignTo("other-el", "c-bl", [-6, 0]);
8562     </code></pre>
8563          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8564          * @param {String} position The position to align to.
8565          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8566          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8567          * @return {Roo.Element} this
8568          */
8569         alignTo : function(element, position, offsets, animate){
8570             var xy = this.getAlignToXY(element, position, offsets);
8571             this.setXY(xy, this.preanim(arguments, 3));
8572             return this;
8573         },
8574
8575         /**
8576          * Anchors an element to another element and realigns it when the window is resized.
8577          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8578          * @param {String} position The position to align to.
8579          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8580          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8581          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8582          * is a number, it is used as the buffer delay (defaults to 50ms).
8583          * @param {Function} callback The function to call after the animation finishes
8584          * @return {Roo.Element} this
8585          */
8586         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8587             var action = function(){
8588                 this.alignTo(el, alignment, offsets, animate);
8589                 Roo.callback(callback, this);
8590             };
8591             Roo.EventManager.onWindowResize(action, this);
8592             var tm = typeof monitorScroll;
8593             if(tm != 'undefined'){
8594                 Roo.EventManager.on(window, 'scroll', action, this,
8595                     {buffer: tm == 'number' ? monitorScroll : 50});
8596             }
8597             action.call(this); // align immediately
8598             return this;
8599         },
8600         /**
8601          * Clears any opacity settings from this element. Required in some cases for IE.
8602          * @return {Roo.Element} this
8603          */
8604         clearOpacity : function(){
8605             if (window.ActiveXObject) {
8606                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8607                     this.dom.style.filter = "";
8608                 }
8609             } else {
8610                 this.dom.style.opacity = "";
8611                 this.dom.style["-moz-opacity"] = "";
8612                 this.dom.style["-khtml-opacity"] = "";
8613             }
8614             return this;
8615         },
8616
8617         /**
8618          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8619          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8620          * @return {Roo.Element} this
8621          */
8622         hide : function(animate){
8623             this.setVisible(false, this.preanim(arguments, 0));
8624             return this;
8625         },
8626
8627         /**
8628         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8629         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8630          * @return {Roo.Element} this
8631          */
8632         show : function(animate){
8633             this.setVisible(true, this.preanim(arguments, 0));
8634             return this;
8635         },
8636
8637         /**
8638          * @private Test if size has a unit, otherwise appends the default
8639          */
8640         addUnits : function(size){
8641             return Roo.Element.addUnits(size, this.defaultUnit);
8642         },
8643
8644         /**
8645          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8646          * @return {Roo.Element} this
8647          */
8648         beginMeasure : function(){
8649             var el = this.dom;
8650             if(el.offsetWidth || el.offsetHeight){
8651                 return this; // offsets work already
8652             }
8653             var changed = [];
8654             var p = this.dom, b = document.body; // start with this element
8655             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8656                 var pe = Roo.get(p);
8657                 if(pe.getStyle('display') == 'none'){
8658                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8659                     p.style.visibility = "hidden";
8660                     p.style.display = "block";
8661                 }
8662                 p = p.parentNode;
8663             }
8664             this._measureChanged = changed;
8665             return this;
8666
8667         },
8668
8669         /**
8670          * Restores displays to before beginMeasure was called
8671          * @return {Roo.Element} this
8672          */
8673         endMeasure : function(){
8674             var changed = this._measureChanged;
8675             if(changed){
8676                 for(var i = 0, len = changed.length; i < len; i++) {
8677                     var r = changed[i];
8678                     r.el.style.visibility = r.visibility;
8679                     r.el.style.display = "none";
8680                 }
8681                 this._measureChanged = null;
8682             }
8683             return this;
8684         },
8685
8686         /**
8687         * Update the innerHTML of this element, optionally searching for and processing scripts
8688         * @param {String} html The new HTML
8689         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8690         * @param {Function} callback For async script loading you can be noticed when the update completes
8691         * @return {Roo.Element} this
8692          */
8693         update : function(html, loadScripts, callback){
8694             if(typeof html == "undefined"){
8695                 html = "";
8696             }
8697             if(loadScripts !== true){
8698                 this.dom.innerHTML = html;
8699                 if(typeof callback == "function"){
8700                     callback();
8701                 }
8702                 return this;
8703             }
8704             var id = Roo.id();
8705             var dom = this.dom;
8706
8707             html += '<span id="' + id + '"></span>';
8708
8709             E.onAvailable(id, function(){
8710                 var hd = document.getElementsByTagName("head")[0];
8711                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8712                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8713                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8714
8715                 var match;
8716                 while(match = re.exec(html)){
8717                     var attrs = match[1];
8718                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8719                     if(srcMatch && srcMatch[2]){
8720                        var s = document.createElement("script");
8721                        s.src = srcMatch[2];
8722                        var typeMatch = attrs.match(typeRe);
8723                        if(typeMatch && typeMatch[2]){
8724                            s.type = typeMatch[2];
8725                        }
8726                        hd.appendChild(s);
8727                     }else if(match[2] && match[2].length > 0){
8728                         if(window.execScript) {
8729                            window.execScript(match[2]);
8730                         } else {
8731                             /**
8732                              * eval:var:id
8733                              * eval:var:dom
8734                              * eval:var:html
8735                              * 
8736                              */
8737                            window.eval(match[2]);
8738                         }
8739                     }
8740                 }
8741                 var el = document.getElementById(id);
8742                 if(el){el.parentNode.removeChild(el);}
8743                 if(typeof callback == "function"){
8744                     callback();
8745                 }
8746             });
8747             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8748             return this;
8749         },
8750
8751         /**
8752          * Direct access to the UpdateManager update() method (takes the same parameters).
8753          * @param {String/Function} url The url for this request or a function to call to get the url
8754          * @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}
8755          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8756          * @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.
8757          * @return {Roo.Element} this
8758          */
8759         load : function(){
8760             var um = this.getUpdateManager();
8761             um.update.apply(um, arguments);
8762             return this;
8763         },
8764
8765         /**
8766         * Gets this element's UpdateManager
8767         * @return {Roo.UpdateManager} The UpdateManager
8768         */
8769         getUpdateManager : function(){
8770             if(!this.updateManager){
8771                 this.updateManager = new Roo.UpdateManager(this);
8772             }
8773             return this.updateManager;
8774         },
8775
8776         /**
8777          * Disables text selection for this element (normalized across browsers)
8778          * @return {Roo.Element} this
8779          */
8780         unselectable : function(){
8781             this.dom.unselectable = "on";
8782             this.swallowEvent("selectstart", true);
8783             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8784             this.addClass("x-unselectable");
8785             return this;
8786         },
8787
8788         /**
8789         * Calculates the x, y to center this element on the screen
8790         * @return {Array} The x, y values [x, y]
8791         */
8792         getCenterXY : function(){
8793             return this.getAlignToXY(document, 'c-c');
8794         },
8795
8796         /**
8797         * Centers the Element in either the viewport, or another Element.
8798         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8799         */
8800         center : function(centerIn){
8801             this.alignTo(centerIn || document, 'c-c');
8802             return this;
8803         },
8804
8805         /**
8806          * Tests various css rules/browsers to determine if this element uses a border box
8807          * @return {Boolean}
8808          */
8809         isBorderBox : function(){
8810             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8811         },
8812
8813         /**
8814          * Return a box {x, y, width, height} that can be used to set another elements
8815          * size/location to match this element.
8816          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8817          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8818          * @return {Object} box An object in the format {x, y, width, height}
8819          */
8820         getBox : function(contentBox, local){
8821             var xy;
8822             if(!local){
8823                 xy = this.getXY();
8824             }else{
8825                 var left = parseInt(this.getStyle("left"), 10) || 0;
8826                 var top = parseInt(this.getStyle("top"), 10) || 0;
8827                 xy = [left, top];
8828             }
8829             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8830             if(!contentBox){
8831                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8832             }else{
8833                 var l = this.getBorderWidth("l")+this.getPadding("l");
8834                 var r = this.getBorderWidth("r")+this.getPadding("r");
8835                 var t = this.getBorderWidth("t")+this.getPadding("t");
8836                 var b = this.getBorderWidth("b")+this.getPadding("b");
8837                 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)};
8838             }
8839             bx.right = bx.x + bx.width;
8840             bx.bottom = bx.y + bx.height;
8841             return bx;
8842         },
8843
8844         /**
8845          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8846          for more information about the sides.
8847          * @param {String} sides
8848          * @return {Number}
8849          */
8850         getFrameWidth : function(sides, onlyContentBox){
8851             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8852         },
8853
8854         /**
8855          * 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.
8856          * @param {Object} box The box to fill {x, y, width, height}
8857          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8858          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8859          * @return {Roo.Element} this
8860          */
8861         setBox : function(box, adjust, animate){
8862             var w = box.width, h = box.height;
8863             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8864                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8865                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8866             }
8867             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8868             return this;
8869         },
8870
8871         /**
8872          * Forces the browser to repaint this element
8873          * @return {Roo.Element} this
8874          */
8875          repaint : function(){
8876             var dom = this.dom;
8877             this.addClass("x-repaint");
8878             setTimeout(function(){
8879                 Roo.get(dom).removeClass("x-repaint");
8880             }, 1);
8881             return this;
8882         },
8883
8884         /**
8885          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8886          * then it returns the calculated width of the sides (see getPadding)
8887          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8888          * @return {Object/Number}
8889          */
8890         getMargins : function(side){
8891             if(!side){
8892                 return {
8893                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8894                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8895                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8896                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8897                 };
8898             }else{
8899                 return this.addStyles(side, El.margins);
8900              }
8901         },
8902
8903         // private
8904         addStyles : function(sides, styles){
8905             var val = 0, v, w;
8906             for(var i = 0, len = sides.length; i < len; i++){
8907                 v = this.getStyle(styles[sides.charAt(i)]);
8908                 if(v){
8909                      w = parseInt(v, 10);
8910                      if(w){ val += w; }
8911                 }
8912             }
8913             return val;
8914         },
8915
8916         /**
8917          * Creates a proxy element of this element
8918          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8919          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8920          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8921          * @return {Roo.Element} The new proxy element
8922          */
8923         createProxy : function(config, renderTo, matchBox){
8924             if(renderTo){
8925                 renderTo = Roo.getDom(renderTo);
8926             }else{
8927                 renderTo = document.body;
8928             }
8929             config = typeof config == "object" ?
8930                 config : {tag : "div", cls: config};
8931             var proxy = Roo.DomHelper.append(renderTo, config, true);
8932             if(matchBox){
8933                proxy.setBox(this.getBox());
8934             }
8935             return proxy;
8936         },
8937
8938         /**
8939          * Puts a mask over this element to disable user interaction. Requires core.css.
8940          * This method can only be applied to elements which accept child nodes.
8941          * @param {String} msg (optional) A message to display in the mask
8942          * @param {String} msgCls (optional) A css class to apply to the msg element
8943          * @return {Element} The mask  element
8944          */
8945         mask : function(msg, msgCls)
8946         {
8947             if(this.getStyle("position") == "static"){
8948                 this.setStyle("position", "relative");
8949             }
8950             if(!this._mask){
8951                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8952             }
8953             this.addClass("x-masked");
8954             this._mask.setDisplayed(true);
8955             
8956             // we wander
8957             var z = 0;
8958             var dom = this.dom
8959             while (dom && dom.style) {
8960                 if (!isNaN(parseInt(dom.style.zIndex))) {
8961                     z = Math.max(z, parseInt(dom.style.zIndex));
8962                 }
8963                 dom = dom.parentNode;
8964             }
8965             // if we are masking the body - then it hides everything..
8966             if (this.dom == document.body) {
8967                 z = 1000000;
8968                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8969                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8970             }
8971            
8972             if(typeof msg == 'string'){
8973                 if(!this._maskMsg){
8974                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8975                 }
8976                 var mm = this._maskMsg;
8977                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8978                 mm.dom.firstChild.innerHTML = msg;
8979                 mm.setDisplayed(true);
8980                 mm.center(this);
8981                 mm.setStyle('z-index', z + 102);
8982             }
8983             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8984                 this._mask.setHeight(this.getHeight());
8985             }
8986             this._mask.setStyle('z-index', z + 100);
8987             
8988             return this._mask;
8989         },
8990
8991         /**
8992          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8993          * it is cached for reuse.
8994          */
8995         unmask : function(removeEl){
8996             if(this._mask){
8997                 if(removeEl === true){
8998                     this._mask.remove();
8999                     delete this._mask;
9000                     if(this._maskMsg){
9001                         this._maskMsg.remove();
9002                         delete this._maskMsg;
9003                     }
9004                 }else{
9005                     this._mask.setDisplayed(false);
9006                     if(this._maskMsg){
9007                         this._maskMsg.setDisplayed(false);
9008                     }
9009                 }
9010             }
9011             this.removeClass("x-masked");
9012         },
9013
9014         /**
9015          * Returns true if this element is masked
9016          * @return {Boolean}
9017          */
9018         isMasked : function(){
9019             return this._mask && this._mask.isVisible();
9020         },
9021
9022         /**
9023          * Creates an iframe shim for this element to keep selects and other windowed objects from
9024          * showing through.
9025          * @return {Roo.Element} The new shim element
9026          */
9027         createShim : function(){
9028             var el = document.createElement('iframe');
9029             el.frameBorder = 'no';
9030             el.className = 'roo-shim';
9031             if(Roo.isIE && Roo.isSecure){
9032                 el.src = Roo.SSL_SECURE_URL;
9033             }
9034             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9035             shim.autoBoxAdjust = false;
9036             return shim;
9037         },
9038
9039         /**
9040          * Removes this element from the DOM and deletes it from the cache
9041          */
9042         remove : function(){
9043             if(this.dom.parentNode){
9044                 this.dom.parentNode.removeChild(this.dom);
9045             }
9046             delete El.cache[this.dom.id];
9047         },
9048
9049         /**
9050          * Sets up event handlers to add and remove a css class when the mouse is over this element
9051          * @param {String} className
9052          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9053          * mouseout events for children elements
9054          * @return {Roo.Element} this
9055          */
9056         addClassOnOver : function(className, preventFlicker){
9057             this.on("mouseover", function(){
9058                 Roo.fly(this, '_internal').addClass(className);
9059             }, this.dom);
9060             var removeFn = function(e){
9061                 if(preventFlicker !== true || !e.within(this, true)){
9062                     Roo.fly(this, '_internal').removeClass(className);
9063                 }
9064             };
9065             this.on("mouseout", removeFn, this.dom);
9066             return this;
9067         },
9068
9069         /**
9070          * Sets up event handlers to add and remove a css class when this element has the focus
9071          * @param {String} className
9072          * @return {Roo.Element} this
9073          */
9074         addClassOnFocus : function(className){
9075             this.on("focus", function(){
9076                 Roo.fly(this, '_internal').addClass(className);
9077             }, this.dom);
9078             this.on("blur", function(){
9079                 Roo.fly(this, '_internal').removeClass(className);
9080             }, this.dom);
9081             return this;
9082         },
9083         /**
9084          * 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)
9085          * @param {String} className
9086          * @return {Roo.Element} this
9087          */
9088         addClassOnClick : function(className){
9089             var dom = this.dom;
9090             this.on("mousedown", function(){
9091                 Roo.fly(dom, '_internal').addClass(className);
9092                 var d = Roo.get(document);
9093                 var fn = function(){
9094                     Roo.fly(dom, '_internal').removeClass(className);
9095                     d.removeListener("mouseup", fn);
9096                 };
9097                 d.on("mouseup", fn);
9098             });
9099             return this;
9100         },
9101
9102         /**
9103          * Stops the specified event from bubbling and optionally prevents the default action
9104          * @param {String} eventName
9105          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9106          * @return {Roo.Element} this
9107          */
9108         swallowEvent : function(eventName, preventDefault){
9109             var fn = function(e){
9110                 e.stopPropagation();
9111                 if(preventDefault){
9112                     e.preventDefault();
9113                 }
9114             };
9115             if(eventName instanceof Array){
9116                 for(var i = 0, len = eventName.length; i < len; i++){
9117                      this.on(eventName[i], fn);
9118                 }
9119                 return this;
9120             }
9121             this.on(eventName, fn);
9122             return this;
9123         },
9124
9125         /**
9126          * @private
9127          */
9128       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9129
9130         /**
9131          * Sizes this element to its parent element's dimensions performing
9132          * neccessary box adjustments.
9133          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9134          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9135          * @return {Roo.Element} this
9136          */
9137         fitToParent : function(monitorResize, targetParent) {
9138           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9139           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9140           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9141             return;
9142           }
9143           var p = Roo.get(targetParent || this.dom.parentNode);
9144           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9145           if (monitorResize === true) {
9146             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9147             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9148           }
9149           return this;
9150         },
9151
9152         /**
9153          * Gets the next sibling, skipping text nodes
9154          * @return {HTMLElement} The next sibling or null
9155          */
9156         getNextSibling : function(){
9157             var n = this.dom.nextSibling;
9158             while(n && n.nodeType != 1){
9159                 n = n.nextSibling;
9160             }
9161             return n;
9162         },
9163
9164         /**
9165          * Gets the previous sibling, skipping text nodes
9166          * @return {HTMLElement} The previous sibling or null
9167          */
9168         getPrevSibling : function(){
9169             var n = this.dom.previousSibling;
9170             while(n && n.nodeType != 1){
9171                 n = n.previousSibling;
9172             }
9173             return n;
9174         },
9175
9176
9177         /**
9178          * Appends the passed element(s) to this element
9179          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9180          * @return {Roo.Element} this
9181          */
9182         appendChild: function(el){
9183             el = Roo.get(el);
9184             el.appendTo(this);
9185             return this;
9186         },
9187
9188         /**
9189          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9190          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9191          * automatically generated with the specified attributes.
9192          * @param {HTMLElement} insertBefore (optional) a child element of this element
9193          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9194          * @return {Roo.Element} The new child element
9195          */
9196         createChild: function(config, insertBefore, returnDom){
9197             config = config || {tag:'div'};
9198             if(insertBefore){
9199                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9200             }
9201             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9202         },
9203
9204         /**
9205          * Appends this element to the passed element
9206          * @param {String/HTMLElement/Element} el The new parent element
9207          * @return {Roo.Element} this
9208          */
9209         appendTo: function(el){
9210             el = Roo.getDom(el);
9211             el.appendChild(this.dom);
9212             return this;
9213         },
9214
9215         /**
9216          * Inserts this element before the passed element in the DOM
9217          * @param {String/HTMLElement/Element} el The element to insert before
9218          * @return {Roo.Element} this
9219          */
9220         insertBefore: function(el){
9221             el = Roo.getDom(el);
9222             el.parentNode.insertBefore(this.dom, el);
9223             return this;
9224         },
9225
9226         /**
9227          * Inserts this element after the passed element in the DOM
9228          * @param {String/HTMLElement/Element} el The element to insert after
9229          * @return {Roo.Element} this
9230          */
9231         insertAfter: function(el){
9232             el = Roo.getDom(el);
9233             el.parentNode.insertBefore(this.dom, el.nextSibling);
9234             return this;
9235         },
9236
9237         /**
9238          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9239          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9240          * @return {Roo.Element} The new child
9241          */
9242         insertFirst: function(el, returnDom){
9243             el = el || {};
9244             if(typeof el == 'object' && !el.nodeType){ // dh config
9245                 return this.createChild(el, this.dom.firstChild, returnDom);
9246             }else{
9247                 el = Roo.getDom(el);
9248                 this.dom.insertBefore(el, this.dom.firstChild);
9249                 return !returnDom ? Roo.get(el) : el;
9250             }
9251         },
9252
9253         /**
9254          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9255          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9256          * @param {String} where (optional) 'before' or 'after' defaults to before
9257          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9258          * @return {Roo.Element} the inserted Element
9259          */
9260         insertSibling: function(el, where, returnDom){
9261             where = where ? where.toLowerCase() : 'before';
9262             el = el || {};
9263             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9264
9265             if(typeof el == 'object' && !el.nodeType){ // dh config
9266                 if(where == 'after' && !this.dom.nextSibling){
9267                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9268                 }else{
9269                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9270                 }
9271
9272             }else{
9273                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9274                             where == 'before' ? this.dom : this.dom.nextSibling);
9275                 if(!returnDom){
9276                     rt = Roo.get(rt);
9277                 }
9278             }
9279             return rt;
9280         },
9281
9282         /**
9283          * Creates and wraps this element with another element
9284          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9285          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9286          * @return {HTMLElement/Element} The newly created wrapper element
9287          */
9288         wrap: function(config, returnDom){
9289             if(!config){
9290                 config = {tag: "div"};
9291             }
9292             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9293             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9294             return newEl;
9295         },
9296
9297         /**
9298          * Replaces the passed element with this element
9299          * @param {String/HTMLElement/Element} el The element to replace
9300          * @return {Roo.Element} this
9301          */
9302         replace: function(el){
9303             el = Roo.get(el);
9304             this.insertBefore(el);
9305             el.remove();
9306             return this;
9307         },
9308
9309         /**
9310          * Inserts an html fragment into this element
9311          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9312          * @param {String} html The HTML fragment
9313          * @param {Boolean} returnEl True to return an Roo.Element
9314          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9315          */
9316         insertHtml : function(where, html, returnEl){
9317             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9318             return returnEl ? Roo.get(el) : el;
9319         },
9320
9321         /**
9322          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9323          * @param {Object} o The object with the attributes
9324          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9325          * @return {Roo.Element} this
9326          */
9327         set : function(o, useSet){
9328             var el = this.dom;
9329             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9330             for(var attr in o){
9331                 if(attr == "style" || typeof o[attr] == "function") continue;
9332                 if(attr=="cls"){
9333                     el.className = o["cls"];
9334                 }else{
9335                     if(useSet) el.setAttribute(attr, o[attr]);
9336                     else el[attr] = o[attr];
9337                 }
9338             }
9339             if(o.style){
9340                 Roo.DomHelper.applyStyles(el, o.style);
9341             }
9342             return this;
9343         },
9344
9345         /**
9346          * Convenience method for constructing a KeyMap
9347          * @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:
9348          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9349          * @param {Function} fn The function to call
9350          * @param {Object} scope (optional) The scope of the function
9351          * @return {Roo.KeyMap} The KeyMap created
9352          */
9353         addKeyListener : function(key, fn, scope){
9354             var config;
9355             if(typeof key != "object" || key instanceof Array){
9356                 config = {
9357                     key: key,
9358                     fn: fn,
9359                     scope: scope
9360                 };
9361             }else{
9362                 config = {
9363                     key : key.key,
9364                     shift : key.shift,
9365                     ctrl : key.ctrl,
9366                     alt : key.alt,
9367                     fn: fn,
9368                     scope: scope
9369                 };
9370             }
9371             return new Roo.KeyMap(this, config);
9372         },
9373
9374         /**
9375          * Creates a KeyMap for this element
9376          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9377          * @return {Roo.KeyMap} The KeyMap created
9378          */
9379         addKeyMap : function(config){
9380             return new Roo.KeyMap(this, config);
9381         },
9382
9383         /**
9384          * Returns true if this element is scrollable.
9385          * @return {Boolean}
9386          */
9387          isScrollable : function(){
9388             var dom = this.dom;
9389             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9390         },
9391
9392         /**
9393          * 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().
9394          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9395          * @param {Number} value The new scroll value
9396          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9397          * @return {Element} this
9398          */
9399
9400         scrollTo : function(side, value, animate){
9401             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9402             if(!animate || !A){
9403                 this.dom[prop] = value;
9404             }else{
9405                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9406                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9407             }
9408             return this;
9409         },
9410
9411         /**
9412          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9413          * within this element's scrollable range.
9414          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9415          * @param {Number} distance How far to scroll the element in pixels
9416          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9417          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9418          * was scrolled as far as it could go.
9419          */
9420          scroll : function(direction, distance, animate){
9421              if(!this.isScrollable()){
9422                  return;
9423              }
9424              var el = this.dom;
9425              var l = el.scrollLeft, t = el.scrollTop;
9426              var w = el.scrollWidth, h = el.scrollHeight;
9427              var cw = el.clientWidth, ch = el.clientHeight;
9428              direction = direction.toLowerCase();
9429              var scrolled = false;
9430              var a = this.preanim(arguments, 2);
9431              switch(direction){
9432                  case "l":
9433                  case "left":
9434                      if(w - l > cw){
9435                          var v = Math.min(l + distance, w-cw);
9436                          this.scrollTo("left", v, a);
9437                          scrolled = true;
9438                      }
9439                      break;
9440                 case "r":
9441                 case "right":
9442                      if(l > 0){
9443                          var v = Math.max(l - distance, 0);
9444                          this.scrollTo("left", v, a);
9445                          scrolled = true;
9446                      }
9447                      break;
9448                 case "t":
9449                 case "top":
9450                 case "up":
9451                      if(t > 0){
9452                          var v = Math.max(t - distance, 0);
9453                          this.scrollTo("top", v, a);
9454                          scrolled = true;
9455                      }
9456                      break;
9457                 case "b":
9458                 case "bottom":
9459                 case "down":
9460                      if(h - t > ch){
9461                          var v = Math.min(t + distance, h-ch);
9462                          this.scrollTo("top", v, a);
9463                          scrolled = true;
9464                      }
9465                      break;
9466              }
9467              return scrolled;
9468         },
9469
9470         /**
9471          * Translates the passed page coordinates into left/top css values for this element
9472          * @param {Number/Array} x The page x or an array containing [x, y]
9473          * @param {Number} y The page y
9474          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9475          */
9476         translatePoints : function(x, y){
9477             if(typeof x == 'object' || x instanceof Array){
9478                 y = x[1]; x = x[0];
9479             }
9480             var p = this.getStyle('position');
9481             var o = this.getXY();
9482
9483             var l = parseInt(this.getStyle('left'), 10);
9484             var t = parseInt(this.getStyle('top'), 10);
9485
9486             if(isNaN(l)){
9487                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9488             }
9489             if(isNaN(t)){
9490                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9491             }
9492
9493             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9494         },
9495
9496         /**
9497          * Returns the current scroll position of the element.
9498          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9499          */
9500         getScroll : function(){
9501             var d = this.dom, doc = document;
9502             if(d == doc || d == doc.body){
9503                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9504                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9505                 return {left: l, top: t};
9506             }else{
9507                 return {left: d.scrollLeft, top: d.scrollTop};
9508             }
9509         },
9510
9511         /**
9512          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9513          * are convert to standard 6 digit hex color.
9514          * @param {String} attr The css attribute
9515          * @param {String} defaultValue The default value to use when a valid color isn't found
9516          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9517          * YUI color anims.
9518          */
9519         getColor : function(attr, defaultValue, prefix){
9520             var v = this.getStyle(attr);
9521             if(!v || v == "transparent" || v == "inherit") {
9522                 return defaultValue;
9523             }
9524             var color = typeof prefix == "undefined" ? "#" : prefix;
9525             if(v.substr(0, 4) == "rgb("){
9526                 var rvs = v.slice(4, v.length -1).split(",");
9527                 for(var i = 0; i < 3; i++){
9528                     var h = parseInt(rvs[i]).toString(16);
9529                     if(h < 16){
9530                         h = "0" + h;
9531                     }
9532                     color += h;
9533                 }
9534             } else {
9535                 if(v.substr(0, 1) == "#"){
9536                     if(v.length == 4) {
9537                         for(var i = 1; i < 4; i++){
9538                             var c = v.charAt(i);
9539                             color +=  c + c;
9540                         }
9541                     }else if(v.length == 7){
9542                         color += v.substr(1);
9543                     }
9544                 }
9545             }
9546             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9547         },
9548
9549         /**
9550          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9551          * gradient background, rounded corners and a 4-way shadow.
9552          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9553          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9554          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9555          * @return {Roo.Element} this
9556          */
9557         boxWrap : function(cls){
9558             cls = cls || 'x-box';
9559             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9560             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9561             return el;
9562         },
9563
9564         /**
9565          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9566          * @param {String} namespace The namespace in which to look for the attribute
9567          * @param {String} name The attribute name
9568          * @return {String} The attribute value
9569          */
9570         getAttributeNS : Roo.isIE ? function(ns, name){
9571             var d = this.dom;
9572             var type = typeof d[ns+":"+name];
9573             if(type != 'undefined' && type != 'unknown'){
9574                 return d[ns+":"+name];
9575             }
9576             return d[name];
9577         } : function(ns, name){
9578             var d = this.dom;
9579             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9580         },
9581         
9582         
9583         /**
9584          * Sets or Returns the value the dom attribute value
9585          * @param {String} name The attribute name
9586          * @param {String} value (optional) The value to set the attribute to
9587          * @return {String} The attribute value
9588          */
9589         attr : function(name){
9590             if (arguments.length > 1) {
9591                 this.dom.setAttribute(name, arguments[1]);
9592                 return arguments[1];
9593             }
9594             if (!this.dom.hasAttribute(name)) {
9595                 return undefined;
9596             }
9597             return this.dom.getAttribute(name);
9598         }
9599         
9600         
9601         
9602     };
9603
9604     var ep = El.prototype;
9605
9606     /**
9607      * Appends an event handler (Shorthand for addListener)
9608      * @param {String}   eventName     The type of event to append
9609      * @param {Function} fn        The method the event invokes
9610      * @param {Object} scope       (optional) The scope (this object) of the fn
9611      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9612      * @method
9613      */
9614     ep.on = ep.addListener;
9615         // backwards compat
9616     ep.mon = ep.addListener;
9617
9618     /**
9619      * Removes an event handler from this element (shorthand for removeListener)
9620      * @param {String} eventName the type of event to remove
9621      * @param {Function} fn the method the event invokes
9622      * @return {Roo.Element} this
9623      * @method
9624      */
9625     ep.un = ep.removeListener;
9626
9627     /**
9628      * true to automatically adjust width and height settings for box-model issues (default to true)
9629      */
9630     ep.autoBoxAdjust = true;
9631
9632     // private
9633     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9634
9635     // private
9636     El.addUnits = function(v, defaultUnit){
9637         if(v === "" || v == "auto"){
9638             return v;
9639         }
9640         if(v === undefined){
9641             return '';
9642         }
9643         if(typeof v == "number" || !El.unitPattern.test(v)){
9644             return v + (defaultUnit || 'px');
9645         }
9646         return v;
9647     };
9648
9649     // special markup used throughout Roo when box wrapping elements
9650     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>';
9651     /**
9652      * Visibility mode constant - Use visibility to hide element
9653      * @static
9654      * @type Number
9655      */
9656     El.VISIBILITY = 1;
9657     /**
9658      * Visibility mode constant - Use display to hide element
9659      * @static
9660      * @type Number
9661      */
9662     El.DISPLAY = 2;
9663
9664     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9665     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9666     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9667
9668
9669
9670     /**
9671      * @private
9672      */
9673     El.cache = {};
9674
9675     var docEl;
9676
9677     /**
9678      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9679      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9680      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9681      * @return {Element} The Element object
9682      * @static
9683      */
9684     El.get = function(el){
9685         var ex, elm, id;
9686         if(!el){ return null; }
9687         if(typeof el == "string"){ // element id
9688             if(!(elm = document.getElementById(el))){
9689                 return null;
9690             }
9691             if(ex = El.cache[el]){
9692                 ex.dom = elm;
9693             }else{
9694                 ex = El.cache[el] = new El(elm);
9695             }
9696             return ex;
9697         }else if(el.tagName){ // dom element
9698             if(!(id = el.id)){
9699                 id = Roo.id(el);
9700             }
9701             if(ex = El.cache[id]){
9702                 ex.dom = el;
9703             }else{
9704                 ex = El.cache[id] = new El(el);
9705             }
9706             return ex;
9707         }else if(el instanceof El){
9708             if(el != docEl){
9709                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9710                                                               // catch case where it hasn't been appended
9711                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9712             }
9713             return el;
9714         }else if(el.isComposite){
9715             return el;
9716         }else if(el instanceof Array){
9717             return El.select(el);
9718         }else if(el == document){
9719             // create a bogus element object representing the document object
9720             if(!docEl){
9721                 var f = function(){};
9722                 f.prototype = El.prototype;
9723                 docEl = new f();
9724                 docEl.dom = document;
9725             }
9726             return docEl;
9727         }
9728         return null;
9729     };
9730
9731     // private
9732     El.uncache = function(el){
9733         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9734             if(a[i]){
9735                 delete El.cache[a[i].id || a[i]];
9736             }
9737         }
9738     };
9739
9740     // private
9741     // Garbage collection - uncache elements/purge listeners on orphaned elements
9742     // so we don't hold a reference and cause the browser to retain them
9743     El.garbageCollect = function(){
9744         if(!Roo.enableGarbageCollector){
9745             clearInterval(El.collectorThread);
9746             return;
9747         }
9748         for(var eid in El.cache){
9749             var el = El.cache[eid], d = el.dom;
9750             // -------------------------------------------------------
9751             // Determining what is garbage:
9752             // -------------------------------------------------------
9753             // !d
9754             // dom node is null, definitely garbage
9755             // -------------------------------------------------------
9756             // !d.parentNode
9757             // no parentNode == direct orphan, definitely garbage
9758             // -------------------------------------------------------
9759             // !d.offsetParent && !document.getElementById(eid)
9760             // display none elements have no offsetParent so we will
9761             // also try to look it up by it's id. However, check
9762             // offsetParent first so we don't do unneeded lookups.
9763             // This enables collection of elements that are not orphans
9764             // directly, but somewhere up the line they have an orphan
9765             // parent.
9766             // -------------------------------------------------------
9767             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9768                 delete El.cache[eid];
9769                 if(d && Roo.enableListenerCollection){
9770                     E.purgeElement(d);
9771                 }
9772             }
9773         }
9774     }
9775     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9776
9777
9778     // dom is optional
9779     El.Flyweight = function(dom){
9780         this.dom = dom;
9781     };
9782     El.Flyweight.prototype = El.prototype;
9783
9784     El._flyweights = {};
9785     /**
9786      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9787      * the dom node can be overwritten by other code.
9788      * @param {String/HTMLElement} el The dom node or id
9789      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9790      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9791      * @static
9792      * @return {Element} The shared Element object
9793      */
9794     El.fly = function(el, named){
9795         named = named || '_global';
9796         el = Roo.getDom(el);
9797         if(!el){
9798             return null;
9799         }
9800         if(!El._flyweights[named]){
9801             El._flyweights[named] = new El.Flyweight();
9802         }
9803         El._flyweights[named].dom = el;
9804         return El._flyweights[named];
9805     };
9806
9807     /**
9808      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9809      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9810      * Shorthand of {@link Roo.Element#get}
9811      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9812      * @return {Element} The Element object
9813      * @member Roo
9814      * @method get
9815      */
9816     Roo.get = El.get;
9817     /**
9818      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9819      * the dom node can be overwritten by other code.
9820      * Shorthand of {@link Roo.Element#fly}
9821      * @param {String/HTMLElement} el The dom node or id
9822      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9823      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9824      * @static
9825      * @return {Element} The shared Element object
9826      * @member Roo
9827      * @method fly
9828      */
9829     Roo.fly = El.fly;
9830
9831     // speedy lookup for elements never to box adjust
9832     var noBoxAdjust = Roo.isStrict ? {
9833         select:1
9834     } : {
9835         input:1, select:1, textarea:1
9836     };
9837     if(Roo.isIE || Roo.isGecko){
9838         noBoxAdjust['button'] = 1;
9839     }
9840
9841
9842     Roo.EventManager.on(window, 'unload', function(){
9843         delete El.cache;
9844         delete El._flyweights;
9845     });
9846 })();
9847
9848
9849
9850
9851 if(Roo.DomQuery){
9852     Roo.Element.selectorFunction = Roo.DomQuery.select;
9853 }
9854
9855 Roo.Element.select = function(selector, unique, root){
9856     var els;
9857     if(typeof selector == "string"){
9858         els = Roo.Element.selectorFunction(selector, root);
9859     }else if(selector.length !== undefined){
9860         els = selector;
9861     }else{
9862         throw "Invalid selector";
9863     }
9864     if(unique === true){
9865         return new Roo.CompositeElement(els);
9866     }else{
9867         return new Roo.CompositeElementLite(els);
9868     }
9869 };
9870 /**
9871  * Selects elements based on the passed CSS selector to enable working on them as 1.
9872  * @param {String/Array} selector The CSS selector or an array of elements
9873  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9874  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9875  * @return {CompositeElementLite/CompositeElement}
9876  * @member Roo
9877  * @method select
9878  */
9879 Roo.select = Roo.Element.select;
9880
9881
9882
9883
9884
9885
9886
9887
9888
9889
9890
9891
9892
9893
9894 /*
9895  * Based on:
9896  * Ext JS Library 1.1.1
9897  * Copyright(c) 2006-2007, Ext JS, LLC.
9898  *
9899  * Originally Released Under LGPL - original licence link has changed is not relivant.
9900  *
9901  * Fork - LGPL
9902  * <script type="text/javascript">
9903  */
9904
9905
9906
9907 //Notifies Element that fx methods are available
9908 Roo.enableFx = true;
9909
9910 /**
9911  * @class Roo.Fx
9912  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9913  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9914  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9915  * Element effects to work.</p><br/>
9916  *
9917  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9918  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9919  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9920  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9921  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9922  * expected results and should be done with care.</p><br/>
9923  *
9924  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9925  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9926 <pre>
9927 Value  Description
9928 -----  -----------------------------
9929 tl     The top left corner
9930 t      The center of the top edge
9931 tr     The top right corner
9932 l      The center of the left edge
9933 r      The center of the right edge
9934 bl     The bottom left corner
9935 b      The center of the bottom edge
9936 br     The bottom right corner
9937 </pre>
9938  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9939  * below are common options that can be passed to any Fx method.</b>
9940  * @cfg {Function} callback A function called when the effect is finished
9941  * @cfg {Object} scope The scope of the effect function
9942  * @cfg {String} easing A valid Easing value for the effect
9943  * @cfg {String} afterCls A css class to apply after the effect
9944  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9945  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9946  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9947  * effects that end with the element being visually hidden, ignored otherwise)
9948  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9949  * a function which returns such a specification that will be applied to the Element after the effect finishes
9950  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9951  * @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
9952  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9953  */
9954 Roo.Fx = {
9955         /**
9956          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9957          * origin for the slide effect.  This function automatically handles wrapping the element with
9958          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9959          * Usage:
9960          *<pre><code>
9961 // default: slide the element in from the top
9962 el.slideIn();
9963
9964 // custom: slide the element in from the right with a 2-second duration
9965 el.slideIn('r', { duration: 2 });
9966
9967 // common config options shown with default values
9968 el.slideIn('t', {
9969     easing: 'easeOut',
9970     duration: .5
9971 });
9972 </code></pre>
9973          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9974          * @param {Object} options (optional) Object literal with any of the Fx config options
9975          * @return {Roo.Element} The Element
9976          */
9977     slideIn : function(anchor, o){
9978         var el = this.getFxEl();
9979         o = o || {};
9980
9981         el.queueFx(o, function(){
9982
9983             anchor = anchor || "t";
9984
9985             // fix display to visibility
9986             this.fixDisplay();
9987
9988             // restore values after effect
9989             var r = this.getFxRestore();
9990             var b = this.getBox();
9991             // fixed size for slide
9992             this.setSize(b);
9993
9994             // wrap if needed
9995             var wrap = this.fxWrap(r.pos, o, "hidden");
9996
9997             var st = this.dom.style;
9998             st.visibility = "visible";
9999             st.position = "absolute";
10000
10001             // clear out temp styles after slide and unwrap
10002             var after = function(){
10003                 el.fxUnwrap(wrap, r.pos, o);
10004                 st.width = r.width;
10005                 st.height = r.height;
10006                 el.afterFx(o);
10007             };
10008             // time to calc the positions
10009             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10010
10011             switch(anchor.toLowerCase()){
10012                 case "t":
10013                     wrap.setSize(b.width, 0);
10014                     st.left = st.bottom = "0";
10015                     a = {height: bh};
10016                 break;
10017                 case "l":
10018                     wrap.setSize(0, b.height);
10019                     st.right = st.top = "0";
10020                     a = {width: bw};
10021                 break;
10022                 case "r":
10023                     wrap.setSize(0, b.height);
10024                     wrap.setX(b.right);
10025                     st.left = st.top = "0";
10026                     a = {width: bw, points: pt};
10027                 break;
10028                 case "b":
10029                     wrap.setSize(b.width, 0);
10030                     wrap.setY(b.bottom);
10031                     st.left = st.top = "0";
10032                     a = {height: bh, points: pt};
10033                 break;
10034                 case "tl":
10035                     wrap.setSize(0, 0);
10036                     st.right = st.bottom = "0";
10037                     a = {width: bw, height: bh};
10038                 break;
10039                 case "bl":
10040                     wrap.setSize(0, 0);
10041                     wrap.setY(b.y+b.height);
10042                     st.right = st.top = "0";
10043                     a = {width: bw, height: bh, points: pt};
10044                 break;
10045                 case "br":
10046                     wrap.setSize(0, 0);
10047                     wrap.setXY([b.right, b.bottom]);
10048                     st.left = st.top = "0";
10049                     a = {width: bw, height: bh, points: pt};
10050                 break;
10051                 case "tr":
10052                     wrap.setSize(0, 0);
10053                     wrap.setX(b.x+b.width);
10054                     st.left = st.bottom = "0";
10055                     a = {width: bw, height: bh, points: pt};
10056                 break;
10057             }
10058             this.dom.style.visibility = "visible";
10059             wrap.show();
10060
10061             arguments.callee.anim = wrap.fxanim(a,
10062                 o,
10063                 'motion',
10064                 .5,
10065                 'easeOut', after);
10066         });
10067         return this;
10068     },
10069     
10070         /**
10071          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10072          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10073          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10074          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10075          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10076          * Usage:
10077          *<pre><code>
10078 // default: slide the element out to the top
10079 el.slideOut();
10080
10081 // custom: slide the element out to the right with a 2-second duration
10082 el.slideOut('r', { duration: 2 });
10083
10084 // common config options shown with default values
10085 el.slideOut('t', {
10086     easing: 'easeOut',
10087     duration: .5,
10088     remove: false,
10089     useDisplay: false
10090 });
10091 </code></pre>
10092          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10093          * @param {Object} options (optional) Object literal with any of the Fx config options
10094          * @return {Roo.Element} The Element
10095          */
10096     slideOut : function(anchor, o){
10097         var el = this.getFxEl();
10098         o = o || {};
10099
10100         el.queueFx(o, function(){
10101
10102             anchor = anchor || "t";
10103
10104             // restore values after effect
10105             var r = this.getFxRestore();
10106             
10107             var b = this.getBox();
10108             // fixed size for slide
10109             this.setSize(b);
10110
10111             // wrap if needed
10112             var wrap = this.fxWrap(r.pos, o, "visible");
10113
10114             var st = this.dom.style;
10115             st.visibility = "visible";
10116             st.position = "absolute";
10117
10118             wrap.setSize(b);
10119
10120             var after = function(){
10121                 if(o.useDisplay){
10122                     el.setDisplayed(false);
10123                 }else{
10124                     el.hide();
10125                 }
10126
10127                 el.fxUnwrap(wrap, r.pos, o);
10128
10129                 st.width = r.width;
10130                 st.height = r.height;
10131
10132                 el.afterFx(o);
10133             };
10134
10135             var a, zero = {to: 0};
10136             switch(anchor.toLowerCase()){
10137                 case "t":
10138                     st.left = st.bottom = "0";
10139                     a = {height: zero};
10140                 break;
10141                 case "l":
10142                     st.right = st.top = "0";
10143                     a = {width: zero};
10144                 break;
10145                 case "r":
10146                     st.left = st.top = "0";
10147                     a = {width: zero, points: {to:[b.right, b.y]}};
10148                 break;
10149                 case "b":
10150                     st.left = st.top = "0";
10151                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10152                 break;
10153                 case "tl":
10154                     st.right = st.bottom = "0";
10155                     a = {width: zero, height: zero};
10156                 break;
10157                 case "bl":
10158                     st.right = st.top = "0";
10159                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10160                 break;
10161                 case "br":
10162                     st.left = st.top = "0";
10163                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10164                 break;
10165                 case "tr":
10166                     st.left = st.bottom = "0";
10167                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10168                 break;
10169             }
10170
10171             arguments.callee.anim = wrap.fxanim(a,
10172                 o,
10173                 'motion',
10174                 .5,
10175                 "easeOut", after);
10176         });
10177         return this;
10178     },
10179
10180         /**
10181          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10182          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10183          * The element must be removed from the DOM using the 'remove' config option if desired.
10184          * Usage:
10185          *<pre><code>
10186 // default
10187 el.puff();
10188
10189 // common config options shown with default values
10190 el.puff({
10191     easing: 'easeOut',
10192     duration: .5,
10193     remove: false,
10194     useDisplay: false
10195 });
10196 </code></pre>
10197          * @param {Object} options (optional) Object literal with any of the Fx config options
10198          * @return {Roo.Element} The Element
10199          */
10200     puff : function(o){
10201         var el = this.getFxEl();
10202         o = o || {};
10203
10204         el.queueFx(o, function(){
10205             this.clearOpacity();
10206             this.show();
10207
10208             // restore values after effect
10209             var r = this.getFxRestore();
10210             var st = this.dom.style;
10211
10212             var after = function(){
10213                 if(o.useDisplay){
10214                     el.setDisplayed(false);
10215                 }else{
10216                     el.hide();
10217                 }
10218
10219                 el.clearOpacity();
10220
10221                 el.setPositioning(r.pos);
10222                 st.width = r.width;
10223                 st.height = r.height;
10224                 st.fontSize = '';
10225                 el.afterFx(o);
10226             };
10227
10228             var width = this.getWidth();
10229             var height = this.getHeight();
10230
10231             arguments.callee.anim = this.fxanim({
10232                     width : {to: this.adjustWidth(width * 2)},
10233                     height : {to: this.adjustHeight(height * 2)},
10234                     points : {by: [-(width * .5), -(height * .5)]},
10235                     opacity : {to: 0},
10236                     fontSize: {to:200, unit: "%"}
10237                 },
10238                 o,
10239                 'motion',
10240                 .5,
10241                 "easeOut", after);
10242         });
10243         return this;
10244     },
10245
10246         /**
10247          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10248          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10249          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10250          * Usage:
10251          *<pre><code>
10252 // default
10253 el.switchOff();
10254
10255 // all config options shown with default values
10256 el.switchOff({
10257     easing: 'easeIn',
10258     duration: .3,
10259     remove: false,
10260     useDisplay: false
10261 });
10262 </code></pre>
10263          * @param {Object} options (optional) Object literal with any of the Fx config options
10264          * @return {Roo.Element} The Element
10265          */
10266     switchOff : function(o){
10267         var el = this.getFxEl();
10268         o = o || {};
10269
10270         el.queueFx(o, function(){
10271             this.clearOpacity();
10272             this.clip();
10273
10274             // restore values after effect
10275             var r = this.getFxRestore();
10276             var st = this.dom.style;
10277
10278             var after = function(){
10279                 if(o.useDisplay){
10280                     el.setDisplayed(false);
10281                 }else{
10282                     el.hide();
10283                 }
10284
10285                 el.clearOpacity();
10286                 el.setPositioning(r.pos);
10287                 st.width = r.width;
10288                 st.height = r.height;
10289
10290                 el.afterFx(o);
10291             };
10292
10293             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10294                 this.clearOpacity();
10295                 (function(){
10296                     this.fxanim({
10297                         height:{to:1},
10298                         points:{by:[0, this.getHeight() * .5]}
10299                     }, o, 'motion', 0.3, 'easeIn', after);
10300                 }).defer(100, this);
10301             });
10302         });
10303         return this;
10304     },
10305
10306     /**
10307      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10308      * changed using the "attr" config option) and then fading back to the original color. If no original
10309      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10310      * Usage:
10311 <pre><code>
10312 // default: highlight background to yellow
10313 el.highlight();
10314
10315 // custom: highlight foreground text to blue for 2 seconds
10316 el.highlight("0000ff", { attr: 'color', duration: 2 });
10317
10318 // common config options shown with default values
10319 el.highlight("ffff9c", {
10320     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10321     endColor: (current color) or "ffffff",
10322     easing: 'easeIn',
10323     duration: 1
10324 });
10325 </code></pre>
10326      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10327      * @param {Object} options (optional) Object literal with any of the Fx config options
10328      * @return {Roo.Element} The Element
10329      */ 
10330     highlight : function(color, o){
10331         var el = this.getFxEl();
10332         o = o || {};
10333
10334         el.queueFx(o, function(){
10335             color = color || "ffff9c";
10336             attr = o.attr || "backgroundColor";
10337
10338             this.clearOpacity();
10339             this.show();
10340
10341             var origColor = this.getColor(attr);
10342             var restoreColor = this.dom.style[attr];
10343             endColor = (o.endColor || origColor) || "ffffff";
10344
10345             var after = function(){
10346                 el.dom.style[attr] = restoreColor;
10347                 el.afterFx(o);
10348             };
10349
10350             var a = {};
10351             a[attr] = {from: color, to: endColor};
10352             arguments.callee.anim = this.fxanim(a,
10353                 o,
10354                 'color',
10355                 1,
10356                 'easeIn', after);
10357         });
10358         return this;
10359     },
10360
10361    /**
10362     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10363     * Usage:
10364 <pre><code>
10365 // default: a single light blue ripple
10366 el.frame();
10367
10368 // custom: 3 red ripples lasting 3 seconds total
10369 el.frame("ff0000", 3, { duration: 3 });
10370
10371 // common config options shown with default values
10372 el.frame("C3DAF9", 1, {
10373     duration: 1 //duration of entire animation (not each individual ripple)
10374     // Note: Easing is not configurable and will be ignored if included
10375 });
10376 </code></pre>
10377     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10378     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10379     * @param {Object} options (optional) Object literal with any of the Fx config options
10380     * @return {Roo.Element} The Element
10381     */
10382     frame : function(color, count, o){
10383         var el = this.getFxEl();
10384         o = o || {};
10385
10386         el.queueFx(o, function(){
10387             color = color || "#C3DAF9";
10388             if(color.length == 6){
10389                 color = "#" + color;
10390             }
10391             count = count || 1;
10392             duration = o.duration || 1;
10393             this.show();
10394
10395             var b = this.getBox();
10396             var animFn = function(){
10397                 var proxy = this.createProxy({
10398
10399                      style:{
10400                         visbility:"hidden",
10401                         position:"absolute",
10402                         "z-index":"35000", // yee haw
10403                         border:"0px solid " + color
10404                      }
10405                   });
10406                 var scale = Roo.isBorderBox ? 2 : 1;
10407                 proxy.animate({
10408                     top:{from:b.y, to:b.y - 20},
10409                     left:{from:b.x, to:b.x - 20},
10410                     borderWidth:{from:0, to:10},
10411                     opacity:{from:1, to:0},
10412                     height:{from:b.height, to:(b.height + (20*scale))},
10413                     width:{from:b.width, to:(b.width + (20*scale))}
10414                 }, duration, function(){
10415                     proxy.remove();
10416                 });
10417                 if(--count > 0){
10418                      animFn.defer((duration/2)*1000, this);
10419                 }else{
10420                     el.afterFx(o);
10421                 }
10422             };
10423             animFn.call(this);
10424         });
10425         return this;
10426     },
10427
10428    /**
10429     * Creates a pause before any subsequent queued effects begin.  If there are
10430     * no effects queued after the pause it will have no effect.
10431     * Usage:
10432 <pre><code>
10433 el.pause(1);
10434 </code></pre>
10435     * @param {Number} seconds The length of time to pause (in seconds)
10436     * @return {Roo.Element} The Element
10437     */
10438     pause : function(seconds){
10439         var el = this.getFxEl();
10440         var o = {};
10441
10442         el.queueFx(o, function(){
10443             setTimeout(function(){
10444                 el.afterFx(o);
10445             }, seconds * 1000);
10446         });
10447         return this;
10448     },
10449
10450    /**
10451     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10452     * using the "endOpacity" config option.
10453     * Usage:
10454 <pre><code>
10455 // default: fade in from opacity 0 to 100%
10456 el.fadeIn();
10457
10458 // custom: fade in from opacity 0 to 75% over 2 seconds
10459 el.fadeIn({ endOpacity: .75, duration: 2});
10460
10461 // common config options shown with default values
10462 el.fadeIn({
10463     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10464     easing: 'easeOut',
10465     duration: .5
10466 });
10467 </code></pre>
10468     * @param {Object} options (optional) Object literal with any of the Fx config options
10469     * @return {Roo.Element} The Element
10470     */
10471     fadeIn : function(o){
10472         var el = this.getFxEl();
10473         o = o || {};
10474         el.queueFx(o, function(){
10475             this.setOpacity(0);
10476             this.fixDisplay();
10477             this.dom.style.visibility = 'visible';
10478             var to = o.endOpacity || 1;
10479             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10480                 o, null, .5, "easeOut", function(){
10481                 if(to == 1){
10482                     this.clearOpacity();
10483                 }
10484                 el.afterFx(o);
10485             });
10486         });
10487         return this;
10488     },
10489
10490    /**
10491     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10492     * using the "endOpacity" config option.
10493     * Usage:
10494 <pre><code>
10495 // default: fade out from the element's current opacity to 0
10496 el.fadeOut();
10497
10498 // custom: fade out from the element's current opacity to 25% over 2 seconds
10499 el.fadeOut({ endOpacity: .25, duration: 2});
10500
10501 // common config options shown with default values
10502 el.fadeOut({
10503     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10504     easing: 'easeOut',
10505     duration: .5
10506     remove: false,
10507     useDisplay: false
10508 });
10509 </code></pre>
10510     * @param {Object} options (optional) Object literal with any of the Fx config options
10511     * @return {Roo.Element} The Element
10512     */
10513     fadeOut : function(o){
10514         var el = this.getFxEl();
10515         o = o || {};
10516         el.queueFx(o, function(){
10517             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10518                 o, null, .5, "easeOut", function(){
10519                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10520                      this.dom.style.display = "none";
10521                 }else{
10522                      this.dom.style.visibility = "hidden";
10523                 }
10524                 this.clearOpacity();
10525                 el.afterFx(o);
10526             });
10527         });
10528         return this;
10529     },
10530
10531    /**
10532     * Animates the transition of an element's dimensions from a starting height/width
10533     * to an ending height/width.
10534     * Usage:
10535 <pre><code>
10536 // change height and width to 100x100 pixels
10537 el.scale(100, 100);
10538
10539 // common config options shown with default values.  The height and width will default to
10540 // the element's existing values if passed as null.
10541 el.scale(
10542     [element's width],
10543     [element's height], {
10544     easing: 'easeOut',
10545     duration: .35
10546 });
10547 </code></pre>
10548     * @param {Number} width  The new width (pass undefined to keep the original width)
10549     * @param {Number} height  The new height (pass undefined to keep the original height)
10550     * @param {Object} options (optional) Object literal with any of the Fx config options
10551     * @return {Roo.Element} The Element
10552     */
10553     scale : function(w, h, o){
10554         this.shift(Roo.apply({}, o, {
10555             width: w,
10556             height: h
10557         }));
10558         return this;
10559     },
10560
10561    /**
10562     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10563     * Any of these properties not specified in the config object will not be changed.  This effect 
10564     * requires that at least one new dimension, position or opacity setting must be passed in on
10565     * the config object in order for the function to have any effect.
10566     * Usage:
10567 <pre><code>
10568 // slide the element horizontally to x position 200 while changing the height and opacity
10569 el.shift({ x: 200, height: 50, opacity: .8 });
10570
10571 // common config options shown with default values.
10572 el.shift({
10573     width: [element's width],
10574     height: [element's height],
10575     x: [element's x position],
10576     y: [element's y position],
10577     opacity: [element's opacity],
10578     easing: 'easeOut',
10579     duration: .35
10580 });
10581 </code></pre>
10582     * @param {Object} options  Object literal with any of the Fx config options
10583     * @return {Roo.Element} The Element
10584     */
10585     shift : function(o){
10586         var el = this.getFxEl();
10587         o = o || {};
10588         el.queueFx(o, function(){
10589             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10590             if(w !== undefined){
10591                 a.width = {to: this.adjustWidth(w)};
10592             }
10593             if(h !== undefined){
10594                 a.height = {to: this.adjustHeight(h)};
10595             }
10596             if(x !== undefined || y !== undefined){
10597                 a.points = {to: [
10598                     x !== undefined ? x : this.getX(),
10599                     y !== undefined ? y : this.getY()
10600                 ]};
10601             }
10602             if(op !== undefined){
10603                 a.opacity = {to: op};
10604             }
10605             if(o.xy !== undefined){
10606                 a.points = {to: o.xy};
10607             }
10608             arguments.callee.anim = this.fxanim(a,
10609                 o, 'motion', .35, "easeOut", function(){
10610                 el.afterFx(o);
10611             });
10612         });
10613         return this;
10614     },
10615
10616         /**
10617          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10618          * ending point of the effect.
10619          * Usage:
10620          *<pre><code>
10621 // default: slide the element downward while fading out
10622 el.ghost();
10623
10624 // custom: slide the element out to the right with a 2-second duration
10625 el.ghost('r', { duration: 2 });
10626
10627 // common config options shown with default values
10628 el.ghost('b', {
10629     easing: 'easeOut',
10630     duration: .5
10631     remove: false,
10632     useDisplay: false
10633 });
10634 </code></pre>
10635          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10636          * @param {Object} options (optional) Object literal with any of the Fx config options
10637          * @return {Roo.Element} The Element
10638          */
10639     ghost : function(anchor, o){
10640         var el = this.getFxEl();
10641         o = o || {};
10642
10643         el.queueFx(o, function(){
10644             anchor = anchor || "b";
10645
10646             // restore values after effect
10647             var r = this.getFxRestore();
10648             var w = this.getWidth(),
10649                 h = this.getHeight();
10650
10651             var st = this.dom.style;
10652
10653             var after = function(){
10654                 if(o.useDisplay){
10655                     el.setDisplayed(false);
10656                 }else{
10657                     el.hide();
10658                 }
10659
10660                 el.clearOpacity();
10661                 el.setPositioning(r.pos);
10662                 st.width = r.width;
10663                 st.height = r.height;
10664
10665                 el.afterFx(o);
10666             };
10667
10668             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10669             switch(anchor.toLowerCase()){
10670                 case "t":
10671                     pt.by = [0, -h];
10672                 break;
10673                 case "l":
10674                     pt.by = [-w, 0];
10675                 break;
10676                 case "r":
10677                     pt.by = [w, 0];
10678                 break;
10679                 case "b":
10680                     pt.by = [0, h];
10681                 break;
10682                 case "tl":
10683                     pt.by = [-w, -h];
10684                 break;
10685                 case "bl":
10686                     pt.by = [-w, h];
10687                 break;
10688                 case "br":
10689                     pt.by = [w, h];
10690                 break;
10691                 case "tr":
10692                     pt.by = [w, -h];
10693                 break;
10694             }
10695
10696             arguments.callee.anim = this.fxanim(a,
10697                 o,
10698                 'motion',
10699                 .5,
10700                 "easeOut", after);
10701         });
10702         return this;
10703     },
10704
10705         /**
10706          * Ensures that all effects queued after syncFx is called on the element are
10707          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10708          * @return {Roo.Element} The Element
10709          */
10710     syncFx : function(){
10711         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10712             block : false,
10713             concurrent : true,
10714             stopFx : false
10715         });
10716         return this;
10717     },
10718
10719         /**
10720          * Ensures that all effects queued after sequenceFx is called on the element are
10721          * run in sequence.  This is the opposite of {@link #syncFx}.
10722          * @return {Roo.Element} The Element
10723          */
10724     sequenceFx : function(){
10725         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10726             block : false,
10727             concurrent : false,
10728             stopFx : false
10729         });
10730         return this;
10731     },
10732
10733         /* @private */
10734     nextFx : function(){
10735         var ef = this.fxQueue[0];
10736         if(ef){
10737             ef.call(this);
10738         }
10739     },
10740
10741         /**
10742          * Returns true if the element has any effects actively running or queued, else returns false.
10743          * @return {Boolean} True if element has active effects, else false
10744          */
10745     hasActiveFx : function(){
10746         return this.fxQueue && this.fxQueue[0];
10747     },
10748
10749         /**
10750          * Stops any running effects and clears the element's internal effects queue if it contains
10751          * any additional effects that haven't started yet.
10752          * @return {Roo.Element} The Element
10753          */
10754     stopFx : function(){
10755         if(this.hasActiveFx()){
10756             var cur = this.fxQueue[0];
10757             if(cur && cur.anim && cur.anim.isAnimated()){
10758                 this.fxQueue = [cur]; // clear out others
10759                 cur.anim.stop(true);
10760             }
10761         }
10762         return this;
10763     },
10764
10765         /* @private */
10766     beforeFx : function(o){
10767         if(this.hasActiveFx() && !o.concurrent){
10768            if(o.stopFx){
10769                this.stopFx();
10770                return true;
10771            }
10772            return false;
10773         }
10774         return true;
10775     },
10776
10777         /**
10778          * Returns true if the element is currently blocking so that no other effect can be queued
10779          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10780          * used to ensure that an effect initiated by a user action runs to completion prior to the
10781          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10782          * @return {Boolean} True if blocking, else false
10783          */
10784     hasFxBlock : function(){
10785         var q = this.fxQueue;
10786         return q && q[0] && q[0].block;
10787     },
10788
10789         /* @private */
10790     queueFx : function(o, fn){
10791         if(!this.fxQueue){
10792             this.fxQueue = [];
10793         }
10794         if(!this.hasFxBlock()){
10795             Roo.applyIf(o, this.fxDefaults);
10796             if(!o.concurrent){
10797                 var run = this.beforeFx(o);
10798                 fn.block = o.block;
10799                 this.fxQueue.push(fn);
10800                 if(run){
10801                     this.nextFx();
10802                 }
10803             }else{
10804                 fn.call(this);
10805             }
10806         }
10807         return this;
10808     },
10809
10810         /* @private */
10811     fxWrap : function(pos, o, vis){
10812         var wrap;
10813         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10814             var wrapXY;
10815             if(o.fixPosition){
10816                 wrapXY = this.getXY();
10817             }
10818             var div = document.createElement("div");
10819             div.style.visibility = vis;
10820             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10821             wrap.setPositioning(pos);
10822             if(wrap.getStyle("position") == "static"){
10823                 wrap.position("relative");
10824             }
10825             this.clearPositioning('auto');
10826             wrap.clip();
10827             wrap.dom.appendChild(this.dom);
10828             if(wrapXY){
10829                 wrap.setXY(wrapXY);
10830             }
10831         }
10832         return wrap;
10833     },
10834
10835         /* @private */
10836     fxUnwrap : function(wrap, pos, o){
10837         this.clearPositioning();
10838         this.setPositioning(pos);
10839         if(!o.wrap){
10840             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10841             wrap.remove();
10842         }
10843     },
10844
10845         /* @private */
10846     getFxRestore : function(){
10847         var st = this.dom.style;
10848         return {pos: this.getPositioning(), width: st.width, height : st.height};
10849     },
10850
10851         /* @private */
10852     afterFx : function(o){
10853         if(o.afterStyle){
10854             this.applyStyles(o.afterStyle);
10855         }
10856         if(o.afterCls){
10857             this.addClass(o.afterCls);
10858         }
10859         if(o.remove === true){
10860             this.remove();
10861         }
10862         Roo.callback(o.callback, o.scope, [this]);
10863         if(!o.concurrent){
10864             this.fxQueue.shift();
10865             this.nextFx();
10866         }
10867     },
10868
10869         /* @private */
10870     getFxEl : function(){ // support for composite element fx
10871         return Roo.get(this.dom);
10872     },
10873
10874         /* @private */
10875     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10876         animType = animType || 'run';
10877         opt = opt || {};
10878         var anim = Roo.lib.Anim[animType](
10879             this.dom, args,
10880             (opt.duration || defaultDur) || .35,
10881             (opt.easing || defaultEase) || 'easeOut',
10882             function(){
10883                 Roo.callback(cb, this);
10884             },
10885             this
10886         );
10887         opt.anim = anim;
10888         return anim;
10889     }
10890 };
10891
10892 // backwords compat
10893 Roo.Fx.resize = Roo.Fx.scale;
10894
10895 //When included, Roo.Fx is automatically applied to Element so that all basic
10896 //effects are available directly via the Element API
10897 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10898  * Based on:
10899  * Ext JS Library 1.1.1
10900  * Copyright(c) 2006-2007, Ext JS, LLC.
10901  *
10902  * Originally Released Under LGPL - original licence link has changed is not relivant.
10903  *
10904  * Fork - LGPL
10905  * <script type="text/javascript">
10906  */
10907
10908
10909 /**
10910  * @class Roo.CompositeElement
10911  * Standard composite class. Creates a Roo.Element for every element in the collection.
10912  * <br><br>
10913  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10914  * actions will be performed on all the elements in this collection.</b>
10915  * <br><br>
10916  * All methods return <i>this</i> and can be chained.
10917  <pre><code>
10918  var els = Roo.select("#some-el div.some-class", true);
10919  // or select directly from an existing element
10920  var el = Roo.get('some-el');
10921  el.select('div.some-class', true);
10922
10923  els.setWidth(100); // all elements become 100 width
10924  els.hide(true); // all elements fade out and hide
10925  // or
10926  els.setWidth(100).hide(true);
10927  </code></pre>
10928  */
10929 Roo.CompositeElement = function(els){
10930     this.elements = [];
10931     this.addElements(els);
10932 };
10933 Roo.CompositeElement.prototype = {
10934     isComposite: true,
10935     addElements : function(els){
10936         if(!els) return this;
10937         if(typeof els == "string"){
10938             els = Roo.Element.selectorFunction(els);
10939         }
10940         var yels = this.elements;
10941         var index = yels.length-1;
10942         for(var i = 0, len = els.length; i < len; i++) {
10943                 yels[++index] = Roo.get(els[i]);
10944         }
10945         return this;
10946     },
10947
10948     /**
10949     * Clears this composite and adds the elements returned by the passed selector.
10950     * @param {String/Array} els A string CSS selector, an array of elements or an element
10951     * @return {CompositeElement} this
10952     */
10953     fill : function(els){
10954         this.elements = [];
10955         this.add(els);
10956         return this;
10957     },
10958
10959     /**
10960     * Filters this composite to only elements that match the passed selector.
10961     * @param {String} selector A string CSS selector
10962     * @return {CompositeElement} this
10963     */
10964     filter : function(selector){
10965         var els = [];
10966         this.each(function(el){
10967             if(el.is(selector)){
10968                 els[els.length] = el.dom;
10969             }
10970         });
10971         this.fill(els);
10972         return this;
10973     },
10974
10975     invoke : function(fn, args){
10976         var els = this.elements;
10977         for(var i = 0, len = els.length; i < len; i++) {
10978                 Roo.Element.prototype[fn].apply(els[i], args);
10979         }
10980         return this;
10981     },
10982     /**
10983     * Adds elements to this composite.
10984     * @param {String/Array} els A string CSS selector, an array of elements or an element
10985     * @return {CompositeElement} this
10986     */
10987     add : function(els){
10988         if(typeof els == "string"){
10989             this.addElements(Roo.Element.selectorFunction(els));
10990         }else if(els.length !== undefined){
10991             this.addElements(els);
10992         }else{
10993             this.addElements([els]);
10994         }
10995         return this;
10996     },
10997     /**
10998     * Calls the passed function passing (el, this, index) for each element in this composite.
10999     * @param {Function} fn The function to call
11000     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11001     * @return {CompositeElement} this
11002     */
11003     each : function(fn, scope){
11004         var els = this.elements;
11005         for(var i = 0, len = els.length; i < len; i++){
11006             if(fn.call(scope || els[i], els[i], this, i) === false) {
11007                 break;
11008             }
11009         }
11010         return this;
11011     },
11012
11013     /**
11014      * Returns the Element object at the specified index
11015      * @param {Number} index
11016      * @return {Roo.Element}
11017      */
11018     item : function(index){
11019         return this.elements[index] || null;
11020     },
11021
11022     /**
11023      * Returns the first Element
11024      * @return {Roo.Element}
11025      */
11026     first : function(){
11027         return this.item(0);
11028     },
11029
11030     /**
11031      * Returns the last Element
11032      * @return {Roo.Element}
11033      */
11034     last : function(){
11035         return this.item(this.elements.length-1);
11036     },
11037
11038     /**
11039      * Returns the number of elements in this composite
11040      * @return Number
11041      */
11042     getCount : function(){
11043         return this.elements.length;
11044     },
11045
11046     /**
11047      * Returns true if this composite contains the passed element
11048      * @return Boolean
11049      */
11050     contains : function(el){
11051         return this.indexOf(el) !== -1;
11052     },
11053
11054     /**
11055      * Returns true if this composite contains the passed element
11056      * @return Boolean
11057      */
11058     indexOf : function(el){
11059         return this.elements.indexOf(Roo.get(el));
11060     },
11061
11062
11063     /**
11064     * Removes the specified element(s).
11065     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11066     * or an array of any of those.
11067     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11068     * @return {CompositeElement} this
11069     */
11070     removeElement : function(el, removeDom){
11071         if(el instanceof Array){
11072             for(var i = 0, len = el.length; i < len; i++){
11073                 this.removeElement(el[i]);
11074             }
11075             return this;
11076         }
11077         var index = typeof el == 'number' ? el : this.indexOf(el);
11078         if(index !== -1){
11079             if(removeDom){
11080                 var d = this.elements[index];
11081                 if(d.dom){
11082                     d.remove();
11083                 }else{
11084                     d.parentNode.removeChild(d);
11085                 }
11086             }
11087             this.elements.splice(index, 1);
11088         }
11089         return this;
11090     },
11091
11092     /**
11093     * Replaces the specified element with the passed element.
11094     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11095     * to replace.
11096     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11097     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11098     * @return {CompositeElement} this
11099     */
11100     replaceElement : function(el, replacement, domReplace){
11101         var index = typeof el == 'number' ? el : this.indexOf(el);
11102         if(index !== -1){
11103             if(domReplace){
11104                 this.elements[index].replaceWith(replacement);
11105             }else{
11106                 this.elements.splice(index, 1, Roo.get(replacement))
11107             }
11108         }
11109         return this;
11110     },
11111
11112     /**
11113      * Removes all elements.
11114      */
11115     clear : function(){
11116         this.elements = [];
11117     }
11118 };
11119 (function(){
11120     Roo.CompositeElement.createCall = function(proto, fnName){
11121         if(!proto[fnName]){
11122             proto[fnName] = function(){
11123                 return this.invoke(fnName, arguments);
11124             };
11125         }
11126     };
11127     for(var fnName in Roo.Element.prototype){
11128         if(typeof Roo.Element.prototype[fnName] == "function"){
11129             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11130         }
11131     };
11132 })();
11133 /*
11134  * Based on:
11135  * Ext JS Library 1.1.1
11136  * Copyright(c) 2006-2007, Ext JS, LLC.
11137  *
11138  * Originally Released Under LGPL - original licence link has changed is not relivant.
11139  *
11140  * Fork - LGPL
11141  * <script type="text/javascript">
11142  */
11143
11144 /**
11145  * @class Roo.CompositeElementLite
11146  * @extends Roo.CompositeElement
11147  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11148  <pre><code>
11149  var els = Roo.select("#some-el div.some-class");
11150  // or select directly from an existing element
11151  var el = Roo.get('some-el');
11152  el.select('div.some-class');
11153
11154  els.setWidth(100); // all elements become 100 width
11155  els.hide(true); // all elements fade out and hide
11156  // or
11157  els.setWidth(100).hide(true);
11158  </code></pre><br><br>
11159  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11160  * actions will be performed on all the elements in this collection.</b>
11161  */
11162 Roo.CompositeElementLite = function(els){
11163     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11164     this.el = new Roo.Element.Flyweight();
11165 };
11166 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11167     addElements : function(els){
11168         if(els){
11169             if(els instanceof Array){
11170                 this.elements = this.elements.concat(els);
11171             }else{
11172                 var yels = this.elements;
11173                 var index = yels.length-1;
11174                 for(var i = 0, len = els.length; i < len; i++) {
11175                     yels[++index] = els[i];
11176                 }
11177             }
11178         }
11179         return this;
11180     },
11181     invoke : function(fn, args){
11182         var els = this.elements;
11183         var el = this.el;
11184         for(var i = 0, len = els.length; i < len; i++) {
11185             el.dom = els[i];
11186                 Roo.Element.prototype[fn].apply(el, args);
11187         }
11188         return this;
11189     },
11190     /**
11191      * Returns a flyweight Element of the dom element object at the specified index
11192      * @param {Number} index
11193      * @return {Roo.Element}
11194      */
11195     item : function(index){
11196         if(!this.elements[index]){
11197             return null;
11198         }
11199         this.el.dom = this.elements[index];
11200         return this.el;
11201     },
11202
11203     // fixes scope with flyweight
11204     addListener : function(eventName, handler, scope, opt){
11205         var els = this.elements;
11206         for(var i = 0, len = els.length; i < len; i++) {
11207             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11208         }
11209         return this;
11210     },
11211
11212     /**
11213     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11214     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11215     * a reference to the dom node, use el.dom.</b>
11216     * @param {Function} fn The function to call
11217     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11218     * @return {CompositeElement} this
11219     */
11220     each : function(fn, scope){
11221         var els = this.elements;
11222         var el = this.el;
11223         for(var i = 0, len = els.length; i < len; i++){
11224             el.dom = els[i];
11225                 if(fn.call(scope || el, el, this, i) === false){
11226                 break;
11227             }
11228         }
11229         return this;
11230     },
11231
11232     indexOf : function(el){
11233         return this.elements.indexOf(Roo.getDom(el));
11234     },
11235
11236     replaceElement : function(el, replacement, domReplace){
11237         var index = typeof el == 'number' ? el : this.indexOf(el);
11238         if(index !== -1){
11239             replacement = Roo.getDom(replacement);
11240             if(domReplace){
11241                 var d = this.elements[index];
11242                 d.parentNode.insertBefore(replacement, d);
11243                 d.parentNode.removeChild(d);
11244             }
11245             this.elements.splice(index, 1, replacement);
11246         }
11247         return this;
11248     }
11249 });
11250 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11251
11252 /*
11253  * Based on:
11254  * Ext JS Library 1.1.1
11255  * Copyright(c) 2006-2007, Ext JS, LLC.
11256  *
11257  * Originally Released Under LGPL - original licence link has changed is not relivant.
11258  *
11259  * Fork - LGPL
11260  * <script type="text/javascript">
11261  */
11262
11263  
11264
11265 /**
11266  * @class Roo.data.Connection
11267  * @extends Roo.util.Observable
11268  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11269  * either to a configured URL, or to a URL specified at request time.<br><br>
11270  * <p>
11271  * Requests made by this class are asynchronous, and will return immediately. No data from
11272  * the server will be available to the statement immediately following the {@link #request} call.
11273  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11274  * <p>
11275  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11276  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11277  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11278  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11279  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11280  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11281  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11282  * standard DOM methods.
11283  * @constructor
11284  * @param {Object} config a configuration object.
11285  */
11286 Roo.data.Connection = function(config){
11287     Roo.apply(this, config);
11288     this.addEvents({
11289         /**
11290          * @event beforerequest
11291          * Fires before a network request is made to retrieve a data object.
11292          * @param {Connection} conn This Connection object.
11293          * @param {Object} options The options config object passed to the {@link #request} method.
11294          */
11295         "beforerequest" : true,
11296         /**
11297          * @event requestcomplete
11298          * Fires if the request was successfully completed.
11299          * @param {Connection} conn This Connection object.
11300          * @param {Object} response The XHR object containing the response data.
11301          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11302          * @param {Object} options The options config object passed to the {@link #request} method.
11303          */
11304         "requestcomplete" : true,
11305         /**
11306          * @event requestexception
11307          * Fires if an error HTTP status was returned from the server.
11308          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11309          * @param {Connection} conn This Connection object.
11310          * @param {Object} response The XHR object containing the response data.
11311          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11312          * @param {Object} options The options config object passed to the {@link #request} method.
11313          */
11314         "requestexception" : true
11315     });
11316     Roo.data.Connection.superclass.constructor.call(this);
11317 };
11318
11319 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11320     /**
11321      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11322      */
11323     /**
11324      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11325      * extra parameters to each request made by this object. (defaults to undefined)
11326      */
11327     /**
11328      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11329      *  to each request made by this object. (defaults to undefined)
11330      */
11331     /**
11332      * @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)
11333      */
11334     /**
11335      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11336      */
11337     timeout : 30000,
11338     /**
11339      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11340      * @type Boolean
11341      */
11342     autoAbort:false,
11343
11344     /**
11345      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11346      * @type Boolean
11347      */
11348     disableCaching: true,
11349
11350     /**
11351      * Sends an HTTP request to a remote server.
11352      * @param {Object} options An object which may contain the following properties:<ul>
11353      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11354      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11355      * request, a url encoded string or a function to call to get either.</li>
11356      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11357      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11358      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11359      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11360      * <li>options {Object} The parameter to the request call.</li>
11361      * <li>success {Boolean} True if the request succeeded.</li>
11362      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11363      * </ul></li>
11364      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11365      * The callback is passed the following parameters:<ul>
11366      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11367      * <li>options {Object} The parameter to the request call.</li>
11368      * </ul></li>
11369      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11370      * The callback is passed the following parameters:<ul>
11371      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11372      * <li>options {Object} The parameter to the request call.</li>
11373      * </ul></li>
11374      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11375      * for the callback function. Defaults to the browser window.</li>
11376      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11377      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11378      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11379      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11380      * params for the post data. Any params will be appended to the URL.</li>
11381      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11382      * </ul>
11383      * @return {Number} transactionId
11384      */
11385     request : function(o){
11386         if(this.fireEvent("beforerequest", this, o) !== false){
11387             var p = o.params;
11388
11389             if(typeof p == "function"){
11390                 p = p.call(o.scope||window, o);
11391             }
11392             if(typeof p == "object"){
11393                 p = Roo.urlEncode(o.params);
11394             }
11395             if(this.extraParams){
11396                 var extras = Roo.urlEncode(this.extraParams);
11397                 p = p ? (p + '&' + extras) : extras;
11398             }
11399
11400             var url = o.url || this.url;
11401             if(typeof url == 'function'){
11402                 url = url.call(o.scope||window, o);
11403             }
11404
11405             if(o.form){
11406                 var form = Roo.getDom(o.form);
11407                 url = url || form.action;
11408
11409                 var enctype = form.getAttribute("enctype");
11410                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11411                     return this.doFormUpload(o, p, url);
11412                 }
11413                 var f = Roo.lib.Ajax.serializeForm(form);
11414                 p = p ? (p + '&' + f) : f;
11415             }
11416
11417             var hs = o.headers;
11418             if(this.defaultHeaders){
11419                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11420                 if(!o.headers){
11421                     o.headers = hs;
11422                 }
11423             }
11424
11425             var cb = {
11426                 success: this.handleResponse,
11427                 failure: this.handleFailure,
11428                 scope: this,
11429                 argument: {options: o},
11430                 timeout : o.timeout || this.timeout
11431             };
11432
11433             var method = o.method||this.method||(p ? "POST" : "GET");
11434
11435             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11436                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11437             }
11438
11439             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11440                 if(o.autoAbort){
11441                     this.abort();
11442                 }
11443             }else if(this.autoAbort !== false){
11444                 this.abort();
11445             }
11446
11447             if((method == 'GET' && p) || o.xmlData){
11448                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11449                 p = '';
11450             }
11451             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11452             return this.transId;
11453         }else{
11454             Roo.callback(o.callback, o.scope, [o, null, null]);
11455             return null;
11456         }
11457     },
11458
11459     /**
11460      * Determine whether this object has a request outstanding.
11461      * @param {Number} transactionId (Optional) defaults to the last transaction
11462      * @return {Boolean} True if there is an outstanding request.
11463      */
11464     isLoading : function(transId){
11465         if(transId){
11466             return Roo.lib.Ajax.isCallInProgress(transId);
11467         }else{
11468             return this.transId ? true : false;
11469         }
11470     },
11471
11472     /**
11473      * Aborts any outstanding request.
11474      * @param {Number} transactionId (Optional) defaults to the last transaction
11475      */
11476     abort : function(transId){
11477         if(transId || this.isLoading()){
11478             Roo.lib.Ajax.abort(transId || this.transId);
11479         }
11480     },
11481
11482     // private
11483     handleResponse : function(response){
11484         this.transId = false;
11485         var options = response.argument.options;
11486         response.argument = options ? options.argument : null;
11487         this.fireEvent("requestcomplete", this, response, options);
11488         Roo.callback(options.success, options.scope, [response, options]);
11489         Roo.callback(options.callback, options.scope, [options, true, response]);
11490     },
11491
11492     // private
11493     handleFailure : function(response, e){
11494         this.transId = false;
11495         var options = response.argument.options;
11496         response.argument = options ? options.argument : null;
11497         this.fireEvent("requestexception", this, response, options, e);
11498         Roo.callback(options.failure, options.scope, [response, options]);
11499         Roo.callback(options.callback, options.scope, [options, false, response]);
11500     },
11501
11502     // private
11503     doFormUpload : function(o, ps, url){
11504         var id = Roo.id();
11505         var frame = document.createElement('iframe');
11506         frame.id = id;
11507         frame.name = id;
11508         frame.className = 'x-hidden';
11509         if(Roo.isIE){
11510             frame.src = Roo.SSL_SECURE_URL;
11511         }
11512         document.body.appendChild(frame);
11513
11514         if(Roo.isIE){
11515            document.frames[id].name = id;
11516         }
11517
11518         var form = Roo.getDom(o.form);
11519         form.target = id;
11520         form.method = 'POST';
11521         form.enctype = form.encoding = 'multipart/form-data';
11522         if(url){
11523             form.action = url;
11524         }
11525
11526         var hiddens, hd;
11527         if(ps){ // add dynamic params
11528             hiddens = [];
11529             ps = Roo.urlDecode(ps, false);
11530             for(var k in ps){
11531                 if(ps.hasOwnProperty(k)){
11532                     hd = document.createElement('input');
11533                     hd.type = 'hidden';
11534                     hd.name = k;
11535                     hd.value = ps[k];
11536                     form.appendChild(hd);
11537                     hiddens.push(hd);
11538                 }
11539             }
11540         }
11541
11542         function cb(){
11543             var r = {  // bogus response object
11544                 responseText : '',
11545                 responseXML : null
11546             };
11547
11548             r.argument = o ? o.argument : null;
11549
11550             try { //
11551                 var doc;
11552                 if(Roo.isIE){
11553                     doc = frame.contentWindow.document;
11554                 }else {
11555                     doc = (frame.contentDocument || window.frames[id].document);
11556                 }
11557                 if(doc && doc.body){
11558                     r.responseText = doc.body.innerHTML;
11559                 }
11560                 if(doc && doc.XMLDocument){
11561                     r.responseXML = doc.XMLDocument;
11562                 }else {
11563                     r.responseXML = doc;
11564                 }
11565             }
11566             catch(e) {
11567                 // ignore
11568             }
11569
11570             Roo.EventManager.removeListener(frame, 'load', cb, this);
11571
11572             this.fireEvent("requestcomplete", this, r, o);
11573             Roo.callback(o.success, o.scope, [r, o]);
11574             Roo.callback(o.callback, o.scope, [o, true, r]);
11575
11576             setTimeout(function(){document.body.removeChild(frame);}, 100);
11577         }
11578
11579         Roo.EventManager.on(frame, 'load', cb, this);
11580         form.submit();
11581
11582         if(hiddens){ // remove dynamic params
11583             for(var i = 0, len = hiddens.length; i < len; i++){
11584                 form.removeChild(hiddens[i]);
11585             }
11586         }
11587     }
11588 });
11589 /*
11590  * Based on:
11591  * Ext JS Library 1.1.1
11592  * Copyright(c) 2006-2007, Ext JS, LLC.
11593  *
11594  * Originally Released Under LGPL - original licence link has changed is not relivant.
11595  *
11596  * Fork - LGPL
11597  * <script type="text/javascript">
11598  */
11599  
11600 /**
11601  * Global Ajax request class.
11602  * 
11603  * @class Roo.Ajax
11604  * @extends Roo.data.Connection
11605  * @static
11606  * 
11607  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11608  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11609  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11610  * @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)
11611  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11612  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11613  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11614  */
11615 Roo.Ajax = new Roo.data.Connection({
11616     // fix up the docs
11617     /**
11618      * @scope Roo.Ajax
11619      * @type {Boolear} 
11620      */
11621     autoAbort : false,
11622
11623     /**
11624      * Serialize the passed form into a url encoded string
11625      * @scope Roo.Ajax
11626      * @param {String/HTMLElement} form
11627      * @return {String}
11628      */
11629     serializeForm : function(form){
11630         return Roo.lib.Ajax.serializeForm(form);
11631     }
11632 });/*
11633  * Based on:
11634  * Ext JS Library 1.1.1
11635  * Copyright(c) 2006-2007, Ext JS, LLC.
11636  *
11637  * Originally Released Under LGPL - original licence link has changed is not relivant.
11638  *
11639  * Fork - LGPL
11640  * <script type="text/javascript">
11641  */
11642
11643  
11644 /**
11645  * @class Roo.UpdateManager
11646  * @extends Roo.util.Observable
11647  * Provides AJAX-style update for Element object.<br><br>
11648  * Usage:<br>
11649  * <pre><code>
11650  * // Get it from a Roo.Element object
11651  * var el = Roo.get("foo");
11652  * var mgr = el.getUpdateManager();
11653  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11654  * ...
11655  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11656  * <br>
11657  * // or directly (returns the same UpdateManager instance)
11658  * var mgr = new Roo.UpdateManager("myElementId");
11659  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11660  * mgr.on("update", myFcnNeedsToKnow);
11661  * <br>
11662    // short handed call directly from the element object
11663    Roo.get("foo").load({
11664         url: "bar.php",
11665         scripts:true,
11666         params: "for=bar",
11667         text: "Loading Foo..."
11668    });
11669  * </code></pre>
11670  * @constructor
11671  * Create new UpdateManager directly.
11672  * @param {String/HTMLElement/Roo.Element} el The element to update
11673  * @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).
11674  */
11675 Roo.UpdateManager = function(el, forceNew){
11676     el = Roo.get(el);
11677     if(!forceNew && el.updateManager){
11678         return el.updateManager;
11679     }
11680     /**
11681      * The Element object
11682      * @type Roo.Element
11683      */
11684     this.el = el;
11685     /**
11686      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11687      * @type String
11688      */
11689     this.defaultUrl = null;
11690
11691     this.addEvents({
11692         /**
11693          * @event beforeupdate
11694          * Fired before an update is made, return false from your handler and the update is cancelled.
11695          * @param {Roo.Element} el
11696          * @param {String/Object/Function} url
11697          * @param {String/Object} params
11698          */
11699         "beforeupdate": true,
11700         /**
11701          * @event update
11702          * Fired after successful update is made.
11703          * @param {Roo.Element} el
11704          * @param {Object} oResponseObject The response Object
11705          */
11706         "update": true,
11707         /**
11708          * @event failure
11709          * Fired on update failure.
11710          * @param {Roo.Element} el
11711          * @param {Object} oResponseObject The response Object
11712          */
11713         "failure": true
11714     });
11715     var d = Roo.UpdateManager.defaults;
11716     /**
11717      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11718      * @type String
11719      */
11720     this.sslBlankUrl = d.sslBlankUrl;
11721     /**
11722      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11723      * @type Boolean
11724      */
11725     this.disableCaching = d.disableCaching;
11726     /**
11727      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11728      * @type String
11729      */
11730     this.indicatorText = d.indicatorText;
11731     /**
11732      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11733      * @type String
11734      */
11735     this.showLoadIndicator = d.showLoadIndicator;
11736     /**
11737      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11738      * @type Number
11739      */
11740     this.timeout = d.timeout;
11741
11742     /**
11743      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11744      * @type Boolean
11745      */
11746     this.loadScripts = d.loadScripts;
11747
11748     /**
11749      * Transaction object of current executing transaction
11750      */
11751     this.transaction = null;
11752
11753     /**
11754      * @private
11755      */
11756     this.autoRefreshProcId = null;
11757     /**
11758      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11759      * @type Function
11760      */
11761     this.refreshDelegate = this.refresh.createDelegate(this);
11762     /**
11763      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11764      * @type Function
11765      */
11766     this.updateDelegate = this.update.createDelegate(this);
11767     /**
11768      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11769      * @type Function
11770      */
11771     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11772     /**
11773      * @private
11774      */
11775     this.successDelegate = this.processSuccess.createDelegate(this);
11776     /**
11777      * @private
11778      */
11779     this.failureDelegate = this.processFailure.createDelegate(this);
11780
11781     if(!this.renderer){
11782      /**
11783       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11784       */
11785     this.renderer = new Roo.UpdateManager.BasicRenderer();
11786     }
11787     
11788     Roo.UpdateManager.superclass.constructor.call(this);
11789 };
11790
11791 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11792     /**
11793      * Get the Element this UpdateManager is bound to
11794      * @return {Roo.Element} The element
11795      */
11796     getEl : function(){
11797         return this.el;
11798     },
11799     /**
11800      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11801      * @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:
11802 <pre><code>
11803 um.update({<br/>
11804     url: "your-url.php",<br/>
11805     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11806     callback: yourFunction,<br/>
11807     scope: yourObject, //(optional scope)  <br/>
11808     discardUrl: false, <br/>
11809     nocache: false,<br/>
11810     text: "Loading...",<br/>
11811     timeout: 30,<br/>
11812     scripts: false<br/>
11813 });
11814 </code></pre>
11815      * The only required property is url. The optional properties nocache, text and scripts
11816      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11817      * @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}
11818      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11819      * @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.
11820      */
11821     update : function(url, params, callback, discardUrl){
11822         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11823             var method = this.method,
11824                 cfg;
11825             if(typeof url == "object"){ // must be config object
11826                 cfg = url;
11827                 url = cfg.url;
11828                 params = params || cfg.params;
11829                 callback = callback || cfg.callback;
11830                 discardUrl = discardUrl || cfg.discardUrl;
11831                 if(callback && cfg.scope){
11832                     callback = callback.createDelegate(cfg.scope);
11833                 }
11834                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11835                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11836                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11837                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11838                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11839             }
11840             this.showLoading();
11841             if(!discardUrl){
11842                 this.defaultUrl = url;
11843             }
11844             if(typeof url == "function"){
11845                 url = url.call(this);
11846             }
11847
11848             method = method || (params ? "POST" : "GET");
11849             if(method == "GET"){
11850                 url = this.prepareUrl(url);
11851             }
11852
11853             var o = Roo.apply(cfg ||{}, {
11854                 url : url,
11855                 params: params,
11856                 success: this.successDelegate,
11857                 failure: this.failureDelegate,
11858                 callback: undefined,
11859                 timeout: (this.timeout*1000),
11860                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11861             });
11862             Roo.log("updated manager called with timeout of " + o.timeout);
11863             this.transaction = Roo.Ajax.request(o);
11864         }
11865     },
11866
11867     /**
11868      * 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.
11869      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11870      * @param {String/HTMLElement} form The form Id or form element
11871      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11872      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11873      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11874      */
11875     formUpdate : function(form, url, reset, callback){
11876         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11877             if(typeof url == "function"){
11878                 url = url.call(this);
11879             }
11880             form = Roo.getDom(form);
11881             this.transaction = Roo.Ajax.request({
11882                 form: form,
11883                 url:url,
11884                 success: this.successDelegate,
11885                 failure: this.failureDelegate,
11886                 timeout: (this.timeout*1000),
11887                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11888             });
11889             this.showLoading.defer(1, this);
11890         }
11891     },
11892
11893     /**
11894      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11895      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11896      */
11897     refresh : function(callback){
11898         if(this.defaultUrl == null){
11899             return;
11900         }
11901         this.update(this.defaultUrl, null, callback, true);
11902     },
11903
11904     /**
11905      * Set this element to auto refresh.
11906      * @param {Number} interval How often to update (in seconds).
11907      * @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)
11908      * @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}
11909      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11910      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11911      */
11912     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11913         if(refreshNow){
11914             this.update(url || this.defaultUrl, params, callback, true);
11915         }
11916         if(this.autoRefreshProcId){
11917             clearInterval(this.autoRefreshProcId);
11918         }
11919         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11920     },
11921
11922     /**
11923      * Stop auto refresh on this element.
11924      */
11925      stopAutoRefresh : function(){
11926         if(this.autoRefreshProcId){
11927             clearInterval(this.autoRefreshProcId);
11928             delete this.autoRefreshProcId;
11929         }
11930     },
11931
11932     isAutoRefreshing : function(){
11933        return this.autoRefreshProcId ? true : false;
11934     },
11935     /**
11936      * Called to update the element to "Loading" state. Override to perform custom action.
11937      */
11938     showLoading : function(){
11939         if(this.showLoadIndicator){
11940             this.el.update(this.indicatorText);
11941         }
11942     },
11943
11944     /**
11945      * Adds unique parameter to query string if disableCaching = true
11946      * @private
11947      */
11948     prepareUrl : function(url){
11949         if(this.disableCaching){
11950             var append = "_dc=" + (new Date().getTime());
11951             if(url.indexOf("?") !== -1){
11952                 url += "&" + append;
11953             }else{
11954                 url += "?" + append;
11955             }
11956         }
11957         return url;
11958     },
11959
11960     /**
11961      * @private
11962      */
11963     processSuccess : function(response){
11964         this.transaction = null;
11965         if(response.argument.form && response.argument.reset){
11966             try{ // put in try/catch since some older FF releases had problems with this
11967                 response.argument.form.reset();
11968             }catch(e){}
11969         }
11970         if(this.loadScripts){
11971             this.renderer.render(this.el, response, this,
11972                 this.updateComplete.createDelegate(this, [response]));
11973         }else{
11974             this.renderer.render(this.el, response, this);
11975             this.updateComplete(response);
11976         }
11977     },
11978
11979     updateComplete : function(response){
11980         this.fireEvent("update", this.el, response);
11981         if(typeof response.argument.callback == "function"){
11982             response.argument.callback(this.el, true, response);
11983         }
11984     },
11985
11986     /**
11987      * @private
11988      */
11989     processFailure : function(response){
11990         this.transaction = null;
11991         this.fireEvent("failure", this.el, response);
11992         if(typeof response.argument.callback == "function"){
11993             response.argument.callback(this.el, false, response);
11994         }
11995     },
11996
11997     /**
11998      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11999      * @param {Object} renderer The object implementing the render() method
12000      */
12001     setRenderer : function(renderer){
12002         this.renderer = renderer;
12003     },
12004
12005     getRenderer : function(){
12006        return this.renderer;
12007     },
12008
12009     /**
12010      * Set the defaultUrl used for updates
12011      * @param {String/Function} defaultUrl The url or a function to call to get the url
12012      */
12013     setDefaultUrl : function(defaultUrl){
12014         this.defaultUrl = defaultUrl;
12015     },
12016
12017     /**
12018      * Aborts the executing transaction
12019      */
12020     abort : function(){
12021         if(this.transaction){
12022             Roo.Ajax.abort(this.transaction);
12023         }
12024     },
12025
12026     /**
12027      * Returns true if an update is in progress
12028      * @return {Boolean}
12029      */
12030     isUpdating : function(){
12031         if(this.transaction){
12032             return Roo.Ajax.isLoading(this.transaction);
12033         }
12034         return false;
12035     }
12036 });
12037
12038 /**
12039  * @class Roo.UpdateManager.defaults
12040  * @static (not really - but it helps the doc tool)
12041  * The defaults collection enables customizing the default properties of UpdateManager
12042  */
12043    Roo.UpdateManager.defaults = {
12044        /**
12045          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12046          * @type Number
12047          */
12048          timeout : 30,
12049
12050          /**
12051          * True to process scripts by default (Defaults to false).
12052          * @type Boolean
12053          */
12054         loadScripts : false,
12055
12056         /**
12057         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12058         * @type String
12059         */
12060         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12061         /**
12062          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12063          * @type Boolean
12064          */
12065         disableCaching : false,
12066         /**
12067          * Whether to show indicatorText when loading (Defaults to true).
12068          * @type Boolean
12069          */
12070         showLoadIndicator : true,
12071         /**
12072          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12073          * @type String
12074          */
12075         indicatorText : '<div class="loading-indicator">Loading...</div>'
12076    };
12077
12078 /**
12079  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12080  *Usage:
12081  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12082  * @param {String/HTMLElement/Roo.Element} el The element to update
12083  * @param {String} url The url
12084  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12085  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12086  * @static
12087  * @deprecated
12088  * @member Roo.UpdateManager
12089  */
12090 Roo.UpdateManager.updateElement = function(el, url, params, options){
12091     var um = Roo.get(el, true).getUpdateManager();
12092     Roo.apply(um, options);
12093     um.update(url, params, options ? options.callback : null);
12094 };
12095 // alias for backwards compat
12096 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12097 /**
12098  * @class Roo.UpdateManager.BasicRenderer
12099  * Default Content renderer. Updates the elements innerHTML with the responseText.
12100  */
12101 Roo.UpdateManager.BasicRenderer = function(){};
12102
12103 Roo.UpdateManager.BasicRenderer.prototype = {
12104     /**
12105      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12106      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12107      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12108      * @param {Roo.Element} el The element being rendered
12109      * @param {Object} response The YUI Connect response object
12110      * @param {UpdateManager} updateManager The calling update manager
12111      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12112      */
12113      render : function(el, response, updateManager, callback){
12114         el.update(response.responseText, updateManager.loadScripts, callback);
12115     }
12116 };
12117 /*
12118  * Based on:
12119  * Roo JS
12120  * (c)) Alan Knowles
12121  * Licence : LGPL
12122  */
12123
12124
12125 /**
12126  * @class Roo.DomTemplate
12127  * @extends Roo.Template
12128  * An effort at a dom based template engine..
12129  *
12130  * Similar to XTemplate, except it uses dom parsing to create the template..
12131  *
12132  * Supported features:
12133  *
12134  *  Tags:
12135
12136 <pre><code>
12137       {a_variable} - output encoded.
12138       {a_variable.format:("Y-m-d")} - call a method on the variable
12139       {a_variable:raw} - unencoded output
12140       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12141       {a_variable:this.method_on_template(...)} - call a method on the template object.
12142  
12143 </code></pre>
12144  *  The tpl tag:
12145 <pre><code>
12146         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12147         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12148         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12149         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12150   
12151 </code></pre>
12152  *      
12153  */
12154 Roo.DomTemplate = function()
12155 {
12156      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12157      if (this.html) {
12158         this.compile();
12159      }
12160 };
12161
12162
12163 Roo.extend(Roo.DomTemplate, Roo.Template, {
12164     /**
12165      * id counter for sub templates.
12166      */
12167     id : 0,
12168     /**
12169      * flag to indicate if dom parser is inside a pre,
12170      * it will strip whitespace if not.
12171      */
12172     inPre : false,
12173     
12174     /**
12175      * The various sub templates
12176      */
12177     tpls : false,
12178     
12179     
12180     
12181     /**
12182      *
12183      * basic tag replacing syntax
12184      * WORD:WORD()
12185      *
12186      * // you can fake an object call by doing this
12187      *  x.t:(test,tesT) 
12188      * 
12189      */
12190     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12191     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12192     
12193     iterChild : function (node, method) {
12194         
12195         var oldPre = this.inPre;
12196         if (node.tagName == 'PRE') {
12197             this.inPre = true;
12198         }
12199         for( var i = 0; i < node.childNodes.length; i++) {
12200             method.call(this, node.childNodes[i]);
12201         }
12202         this.inPre = oldPre;
12203     },
12204     
12205     
12206     
12207     /**
12208      * compile the template
12209      *
12210      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12211      *
12212      */
12213     compile: function()
12214     {
12215         var s = this.html;
12216         
12217         // covert the html into DOM...
12218         var doc = false;
12219         var div =false;
12220         try {
12221             doc = document.implementation.createHTMLDocument("");
12222             doc.documentElement.innerHTML =   this.html  ;
12223             div = doc.documentElement;
12224         } catch (e) {
12225             // old IE... - nasty -- it causes all sorts of issues.. with
12226             // images getting pulled from server..
12227             div = document.createElement('div');
12228             div.innerHTML = this.html;
12229         }
12230         //doc.documentElement.innerHTML = htmlBody
12231          
12232         
12233         
12234         this.tpls = [];
12235         var _t = this;
12236         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12237         
12238         var tpls = this.tpls;
12239         
12240         // create a top level template from the snippet..
12241         
12242         //Roo.log(div.innerHTML);
12243         
12244         var tpl = {
12245             uid : 'master',
12246             id : this.id++,
12247             attr : false,
12248             value : false,
12249             body : div.innerHTML,
12250             
12251             forCall : false,
12252             execCall : false,
12253             dom : div,
12254             isTop : true
12255             
12256         };
12257         tpls.unshift(tpl);
12258         
12259         
12260         // compile them...
12261         this.tpls = [];
12262         Roo.each(tpls, function(tp){
12263             this.compileTpl(tp);
12264             this.tpls[tp.id] = tp;
12265         }, this);
12266         
12267         this.master = tpls[0];
12268         return this;
12269         
12270         
12271     },
12272     
12273     compileNode : function(node, istop) {
12274         // test for
12275         //Roo.log(node);
12276         
12277         
12278         // skip anything not a tag..
12279         if (node.nodeType != 1) {
12280             if (node.nodeType == 3 && !this.inPre) {
12281                 // reduce white space..
12282                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12283                 
12284             }
12285             return;
12286         }
12287         
12288         var tpl = {
12289             uid : false,
12290             id : false,
12291             attr : false,
12292             value : false,
12293             body : '',
12294             
12295             forCall : false,
12296             execCall : false,
12297             dom : false,
12298             isTop : istop
12299             
12300             
12301         };
12302         
12303         
12304         switch(true) {
12305             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12306             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12307             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12308             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12309             // no default..
12310         }
12311         
12312         
12313         if (!tpl.attr) {
12314             // just itterate children..
12315             this.iterChild(node,this.compileNode);
12316             return;
12317         }
12318         tpl.uid = this.id++;
12319         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12320         node.removeAttribute('roo-'+ tpl.attr);
12321         if (tpl.attr != 'name') {
12322             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12323             node.parentNode.replaceChild(placeholder,  node);
12324         } else {
12325             
12326             var placeholder =  document.createElement('span');
12327             placeholder.className = 'roo-tpl-' + tpl.value;
12328             node.parentNode.replaceChild(placeholder,  node);
12329         }
12330         
12331         // parent now sees '{domtplXXXX}
12332         this.iterChild(node,this.compileNode);
12333         
12334         // we should now have node body...
12335         var div = document.createElement('div');
12336         div.appendChild(node);
12337         tpl.dom = node;
12338         // this has the unfortunate side effect of converting tagged attributes
12339         // eg. href="{...}" into %7C...%7D
12340         // this has been fixed by searching for those combo's although it's a bit hacky..
12341         
12342         
12343         tpl.body = div.innerHTML;
12344         
12345         
12346          
12347         tpl.id = tpl.uid;
12348         switch(tpl.attr) {
12349             case 'for' :
12350                 switch (tpl.value) {
12351                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12352                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12353                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12354                 }
12355                 break;
12356             
12357             case 'exec':
12358                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12359                 break;
12360             
12361             case 'if':     
12362                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12363                 break;
12364             
12365             case 'name':
12366                 tpl.id  = tpl.value; // replace non characters???
12367                 break;
12368             
12369         }
12370         
12371         
12372         this.tpls.push(tpl);
12373         
12374         
12375         
12376     },
12377     
12378     
12379     
12380     
12381     /**
12382      * Compile a segment of the template into a 'sub-template'
12383      *
12384      * 
12385      * 
12386      *
12387      */
12388     compileTpl : function(tpl)
12389     {
12390         var fm = Roo.util.Format;
12391         var useF = this.disableFormats !== true;
12392         
12393         var sep = Roo.isGecko ? "+\n" : ",\n";
12394         
12395         var undef = function(str) {
12396             Roo.debug && Roo.log("Property not found :"  + str);
12397             return '';
12398         };
12399           
12400         //Roo.log(tpl.body);
12401         
12402         
12403         
12404         var fn = function(m, lbrace, name, format, args)
12405         {
12406             //Roo.log("ARGS");
12407             //Roo.log(arguments);
12408             args = args ? args.replace(/\\'/g,"'") : args;
12409             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12410             if (typeof(format) == 'undefined') {
12411                 format =  'htmlEncode'; 
12412             }
12413             if (format == 'raw' ) {
12414                 format = false;
12415             }
12416             
12417             if(name.substr(0, 6) == 'domtpl'){
12418                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12419             }
12420             
12421             // build an array of options to determine if value is undefined..
12422             
12423             // basically get 'xxxx.yyyy' then do
12424             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12425             //    (function () { Roo.log("Property not found"); return ''; })() :
12426             //    ......
12427             
12428             var udef_ar = [];
12429             var lookfor = '';
12430             Roo.each(name.split('.'), function(st) {
12431                 lookfor += (lookfor.length ? '.': '') + st;
12432                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12433             });
12434             
12435             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12436             
12437             
12438             if(format && useF){
12439                 
12440                 args = args ? ',' + args : "";
12441                  
12442                 if(format.substr(0, 5) != "this."){
12443                     format = "fm." + format + '(';
12444                 }else{
12445                     format = 'this.call("'+ format.substr(5) + '", ';
12446                     args = ", values";
12447                 }
12448                 
12449                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12450             }
12451              
12452             if (args && args.length) {
12453                 // called with xxyx.yuu:(test,test)
12454                 // change to ()
12455                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12456             }
12457             // raw.. - :raw modifier..
12458             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12459             
12460         };
12461         var body;
12462         // branched to use + in gecko and [].join() in others
12463         if(Roo.isGecko){
12464             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12465                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12466                     "';};};";
12467         }else{
12468             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12469             body.push(tpl.body.replace(/(\r\n|\n)/g,
12470                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12471             body.push("'].join('');};};");
12472             body = body.join('');
12473         }
12474         
12475         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12476        
12477         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12478         eval(body);
12479         
12480         return this;
12481     },
12482      
12483     /**
12484      * same as applyTemplate, except it's done to one of the subTemplates
12485      * when using named templates, you can do:
12486      *
12487      * var str = pl.applySubTemplate('your-name', values);
12488      *
12489      * 
12490      * @param {Number} id of the template
12491      * @param {Object} values to apply to template
12492      * @param {Object} parent (normaly the instance of this object)
12493      */
12494     applySubTemplate : function(id, values, parent)
12495     {
12496         
12497         
12498         var t = this.tpls[id];
12499         
12500         
12501         try { 
12502             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12503                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12504                 return '';
12505             }
12506         } catch(e) {
12507             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12508             Roo.log(values);
12509           
12510             return '';
12511         }
12512         try { 
12513             
12514             if(t.execCall && t.execCall.call(this, values, parent)){
12515                 return '';
12516             }
12517         } catch(e) {
12518             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12519             Roo.log(values);
12520             return '';
12521         }
12522         
12523         try {
12524             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12525             parent = t.target ? values : parent;
12526             if(t.forCall && vs instanceof Array){
12527                 var buf = [];
12528                 for(var i = 0, len = vs.length; i < len; i++){
12529                     try {
12530                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12531                     } catch (e) {
12532                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12533                         Roo.log(e.body);
12534                         //Roo.log(t.compiled);
12535                         Roo.log(vs[i]);
12536                     }   
12537                 }
12538                 return buf.join('');
12539             }
12540         } catch (e) {
12541             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12542             Roo.log(values);
12543             return '';
12544         }
12545         try {
12546             return t.compiled.call(this, vs, parent);
12547         } catch (e) {
12548             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12549             Roo.log(e.body);
12550             //Roo.log(t.compiled);
12551             Roo.log(values);
12552             return '';
12553         }
12554     },
12555
12556    
12557
12558     applyTemplate : function(values){
12559         return this.master.compiled.call(this, values, {});
12560         //var s = this.subs;
12561     },
12562
12563     apply : function(){
12564         return this.applyTemplate.apply(this, arguments);
12565     }
12566
12567  });
12568
12569 Roo.DomTemplate.from = function(el){
12570     el = Roo.getDom(el);
12571     return new Roo.Domtemplate(el.value || el.innerHTML);
12572 };/*
12573  * Based on:
12574  * Ext JS Library 1.1.1
12575  * Copyright(c) 2006-2007, Ext JS, LLC.
12576  *
12577  * Originally Released Under LGPL - original licence link has changed is not relivant.
12578  *
12579  * Fork - LGPL
12580  * <script type="text/javascript">
12581  */
12582
12583 /**
12584  * @class Roo.util.DelayedTask
12585  * Provides a convenient method of performing setTimeout where a new
12586  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12587  * You can use this class to buffer
12588  * the keypress events for a certain number of milliseconds, and perform only if they stop
12589  * for that amount of time.
12590  * @constructor The parameters to this constructor serve as defaults and are not required.
12591  * @param {Function} fn (optional) The default function to timeout
12592  * @param {Object} scope (optional) The default scope of that timeout
12593  * @param {Array} args (optional) The default Array of arguments
12594  */
12595 Roo.util.DelayedTask = function(fn, scope, args){
12596     var id = null, d, t;
12597
12598     var call = function(){
12599         var now = new Date().getTime();
12600         if(now - t >= d){
12601             clearInterval(id);
12602             id = null;
12603             fn.apply(scope, args || []);
12604         }
12605     };
12606     /**
12607      * Cancels any pending timeout and queues a new one
12608      * @param {Number} delay The milliseconds to delay
12609      * @param {Function} newFn (optional) Overrides function passed to constructor
12610      * @param {Object} newScope (optional) Overrides scope passed to constructor
12611      * @param {Array} newArgs (optional) Overrides args passed to constructor
12612      */
12613     this.delay = function(delay, newFn, newScope, newArgs){
12614         if(id && delay != d){
12615             this.cancel();
12616         }
12617         d = delay;
12618         t = new Date().getTime();
12619         fn = newFn || fn;
12620         scope = newScope || scope;
12621         args = newArgs || args;
12622         if(!id){
12623             id = setInterval(call, d);
12624         }
12625     };
12626
12627     /**
12628      * Cancel the last queued timeout
12629      */
12630     this.cancel = function(){
12631         if(id){
12632             clearInterval(id);
12633             id = null;
12634         }
12635     };
12636 };/*
12637  * Based on:
12638  * Ext JS Library 1.1.1
12639  * Copyright(c) 2006-2007, Ext JS, LLC.
12640  *
12641  * Originally Released Under LGPL - original licence link has changed is not relivant.
12642  *
12643  * Fork - LGPL
12644  * <script type="text/javascript">
12645  */
12646  
12647  
12648 Roo.util.TaskRunner = function(interval){
12649     interval = interval || 10;
12650     var tasks = [], removeQueue = [];
12651     var id = 0;
12652     var running = false;
12653
12654     var stopThread = function(){
12655         running = false;
12656         clearInterval(id);
12657         id = 0;
12658     };
12659
12660     var startThread = function(){
12661         if(!running){
12662             running = true;
12663             id = setInterval(runTasks, interval);
12664         }
12665     };
12666
12667     var removeTask = function(task){
12668         removeQueue.push(task);
12669         if(task.onStop){
12670             task.onStop();
12671         }
12672     };
12673
12674     var runTasks = function(){
12675         if(removeQueue.length > 0){
12676             for(var i = 0, len = removeQueue.length; i < len; i++){
12677                 tasks.remove(removeQueue[i]);
12678             }
12679             removeQueue = [];
12680             if(tasks.length < 1){
12681                 stopThread();
12682                 return;
12683             }
12684         }
12685         var now = new Date().getTime();
12686         for(var i = 0, len = tasks.length; i < len; ++i){
12687             var t = tasks[i];
12688             var itime = now - t.taskRunTime;
12689             if(t.interval <= itime){
12690                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12691                 t.taskRunTime = now;
12692                 if(rt === false || t.taskRunCount === t.repeat){
12693                     removeTask(t);
12694                     return;
12695                 }
12696             }
12697             if(t.duration && t.duration <= (now - t.taskStartTime)){
12698                 removeTask(t);
12699             }
12700         }
12701     };
12702
12703     /**
12704      * Queues a new task.
12705      * @param {Object} task
12706      */
12707     this.start = function(task){
12708         tasks.push(task);
12709         task.taskStartTime = new Date().getTime();
12710         task.taskRunTime = 0;
12711         task.taskRunCount = 0;
12712         startThread();
12713         return task;
12714     };
12715
12716     this.stop = function(task){
12717         removeTask(task);
12718         return task;
12719     };
12720
12721     this.stopAll = function(){
12722         stopThread();
12723         for(var i = 0, len = tasks.length; i < len; i++){
12724             if(tasks[i].onStop){
12725                 tasks[i].onStop();
12726             }
12727         }
12728         tasks = [];
12729         removeQueue = [];
12730     };
12731 };
12732
12733 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12734  * Based on:
12735  * Ext JS Library 1.1.1
12736  * Copyright(c) 2006-2007, Ext JS, LLC.
12737  *
12738  * Originally Released Under LGPL - original licence link has changed is not relivant.
12739  *
12740  * Fork - LGPL
12741  * <script type="text/javascript">
12742  */
12743
12744  
12745 /**
12746  * @class Roo.util.MixedCollection
12747  * @extends Roo.util.Observable
12748  * A Collection class that maintains both numeric indexes and keys and exposes events.
12749  * @constructor
12750  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12751  * collection (defaults to false)
12752  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12753  * and return the key value for that item.  This is used when available to look up the key on items that
12754  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12755  * equivalent to providing an implementation for the {@link #getKey} method.
12756  */
12757 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12758     this.items = [];
12759     this.map = {};
12760     this.keys = [];
12761     this.length = 0;
12762     this.addEvents({
12763         /**
12764          * @event clear
12765          * Fires when the collection is cleared.
12766          */
12767         "clear" : true,
12768         /**
12769          * @event add
12770          * Fires when an item is added to the collection.
12771          * @param {Number} index The index at which the item was added.
12772          * @param {Object} o The item added.
12773          * @param {String} key The key associated with the added item.
12774          */
12775         "add" : true,
12776         /**
12777          * @event replace
12778          * Fires when an item is replaced in the collection.
12779          * @param {String} key he key associated with the new added.
12780          * @param {Object} old The item being replaced.
12781          * @param {Object} new The new item.
12782          */
12783         "replace" : true,
12784         /**
12785          * @event remove
12786          * Fires when an item is removed from the collection.
12787          * @param {Object} o The item being removed.
12788          * @param {String} key (optional) The key associated with the removed item.
12789          */
12790         "remove" : true,
12791         "sort" : true
12792     });
12793     this.allowFunctions = allowFunctions === true;
12794     if(keyFn){
12795         this.getKey = keyFn;
12796     }
12797     Roo.util.MixedCollection.superclass.constructor.call(this);
12798 };
12799
12800 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12801     allowFunctions : false,
12802     
12803 /**
12804  * Adds an item to the collection.
12805  * @param {String} key The key to associate with the item
12806  * @param {Object} o The item to add.
12807  * @return {Object} The item added.
12808  */
12809     add : function(key, o){
12810         if(arguments.length == 1){
12811             o = arguments[0];
12812             key = this.getKey(o);
12813         }
12814         if(typeof key == "undefined" || key === null){
12815             this.length++;
12816             this.items.push(o);
12817             this.keys.push(null);
12818         }else{
12819             var old = this.map[key];
12820             if(old){
12821                 return this.replace(key, o);
12822             }
12823             this.length++;
12824             this.items.push(o);
12825             this.map[key] = o;
12826             this.keys.push(key);
12827         }
12828         this.fireEvent("add", this.length-1, o, key);
12829         return o;
12830     },
12831        
12832 /**
12833   * MixedCollection has a generic way to fetch keys if you implement getKey.
12834 <pre><code>
12835 // normal way
12836 var mc = new Roo.util.MixedCollection();
12837 mc.add(someEl.dom.id, someEl);
12838 mc.add(otherEl.dom.id, otherEl);
12839 //and so on
12840
12841 // using getKey
12842 var mc = new Roo.util.MixedCollection();
12843 mc.getKey = function(el){
12844    return el.dom.id;
12845 };
12846 mc.add(someEl);
12847 mc.add(otherEl);
12848
12849 // or via the constructor
12850 var mc = new Roo.util.MixedCollection(false, function(el){
12851    return el.dom.id;
12852 });
12853 mc.add(someEl);
12854 mc.add(otherEl);
12855 </code></pre>
12856  * @param o {Object} The item for which to find the key.
12857  * @return {Object} The key for the passed item.
12858  */
12859     getKey : function(o){
12860          return o.id; 
12861     },
12862    
12863 /**
12864  * Replaces an item in the collection.
12865  * @param {String} key The key associated with the item to replace, or the item to replace.
12866  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12867  * @return {Object}  The new item.
12868  */
12869     replace : function(key, o){
12870         if(arguments.length == 1){
12871             o = arguments[0];
12872             key = this.getKey(o);
12873         }
12874         var old = this.item(key);
12875         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12876              return this.add(key, o);
12877         }
12878         var index = this.indexOfKey(key);
12879         this.items[index] = o;
12880         this.map[key] = o;
12881         this.fireEvent("replace", key, old, o);
12882         return o;
12883     },
12884    
12885 /**
12886  * Adds all elements of an Array or an Object to the collection.
12887  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12888  * an Array of values, each of which are added to the collection.
12889  */
12890     addAll : function(objs){
12891         if(arguments.length > 1 || objs instanceof Array){
12892             var args = arguments.length > 1 ? arguments : objs;
12893             for(var i = 0, len = args.length; i < len; i++){
12894                 this.add(args[i]);
12895             }
12896         }else{
12897             for(var key in objs){
12898                 if(this.allowFunctions || typeof objs[key] != "function"){
12899                     this.add(key, objs[key]);
12900                 }
12901             }
12902         }
12903     },
12904    
12905 /**
12906  * Executes the specified function once for every item in the collection, passing each
12907  * item as the first and only parameter. returning false from the function will stop the iteration.
12908  * @param {Function} fn The function to execute for each item.
12909  * @param {Object} scope (optional) The scope in which to execute the function.
12910  */
12911     each : function(fn, scope){
12912         var items = [].concat(this.items); // each safe for removal
12913         for(var i = 0, len = items.length; i < len; i++){
12914             if(fn.call(scope || items[i], items[i], i, len) === false){
12915                 break;
12916             }
12917         }
12918     },
12919    
12920 /**
12921  * Executes the specified function once for every key in the collection, passing each
12922  * key, and its associated item as the first two parameters.
12923  * @param {Function} fn The function to execute for each item.
12924  * @param {Object} scope (optional) The scope in which to execute the function.
12925  */
12926     eachKey : function(fn, scope){
12927         for(var i = 0, len = this.keys.length; i < len; i++){
12928             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12929         }
12930     },
12931    
12932 /**
12933  * Returns the first item in the collection which elicits a true return value from the
12934  * passed selection function.
12935  * @param {Function} fn The selection function to execute for each item.
12936  * @param {Object} scope (optional) The scope in which to execute the function.
12937  * @return {Object} The first item in the collection which returned true from the selection function.
12938  */
12939     find : function(fn, scope){
12940         for(var i = 0, len = this.items.length; i < len; i++){
12941             if(fn.call(scope || window, this.items[i], this.keys[i])){
12942                 return this.items[i];
12943             }
12944         }
12945         return null;
12946     },
12947    
12948 /**
12949  * Inserts an item at the specified index in the collection.
12950  * @param {Number} index The index to insert the item at.
12951  * @param {String} key The key to associate with the new item, or the item itself.
12952  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12953  * @return {Object} The item inserted.
12954  */
12955     insert : function(index, key, o){
12956         if(arguments.length == 2){
12957             o = arguments[1];
12958             key = this.getKey(o);
12959         }
12960         if(index >= this.length){
12961             return this.add(key, o);
12962         }
12963         this.length++;
12964         this.items.splice(index, 0, o);
12965         if(typeof key != "undefined" && key != null){
12966             this.map[key] = o;
12967         }
12968         this.keys.splice(index, 0, key);
12969         this.fireEvent("add", index, o, key);
12970         return o;
12971     },
12972    
12973 /**
12974  * Removed an item from the collection.
12975  * @param {Object} o The item to remove.
12976  * @return {Object} The item removed.
12977  */
12978     remove : function(o){
12979         return this.removeAt(this.indexOf(o));
12980     },
12981    
12982 /**
12983  * Remove an item from a specified index in the collection.
12984  * @param {Number} index The index within the collection of the item to remove.
12985  */
12986     removeAt : function(index){
12987         if(index < this.length && index >= 0){
12988             this.length--;
12989             var o = this.items[index];
12990             this.items.splice(index, 1);
12991             var key = this.keys[index];
12992             if(typeof key != "undefined"){
12993                 delete this.map[key];
12994             }
12995             this.keys.splice(index, 1);
12996             this.fireEvent("remove", o, key);
12997         }
12998     },
12999    
13000 /**
13001  * Removed an item associated with the passed key fom the collection.
13002  * @param {String} key The key of the item to remove.
13003  */
13004     removeKey : function(key){
13005         return this.removeAt(this.indexOfKey(key));
13006     },
13007    
13008 /**
13009  * Returns the number of items in the collection.
13010  * @return {Number} the number of items in the collection.
13011  */
13012     getCount : function(){
13013         return this.length; 
13014     },
13015    
13016 /**
13017  * Returns index within the collection of the passed Object.
13018  * @param {Object} o The item to find the index of.
13019  * @return {Number} index of the item.
13020  */
13021     indexOf : function(o){
13022         if(!this.items.indexOf){
13023             for(var i = 0, len = this.items.length; i < len; i++){
13024                 if(this.items[i] == o) return i;
13025             }
13026             return -1;
13027         }else{
13028             return this.items.indexOf(o);
13029         }
13030     },
13031    
13032 /**
13033  * Returns index within the collection of the passed key.
13034  * @param {String} key The key to find the index of.
13035  * @return {Number} index of the key.
13036  */
13037     indexOfKey : function(key){
13038         if(!this.keys.indexOf){
13039             for(var i = 0, len = this.keys.length; i < len; i++){
13040                 if(this.keys[i] == key) return i;
13041             }
13042             return -1;
13043         }else{
13044             return this.keys.indexOf(key);
13045         }
13046     },
13047    
13048 /**
13049  * Returns the item associated with the passed key OR index. Key has priority over index.
13050  * @param {String/Number} key The key or index of the item.
13051  * @return {Object} The item associated with the passed key.
13052  */
13053     item : function(key){
13054         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13055         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13056     },
13057     
13058 /**
13059  * Returns the item at the specified index.
13060  * @param {Number} index The index of the item.
13061  * @return {Object}
13062  */
13063     itemAt : function(index){
13064         return this.items[index];
13065     },
13066     
13067 /**
13068  * Returns the item associated with the passed key.
13069  * @param {String/Number} key The key of the item.
13070  * @return {Object} The item associated with the passed key.
13071  */
13072     key : function(key){
13073         return this.map[key];
13074     },
13075    
13076 /**
13077  * Returns true if the collection contains the passed Object as an item.
13078  * @param {Object} o  The Object to look for in the collection.
13079  * @return {Boolean} True if the collection contains the Object as an item.
13080  */
13081     contains : function(o){
13082         return this.indexOf(o) != -1;
13083     },
13084    
13085 /**
13086  * Returns true if the collection contains the passed Object as a key.
13087  * @param {String} key The key to look for in the collection.
13088  * @return {Boolean} True if the collection contains the Object as a key.
13089  */
13090     containsKey : function(key){
13091         return typeof this.map[key] != "undefined";
13092     },
13093    
13094 /**
13095  * Removes all items from the collection.
13096  */
13097     clear : function(){
13098         this.length = 0;
13099         this.items = [];
13100         this.keys = [];
13101         this.map = {};
13102         this.fireEvent("clear");
13103     },
13104    
13105 /**
13106  * Returns the first item in the collection.
13107  * @return {Object} the first item in the collection..
13108  */
13109     first : function(){
13110         return this.items[0]; 
13111     },
13112    
13113 /**
13114  * Returns the last item in the collection.
13115  * @return {Object} the last item in the collection..
13116  */
13117     last : function(){
13118         return this.items[this.length-1];   
13119     },
13120     
13121     _sort : function(property, dir, fn){
13122         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13123         fn = fn || function(a, b){
13124             return a-b;
13125         };
13126         var c = [], k = this.keys, items = this.items;
13127         for(var i = 0, len = items.length; i < len; i++){
13128             c[c.length] = {key: k[i], value: items[i], index: i};
13129         }
13130         c.sort(function(a, b){
13131             var v = fn(a[property], b[property]) * dsc;
13132             if(v == 0){
13133                 v = (a.index < b.index ? -1 : 1);
13134             }
13135             return v;
13136         });
13137         for(var i = 0, len = c.length; i < len; i++){
13138             items[i] = c[i].value;
13139             k[i] = c[i].key;
13140         }
13141         this.fireEvent("sort", this);
13142     },
13143     
13144     /**
13145      * Sorts this collection with the passed comparison function
13146      * @param {String} direction (optional) "ASC" or "DESC"
13147      * @param {Function} fn (optional) comparison function
13148      */
13149     sort : function(dir, fn){
13150         this._sort("value", dir, fn);
13151     },
13152     
13153     /**
13154      * Sorts this collection by keys
13155      * @param {String} direction (optional) "ASC" or "DESC"
13156      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13157      */
13158     keySort : function(dir, fn){
13159         this._sort("key", dir, fn || function(a, b){
13160             return String(a).toUpperCase()-String(b).toUpperCase();
13161         });
13162     },
13163     
13164     /**
13165      * Returns a range of items in this collection
13166      * @param {Number} startIndex (optional) defaults to 0
13167      * @param {Number} endIndex (optional) default to the last item
13168      * @return {Array} An array of items
13169      */
13170     getRange : function(start, end){
13171         var items = this.items;
13172         if(items.length < 1){
13173             return [];
13174         }
13175         start = start || 0;
13176         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13177         var r = [];
13178         if(start <= end){
13179             for(var i = start; i <= end; i++) {
13180                     r[r.length] = items[i];
13181             }
13182         }else{
13183             for(var i = start; i >= end; i--) {
13184                     r[r.length] = items[i];
13185             }
13186         }
13187         return r;
13188     },
13189         
13190     /**
13191      * Filter the <i>objects</i> in this collection by a specific property. 
13192      * Returns a new collection that has been filtered.
13193      * @param {String} property A property on your objects
13194      * @param {String/RegExp} value Either string that the property values 
13195      * should start with or a RegExp to test against the property
13196      * @return {MixedCollection} The new filtered collection
13197      */
13198     filter : function(property, value){
13199         if(!value.exec){ // not a regex
13200             value = String(value);
13201             if(value.length == 0){
13202                 return this.clone();
13203             }
13204             value = new RegExp("^" + Roo.escapeRe(value), "i");
13205         }
13206         return this.filterBy(function(o){
13207             return o && value.test(o[property]);
13208         });
13209         },
13210     
13211     /**
13212      * Filter by a function. * Returns a new collection that has been filtered.
13213      * The passed function will be called with each 
13214      * object in the collection. If the function returns true, the value is included 
13215      * otherwise it is filtered.
13216      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13217      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13218      * @return {MixedCollection} The new filtered collection
13219      */
13220     filterBy : function(fn, scope){
13221         var r = new Roo.util.MixedCollection();
13222         r.getKey = this.getKey;
13223         var k = this.keys, it = this.items;
13224         for(var i = 0, len = it.length; i < len; i++){
13225             if(fn.call(scope||this, it[i], k[i])){
13226                                 r.add(k[i], it[i]);
13227                         }
13228         }
13229         return r;
13230     },
13231     
13232     /**
13233      * Creates a duplicate of this collection
13234      * @return {MixedCollection}
13235      */
13236     clone : function(){
13237         var r = new Roo.util.MixedCollection();
13238         var k = this.keys, it = this.items;
13239         for(var i = 0, len = it.length; i < len; i++){
13240             r.add(k[i], it[i]);
13241         }
13242         r.getKey = this.getKey;
13243         return r;
13244     }
13245 });
13246 /**
13247  * Returns the item associated with the passed key or index.
13248  * @method
13249  * @param {String/Number} key The key or index of the item.
13250  * @return {Object} The item associated with the passed key.
13251  */
13252 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13253  * Based on:
13254  * Ext JS Library 1.1.1
13255  * Copyright(c) 2006-2007, Ext JS, LLC.
13256  *
13257  * Originally Released Under LGPL - original licence link has changed is not relivant.
13258  *
13259  * Fork - LGPL
13260  * <script type="text/javascript">
13261  */
13262 /**
13263  * @class Roo.util.JSON
13264  * Modified version of Douglas Crockford"s json.js that doesn"t
13265  * mess with the Object prototype 
13266  * http://www.json.org/js.html
13267  * @singleton
13268  */
13269 Roo.util.JSON = new (function(){
13270     var useHasOwn = {}.hasOwnProperty ? true : false;
13271     
13272     // crashes Safari in some instances
13273     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13274     
13275     var pad = function(n) {
13276         return n < 10 ? "0" + n : n;
13277     };
13278     
13279     var m = {
13280         "\b": '\\b',
13281         "\t": '\\t',
13282         "\n": '\\n',
13283         "\f": '\\f',
13284         "\r": '\\r',
13285         '"' : '\\"',
13286         "\\": '\\\\'
13287     };
13288
13289     var encodeString = function(s){
13290         if (/["\\\x00-\x1f]/.test(s)) {
13291             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13292                 var c = m[b];
13293                 if(c){
13294                     return c;
13295                 }
13296                 c = b.charCodeAt();
13297                 return "\\u00" +
13298                     Math.floor(c / 16).toString(16) +
13299                     (c % 16).toString(16);
13300             }) + '"';
13301         }
13302         return '"' + s + '"';
13303     };
13304     
13305     var encodeArray = function(o){
13306         var a = ["["], b, i, l = o.length, v;
13307             for (i = 0; i < l; i += 1) {
13308                 v = o[i];
13309                 switch (typeof v) {
13310                     case "undefined":
13311                     case "function":
13312                     case "unknown":
13313                         break;
13314                     default:
13315                         if (b) {
13316                             a.push(',');
13317                         }
13318                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13319                         b = true;
13320                 }
13321             }
13322             a.push("]");
13323             return a.join("");
13324     };
13325     
13326     var encodeDate = function(o){
13327         return '"' + o.getFullYear() + "-" +
13328                 pad(o.getMonth() + 1) + "-" +
13329                 pad(o.getDate()) + "T" +
13330                 pad(o.getHours()) + ":" +
13331                 pad(o.getMinutes()) + ":" +
13332                 pad(o.getSeconds()) + '"';
13333     };
13334     
13335     /**
13336      * Encodes an Object, Array or other value
13337      * @param {Mixed} o The variable to encode
13338      * @return {String} The JSON string
13339      */
13340     this.encode = function(o)
13341     {
13342         // should this be extended to fully wrap stringify..
13343         
13344         if(typeof o == "undefined" || o === null){
13345             return "null";
13346         }else if(o instanceof Array){
13347             return encodeArray(o);
13348         }else if(o instanceof Date){
13349             return encodeDate(o);
13350         }else if(typeof o == "string"){
13351             return encodeString(o);
13352         }else if(typeof o == "number"){
13353             return isFinite(o) ? String(o) : "null";
13354         }else if(typeof o == "boolean"){
13355             return String(o);
13356         }else {
13357             var a = ["{"], b, i, v;
13358             for (i in o) {
13359                 if(!useHasOwn || o.hasOwnProperty(i)) {
13360                     v = o[i];
13361                     switch (typeof v) {
13362                     case "undefined":
13363                     case "function":
13364                     case "unknown":
13365                         break;
13366                     default:
13367                         if(b){
13368                             a.push(',');
13369                         }
13370                         a.push(this.encode(i), ":",
13371                                 v === null ? "null" : this.encode(v));
13372                         b = true;
13373                     }
13374                 }
13375             }
13376             a.push("}");
13377             return a.join("");
13378         }
13379     };
13380     
13381     /**
13382      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13383      * @param {String} json The JSON string
13384      * @return {Object} The resulting object
13385      */
13386     this.decode = function(json){
13387         
13388         return  /** eval:var:json */ eval("(" + json + ')');
13389     };
13390 })();
13391 /** 
13392  * Shorthand for {@link Roo.util.JSON#encode}
13393  * @member Roo encode 
13394  * @method */
13395 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13396 /** 
13397  * Shorthand for {@link Roo.util.JSON#decode}
13398  * @member Roo decode 
13399  * @method */
13400 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13401 /*
13402  * Based on:
13403  * Ext JS Library 1.1.1
13404  * Copyright(c) 2006-2007, Ext JS, LLC.
13405  *
13406  * Originally Released Under LGPL - original licence link has changed is not relivant.
13407  *
13408  * Fork - LGPL
13409  * <script type="text/javascript">
13410  */
13411  
13412 /**
13413  * @class Roo.util.Format
13414  * Reusable data formatting functions
13415  * @singleton
13416  */
13417 Roo.util.Format = function(){
13418     var trimRe = /^\s+|\s+$/g;
13419     return {
13420         /**
13421          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13422          * @param {String} value The string to truncate
13423          * @param {Number} length The maximum length to allow before truncating
13424          * @return {String} The converted text
13425          */
13426         ellipsis : function(value, len){
13427             if(value && value.length > len){
13428                 return value.substr(0, len-3)+"...";
13429             }
13430             return value;
13431         },
13432
13433         /**
13434          * Checks a reference and converts it to empty string if it is undefined
13435          * @param {Mixed} value Reference to check
13436          * @return {Mixed} Empty string if converted, otherwise the original value
13437          */
13438         undef : function(value){
13439             return typeof value != "undefined" ? value : "";
13440         },
13441
13442         /**
13443          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13444          * @param {String} value The string to encode
13445          * @return {String} The encoded text
13446          */
13447         htmlEncode : function(value){
13448             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13449         },
13450
13451         /**
13452          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13453          * @param {String} value The string to decode
13454          * @return {String} The decoded text
13455          */
13456         htmlDecode : function(value){
13457             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13458         },
13459
13460         /**
13461          * Trims any whitespace from either side of a string
13462          * @param {String} value The text to trim
13463          * @return {String} The trimmed text
13464          */
13465         trim : function(value){
13466             return String(value).replace(trimRe, "");
13467         },
13468
13469         /**
13470          * Returns a substring from within an original string
13471          * @param {String} value The original text
13472          * @param {Number} start The start index of the substring
13473          * @param {Number} length The length of the substring
13474          * @return {String} The substring
13475          */
13476         substr : function(value, start, length){
13477             return String(value).substr(start, length);
13478         },
13479
13480         /**
13481          * Converts a string to all lower case letters
13482          * @param {String} value The text to convert
13483          * @return {String} The converted text
13484          */
13485         lowercase : function(value){
13486             return String(value).toLowerCase();
13487         },
13488
13489         /**
13490          * Converts a string to all upper case letters
13491          * @param {String} value The text to convert
13492          * @return {String} The converted text
13493          */
13494         uppercase : function(value){
13495             return String(value).toUpperCase();
13496         },
13497
13498         /**
13499          * Converts the first character only of a string to upper case
13500          * @param {String} value The text to convert
13501          * @return {String} The converted text
13502          */
13503         capitalize : function(value){
13504             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13505         },
13506
13507         // private
13508         call : function(value, fn){
13509             if(arguments.length > 2){
13510                 var args = Array.prototype.slice.call(arguments, 2);
13511                 args.unshift(value);
13512                  
13513                 return /** eval:var:value */  eval(fn).apply(window, args);
13514             }else{
13515                 /** eval:var:value */
13516                 return /** eval:var:value */ eval(fn).call(window, value);
13517             }
13518         },
13519
13520        
13521         /**
13522          * safer version of Math.toFixed..??/
13523          * @param {Number/String} value The numeric value to format
13524          * @param {Number/String} value Decimal places 
13525          * @return {String} The formatted currency string
13526          */
13527         toFixed : function(v, n)
13528         {
13529             // why not use to fixed - precision is buggered???
13530             if (!n) {
13531                 return Math.round(v-0);
13532             }
13533             var fact = Math.pow(10,n+1);
13534             v = (Math.round((v-0)*fact))/fact;
13535             var z = (''+fact).substring(2);
13536             if (v == Math.floor(v)) {
13537                 return Math.floor(v) + '.' + z;
13538             }
13539             
13540             // now just padd decimals..
13541             var ps = String(v).split('.');
13542             var fd = (ps[1] + z);
13543             var r = fd.substring(0,n); 
13544             var rm = fd.substring(n); 
13545             if (rm < 5) {
13546                 return ps[0] + '.' + r;
13547             }
13548             r*=1; // turn it into a number;
13549             r++;
13550             if (String(r).length != n) {
13551                 ps[0]*=1;
13552                 ps[0]++;
13553                 r = String(r).substring(1); // chop the end off.
13554             }
13555             
13556             return ps[0] + '.' + r;
13557              
13558         },
13559         
13560         /**
13561          * Format a number as US currency
13562          * @param {Number/String} value The numeric value to format
13563          * @return {String} The formatted currency string
13564          */
13565         usMoney : function(v){
13566             return '$' + Roo.util.Format.number(v);
13567         },
13568         
13569         /**
13570          * Format a number
13571          * eventually this should probably emulate php's number_format
13572          * @param {Number/String} value The numeric value to format
13573          * @param {Number} decimals number of decimal places
13574          * @return {String} The formatted currency string
13575          */
13576         number : function(v,decimals)
13577         {
13578             // multiply and round.
13579             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13580             var mul = Math.pow(10, decimals);
13581             var zero = String(mul).substring(1);
13582             v = (Math.round((v-0)*mul))/mul;
13583             
13584             // if it's '0' number.. then
13585             
13586             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13587             v = String(v);
13588             var ps = v.split('.');
13589             var whole = ps[0];
13590             
13591             
13592             var r = /(\d+)(\d{3})/;
13593             // add comma's
13594             while (r.test(whole)) {
13595                 whole = whole.replace(r, '$1' + ',' + '$2');
13596             }
13597             
13598             
13599             var sub = ps[1] ?
13600                     // has decimals..
13601                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13602                     // does not have decimals
13603                     (decimals ? ('.' + zero) : '');
13604             
13605             
13606             return whole + sub ;
13607         },
13608         
13609         /**
13610          * Parse a value into a formatted date using the specified format pattern.
13611          * @param {Mixed} value The value to format
13612          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13613          * @return {String} The formatted date string
13614          */
13615         date : function(v, format){
13616             if(!v){
13617                 return "";
13618             }
13619             if(!(v instanceof Date)){
13620                 v = new Date(Date.parse(v));
13621             }
13622             return v.dateFormat(format || Roo.util.Format.defaults.date);
13623         },
13624
13625         /**
13626          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13627          * @param {String} format Any valid date format string
13628          * @return {Function} The date formatting function
13629          */
13630         dateRenderer : function(format){
13631             return function(v){
13632                 return Roo.util.Format.date(v, format);  
13633             };
13634         },
13635
13636         // private
13637         stripTagsRE : /<\/?[^>]+>/gi,
13638         
13639         /**
13640          * Strips all HTML tags
13641          * @param {Mixed} value The text from which to strip tags
13642          * @return {String} The stripped text
13643          */
13644         stripTags : function(v){
13645             return !v ? v : String(v).replace(this.stripTagsRE, "");
13646         }
13647     };
13648 }();
13649 Roo.util.Format.defaults = {
13650     date : 'd/M/Y'
13651 };/*
13652  * Based on:
13653  * Ext JS Library 1.1.1
13654  * Copyright(c) 2006-2007, Ext JS, LLC.
13655  *
13656  * Originally Released Under LGPL - original licence link has changed is not relivant.
13657  *
13658  * Fork - LGPL
13659  * <script type="text/javascript">
13660  */
13661
13662
13663  
13664
13665 /**
13666  * @class Roo.MasterTemplate
13667  * @extends Roo.Template
13668  * Provides a template that can have child templates. The syntax is:
13669 <pre><code>
13670 var t = new Roo.MasterTemplate(
13671         '&lt;select name="{name}"&gt;',
13672                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13673         '&lt;/select&gt;'
13674 );
13675 t.add('options', {value: 'foo', text: 'bar'});
13676 // or you can add multiple child elements in one shot
13677 t.addAll('options', [
13678     {value: 'foo', text: 'bar'},
13679     {value: 'foo2', text: 'bar2'},
13680     {value: 'foo3', text: 'bar3'}
13681 ]);
13682 // then append, applying the master template values
13683 t.append('my-form', {name: 'my-select'});
13684 </code></pre>
13685 * A name attribute for the child template is not required if you have only one child
13686 * template or you want to refer to them by index.
13687  */
13688 Roo.MasterTemplate = function(){
13689     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13690     this.originalHtml = this.html;
13691     var st = {};
13692     var m, re = this.subTemplateRe;
13693     re.lastIndex = 0;
13694     var subIndex = 0;
13695     while(m = re.exec(this.html)){
13696         var name = m[1], content = m[2];
13697         st[subIndex] = {
13698             name: name,
13699             index: subIndex,
13700             buffer: [],
13701             tpl : new Roo.Template(content)
13702         };
13703         if(name){
13704             st[name] = st[subIndex];
13705         }
13706         st[subIndex].tpl.compile();
13707         st[subIndex].tpl.call = this.call.createDelegate(this);
13708         subIndex++;
13709     }
13710     this.subCount = subIndex;
13711     this.subs = st;
13712 };
13713 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13714     /**
13715     * The regular expression used to match sub templates
13716     * @type RegExp
13717     * @property
13718     */
13719     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13720
13721     /**
13722      * Applies the passed values to a child template.
13723      * @param {String/Number} name (optional) The name or index of the child template
13724      * @param {Array/Object} values The values to be applied to the template
13725      * @return {MasterTemplate} this
13726      */
13727      add : function(name, values){
13728         if(arguments.length == 1){
13729             values = arguments[0];
13730             name = 0;
13731         }
13732         var s = this.subs[name];
13733         s.buffer[s.buffer.length] = s.tpl.apply(values);
13734         return this;
13735     },
13736
13737     /**
13738      * Applies all the passed values to a child template.
13739      * @param {String/Number} name (optional) The name or index of the child template
13740      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13741      * @param {Boolean} reset (optional) True to reset the template first
13742      * @return {MasterTemplate} this
13743      */
13744     fill : function(name, values, reset){
13745         var a = arguments;
13746         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13747             values = a[0];
13748             name = 0;
13749             reset = a[1];
13750         }
13751         if(reset){
13752             this.reset();
13753         }
13754         for(var i = 0, len = values.length; i < len; i++){
13755             this.add(name, values[i]);
13756         }
13757         return this;
13758     },
13759
13760     /**
13761      * Resets the template for reuse
13762      * @return {MasterTemplate} this
13763      */
13764      reset : function(){
13765         var s = this.subs;
13766         for(var i = 0; i < this.subCount; i++){
13767             s[i].buffer = [];
13768         }
13769         return this;
13770     },
13771
13772     applyTemplate : function(values){
13773         var s = this.subs;
13774         var replaceIndex = -1;
13775         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13776             return s[++replaceIndex].buffer.join("");
13777         });
13778         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13779     },
13780
13781     apply : function(){
13782         return this.applyTemplate.apply(this, arguments);
13783     },
13784
13785     compile : function(){return this;}
13786 });
13787
13788 /**
13789  * Alias for fill().
13790  * @method
13791  */
13792 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13793  /**
13794  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13795  * var tpl = Roo.MasterTemplate.from('element-id');
13796  * @param {String/HTMLElement} el
13797  * @param {Object} config
13798  * @static
13799  */
13800 Roo.MasterTemplate.from = function(el, config){
13801     el = Roo.getDom(el);
13802     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13803 };/*
13804  * Based on:
13805  * Ext JS Library 1.1.1
13806  * Copyright(c) 2006-2007, Ext JS, LLC.
13807  *
13808  * Originally Released Under LGPL - original licence link has changed is not relivant.
13809  *
13810  * Fork - LGPL
13811  * <script type="text/javascript">
13812  */
13813
13814  
13815 /**
13816  * @class Roo.util.CSS
13817  * Utility class for manipulating CSS rules
13818  * @singleton
13819  */
13820 Roo.util.CSS = function(){
13821         var rules = null;
13822         var doc = document;
13823
13824     var camelRe = /(-[a-z])/gi;
13825     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13826
13827    return {
13828    /**
13829     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13830     * tag and appended to the HEAD of the document.
13831     * @param {String|Object} cssText The text containing the css rules
13832     * @param {String} id An id to add to the stylesheet for later removal
13833     * @return {StyleSheet}
13834     */
13835     createStyleSheet : function(cssText, id){
13836         var ss;
13837         var head = doc.getElementsByTagName("head")[0];
13838         var nrules = doc.createElement("style");
13839         nrules.setAttribute("type", "text/css");
13840         if(id){
13841             nrules.setAttribute("id", id);
13842         }
13843         if (typeof(cssText) != 'string') {
13844             // support object maps..
13845             // not sure if this a good idea.. 
13846             // perhaps it should be merged with the general css handling
13847             // and handle js style props.
13848             var cssTextNew = [];
13849             for(var n in cssText) {
13850                 var citems = [];
13851                 for(var k in cssText[n]) {
13852                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13853                 }
13854                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13855                 
13856             }
13857             cssText = cssTextNew.join("\n");
13858             
13859         }
13860        
13861        
13862        if(Roo.isIE){
13863            head.appendChild(nrules);
13864            ss = nrules.styleSheet;
13865            ss.cssText = cssText;
13866        }else{
13867            try{
13868                 nrules.appendChild(doc.createTextNode(cssText));
13869            }catch(e){
13870                nrules.cssText = cssText; 
13871            }
13872            head.appendChild(nrules);
13873            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13874        }
13875        this.cacheStyleSheet(ss);
13876        return ss;
13877    },
13878
13879    /**
13880     * Removes a style or link tag by id
13881     * @param {String} id The id of the tag
13882     */
13883    removeStyleSheet : function(id){
13884        var existing = doc.getElementById(id);
13885        if(existing){
13886            existing.parentNode.removeChild(existing);
13887        }
13888    },
13889
13890    /**
13891     * Dynamically swaps an existing stylesheet reference for a new one
13892     * @param {String} id The id of an existing link tag to remove
13893     * @param {String} url The href of the new stylesheet to include
13894     */
13895    swapStyleSheet : function(id, url){
13896        this.removeStyleSheet(id);
13897        var ss = doc.createElement("link");
13898        ss.setAttribute("rel", "stylesheet");
13899        ss.setAttribute("type", "text/css");
13900        ss.setAttribute("id", id);
13901        ss.setAttribute("href", url);
13902        doc.getElementsByTagName("head")[0].appendChild(ss);
13903    },
13904    
13905    /**
13906     * Refresh the rule cache if you have dynamically added stylesheets
13907     * @return {Object} An object (hash) of rules indexed by selector
13908     */
13909    refreshCache : function(){
13910        return this.getRules(true);
13911    },
13912
13913    // private
13914    cacheStyleSheet : function(stylesheet){
13915        if(!rules){
13916            rules = {};
13917        }
13918        try{// try catch for cross domain access issue
13919            var ssRules = stylesheet.cssRules || stylesheet.rules;
13920            for(var j = ssRules.length-1; j >= 0; --j){
13921                rules[ssRules[j].selectorText] = ssRules[j];
13922            }
13923        }catch(e){}
13924    },
13925    
13926    /**
13927     * Gets all css rules for the document
13928     * @param {Boolean} refreshCache true to refresh the internal cache
13929     * @return {Object} An object (hash) of rules indexed by selector
13930     */
13931    getRules : function(refreshCache){
13932                 if(rules == null || refreshCache){
13933                         rules = {};
13934                         var ds = doc.styleSheets;
13935                         for(var i =0, len = ds.length; i < len; i++){
13936                             try{
13937                         this.cacheStyleSheet(ds[i]);
13938                     }catch(e){} 
13939                 }
13940                 }
13941                 return rules;
13942         },
13943         
13944         /**
13945     * Gets an an individual CSS rule by selector(s)
13946     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13947     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13948     * @return {CSSRule} The CSS rule or null if one is not found
13949     */
13950    getRule : function(selector, refreshCache){
13951                 var rs = this.getRules(refreshCache);
13952                 if(!(selector instanceof Array)){
13953                     return rs[selector];
13954                 }
13955                 for(var i = 0; i < selector.length; i++){
13956                         if(rs[selector[i]]){
13957                                 return rs[selector[i]];
13958                         }
13959                 }
13960                 return null;
13961         },
13962         
13963         
13964         /**
13965     * Updates a rule property
13966     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13967     * @param {String} property The css property
13968     * @param {String} value The new value for the property
13969     * @return {Boolean} true If a rule was found and updated
13970     */
13971    updateRule : function(selector, property, value){
13972                 if(!(selector instanceof Array)){
13973                         var rule = this.getRule(selector);
13974                         if(rule){
13975                                 rule.style[property.replace(camelRe, camelFn)] = value;
13976                                 return true;
13977                         }
13978                 }else{
13979                         for(var i = 0; i < selector.length; i++){
13980                                 if(this.updateRule(selector[i], property, value)){
13981                                         return true;
13982                                 }
13983                         }
13984                 }
13985                 return false;
13986         }
13987    };   
13988 }();/*
13989  * Based on:
13990  * Ext JS Library 1.1.1
13991  * Copyright(c) 2006-2007, Ext JS, LLC.
13992  *
13993  * Originally Released Under LGPL - original licence link has changed is not relivant.
13994  *
13995  * Fork - LGPL
13996  * <script type="text/javascript">
13997  */
13998
13999  
14000
14001 /**
14002  * @class Roo.util.ClickRepeater
14003  * @extends Roo.util.Observable
14004  * 
14005  * A wrapper class which can be applied to any element. Fires a "click" event while the
14006  * mouse is pressed. The interval between firings may be specified in the config but
14007  * defaults to 10 milliseconds.
14008  * 
14009  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14010  * 
14011  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14012  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14013  * Similar to an autorepeat key delay.
14014  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14015  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14016  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14017  *           "interval" and "delay" are ignored. "immediate" is honored.
14018  * @cfg {Boolean} preventDefault True to prevent the default click event
14019  * @cfg {Boolean} stopDefault True to stop the default click event
14020  * 
14021  * @history
14022  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14023  *     2007-02-02 jvs Renamed to ClickRepeater
14024  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14025  *
14026  *  @constructor
14027  * @param {String/HTMLElement/Element} el The element to listen on
14028  * @param {Object} config
14029  **/
14030 Roo.util.ClickRepeater = function(el, config)
14031 {
14032     this.el = Roo.get(el);
14033     this.el.unselectable();
14034
14035     Roo.apply(this, config);
14036
14037     this.addEvents({
14038     /**
14039      * @event mousedown
14040      * Fires when the mouse button is depressed.
14041      * @param {Roo.util.ClickRepeater} this
14042      */
14043         "mousedown" : true,
14044     /**
14045      * @event click
14046      * Fires on a specified interval during the time the element is pressed.
14047      * @param {Roo.util.ClickRepeater} this
14048      */
14049         "click" : true,
14050     /**
14051      * @event mouseup
14052      * Fires when the mouse key is released.
14053      * @param {Roo.util.ClickRepeater} this
14054      */
14055         "mouseup" : true
14056     });
14057
14058     this.el.on("mousedown", this.handleMouseDown, this);
14059     if(this.preventDefault || this.stopDefault){
14060         this.el.on("click", function(e){
14061             if(this.preventDefault){
14062                 e.preventDefault();
14063             }
14064             if(this.stopDefault){
14065                 e.stopEvent();
14066             }
14067         }, this);
14068     }
14069
14070     // allow inline handler
14071     if(this.handler){
14072         this.on("click", this.handler,  this.scope || this);
14073     }
14074
14075     Roo.util.ClickRepeater.superclass.constructor.call(this);
14076 };
14077
14078 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14079     interval : 20,
14080     delay: 250,
14081     preventDefault : true,
14082     stopDefault : false,
14083     timer : 0,
14084
14085     // private
14086     handleMouseDown : function(){
14087         clearTimeout(this.timer);
14088         this.el.blur();
14089         if(this.pressClass){
14090             this.el.addClass(this.pressClass);
14091         }
14092         this.mousedownTime = new Date();
14093
14094         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14095         this.el.on("mouseout", this.handleMouseOut, this);
14096
14097         this.fireEvent("mousedown", this);
14098         this.fireEvent("click", this);
14099         
14100         this.timer = this.click.defer(this.delay || this.interval, this);
14101     },
14102
14103     // private
14104     click : function(){
14105         this.fireEvent("click", this);
14106         this.timer = this.click.defer(this.getInterval(), this);
14107     },
14108
14109     // private
14110     getInterval: function(){
14111         if(!this.accelerate){
14112             return this.interval;
14113         }
14114         var pressTime = this.mousedownTime.getElapsed();
14115         if(pressTime < 500){
14116             return 400;
14117         }else if(pressTime < 1700){
14118             return 320;
14119         }else if(pressTime < 2600){
14120             return 250;
14121         }else if(pressTime < 3500){
14122             return 180;
14123         }else if(pressTime < 4400){
14124             return 140;
14125         }else if(pressTime < 5300){
14126             return 80;
14127         }else if(pressTime < 6200){
14128             return 50;
14129         }else{
14130             return 10;
14131         }
14132     },
14133
14134     // private
14135     handleMouseOut : function(){
14136         clearTimeout(this.timer);
14137         if(this.pressClass){
14138             this.el.removeClass(this.pressClass);
14139         }
14140         this.el.on("mouseover", this.handleMouseReturn, this);
14141     },
14142
14143     // private
14144     handleMouseReturn : function(){
14145         this.el.un("mouseover", this.handleMouseReturn);
14146         if(this.pressClass){
14147             this.el.addClass(this.pressClass);
14148         }
14149         this.click();
14150     },
14151
14152     // private
14153     handleMouseUp : function(){
14154         clearTimeout(this.timer);
14155         this.el.un("mouseover", this.handleMouseReturn);
14156         this.el.un("mouseout", this.handleMouseOut);
14157         Roo.get(document).un("mouseup", this.handleMouseUp);
14158         this.el.removeClass(this.pressClass);
14159         this.fireEvent("mouseup", this);
14160     }
14161 });/*
14162  * Based on:
14163  * Ext JS Library 1.1.1
14164  * Copyright(c) 2006-2007, Ext JS, LLC.
14165  *
14166  * Originally Released Under LGPL - original licence link has changed is not relivant.
14167  *
14168  * Fork - LGPL
14169  * <script type="text/javascript">
14170  */
14171
14172  
14173 /**
14174  * @class Roo.KeyNav
14175  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14176  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14177  * way to implement custom navigation schemes for any UI component.</p>
14178  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14179  * pageUp, pageDown, del, home, end.  Usage:</p>
14180  <pre><code>
14181 var nav = new Roo.KeyNav("my-element", {
14182     "left" : function(e){
14183         this.moveLeft(e.ctrlKey);
14184     },
14185     "right" : function(e){
14186         this.moveRight(e.ctrlKey);
14187     },
14188     "enter" : function(e){
14189         this.save();
14190     },
14191     scope : this
14192 });
14193 </code></pre>
14194  * @constructor
14195  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14196  * @param {Object} config The config
14197  */
14198 Roo.KeyNav = function(el, config){
14199     this.el = Roo.get(el);
14200     Roo.apply(this, config);
14201     if(!this.disabled){
14202         this.disabled = true;
14203         this.enable();
14204     }
14205 };
14206
14207 Roo.KeyNav.prototype = {
14208     /**
14209      * @cfg {Boolean} disabled
14210      * True to disable this KeyNav instance (defaults to false)
14211      */
14212     disabled : false,
14213     /**
14214      * @cfg {String} defaultEventAction
14215      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14216      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14217      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14218      */
14219     defaultEventAction: "stopEvent",
14220     /**
14221      * @cfg {Boolean} forceKeyDown
14222      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14223      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14224      * handle keydown instead of keypress.
14225      */
14226     forceKeyDown : false,
14227
14228     // private
14229     prepareEvent : function(e){
14230         var k = e.getKey();
14231         var h = this.keyToHandler[k];
14232         //if(h && this[h]){
14233         //    e.stopPropagation();
14234         //}
14235         if(Roo.isSafari && h && k >= 37 && k <= 40){
14236             e.stopEvent();
14237         }
14238     },
14239
14240     // private
14241     relay : function(e){
14242         var k = e.getKey();
14243         var h = this.keyToHandler[k];
14244         if(h && this[h]){
14245             if(this.doRelay(e, this[h], h) !== true){
14246                 e[this.defaultEventAction]();
14247             }
14248         }
14249     },
14250
14251     // private
14252     doRelay : function(e, h, hname){
14253         return h.call(this.scope || this, e);
14254     },
14255
14256     // possible handlers
14257     enter : false,
14258     left : false,
14259     right : false,
14260     up : false,
14261     down : false,
14262     tab : false,
14263     esc : false,
14264     pageUp : false,
14265     pageDown : false,
14266     del : false,
14267     home : false,
14268     end : false,
14269
14270     // quick lookup hash
14271     keyToHandler : {
14272         37 : "left",
14273         39 : "right",
14274         38 : "up",
14275         40 : "down",
14276         33 : "pageUp",
14277         34 : "pageDown",
14278         46 : "del",
14279         36 : "home",
14280         35 : "end",
14281         13 : "enter",
14282         27 : "esc",
14283         9  : "tab"
14284     },
14285
14286         /**
14287          * Enable this KeyNav
14288          */
14289         enable: function(){
14290                 if(this.disabled){
14291             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14292             // the EventObject will normalize Safari automatically
14293             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14294                 this.el.on("keydown", this.relay,  this);
14295             }else{
14296                 this.el.on("keydown", this.prepareEvent,  this);
14297                 this.el.on("keypress", this.relay,  this);
14298             }
14299                     this.disabled = false;
14300                 }
14301         },
14302
14303         /**
14304          * Disable this KeyNav
14305          */
14306         disable: function(){
14307                 if(!this.disabled){
14308                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14309                 this.el.un("keydown", this.relay);
14310             }else{
14311                 this.el.un("keydown", this.prepareEvent);
14312                 this.el.un("keypress", this.relay);
14313             }
14314                     this.disabled = true;
14315                 }
14316         }
14317 };/*
14318  * Based on:
14319  * Ext JS Library 1.1.1
14320  * Copyright(c) 2006-2007, Ext JS, LLC.
14321  *
14322  * Originally Released Under LGPL - original licence link has changed is not relivant.
14323  *
14324  * Fork - LGPL
14325  * <script type="text/javascript">
14326  */
14327
14328  
14329 /**
14330  * @class Roo.KeyMap
14331  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14332  * The constructor accepts the same config object as defined by {@link #addBinding}.
14333  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14334  * combination it will call the function with this signature (if the match is a multi-key
14335  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14336  * A KeyMap can also handle a string representation of keys.<br />
14337  * Usage:
14338  <pre><code>
14339 // map one key by key code
14340 var map = new Roo.KeyMap("my-element", {
14341     key: 13, // or Roo.EventObject.ENTER
14342     fn: myHandler,
14343     scope: myObject
14344 });
14345
14346 // map multiple keys to one action by string
14347 var map = new Roo.KeyMap("my-element", {
14348     key: "a\r\n\t",
14349     fn: myHandler,
14350     scope: myObject
14351 });
14352
14353 // map multiple keys to multiple actions by strings and array of codes
14354 var map = new Roo.KeyMap("my-element", [
14355     {
14356         key: [10,13],
14357         fn: function(){ alert("Return was pressed"); }
14358     }, {
14359         key: "abc",
14360         fn: function(){ alert('a, b or c was pressed'); }
14361     }, {
14362         key: "\t",
14363         ctrl:true,
14364         shift:true,
14365         fn: function(){ alert('Control + shift + tab was pressed.'); }
14366     }
14367 ]);
14368 </code></pre>
14369  * <b>Note: A KeyMap starts enabled</b>
14370  * @constructor
14371  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14372  * @param {Object} config The config (see {@link #addBinding})
14373  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14374  */
14375 Roo.KeyMap = function(el, config, eventName){
14376     this.el  = Roo.get(el);
14377     this.eventName = eventName || "keydown";
14378     this.bindings = [];
14379     if(config){
14380         this.addBinding(config);
14381     }
14382     this.enable();
14383 };
14384
14385 Roo.KeyMap.prototype = {
14386     /**
14387      * True to stop the event from bubbling and prevent the default browser action if the
14388      * key was handled by the KeyMap (defaults to false)
14389      * @type Boolean
14390      */
14391     stopEvent : false,
14392
14393     /**
14394      * Add a new binding to this KeyMap. The following config object properties are supported:
14395      * <pre>
14396 Property    Type             Description
14397 ----------  ---------------  ----------------------------------------------------------------------
14398 key         String/Array     A single keycode or an array of keycodes to handle
14399 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14400 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14401 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14402 fn          Function         The function to call when KeyMap finds the expected key combination
14403 scope       Object           The scope of the callback function
14404 </pre>
14405      *
14406      * Usage:
14407      * <pre><code>
14408 // Create a KeyMap
14409 var map = new Roo.KeyMap(document, {
14410     key: Roo.EventObject.ENTER,
14411     fn: handleKey,
14412     scope: this
14413 });
14414
14415 //Add a new binding to the existing KeyMap later
14416 map.addBinding({
14417     key: 'abc',
14418     shift: true,
14419     fn: handleKey,
14420     scope: this
14421 });
14422 </code></pre>
14423      * @param {Object/Array} config A single KeyMap config or an array of configs
14424      */
14425         addBinding : function(config){
14426         if(config instanceof Array){
14427             for(var i = 0, len = config.length; i < len; i++){
14428                 this.addBinding(config[i]);
14429             }
14430             return;
14431         }
14432         var keyCode = config.key,
14433             shift = config.shift, 
14434             ctrl = config.ctrl, 
14435             alt = config.alt,
14436             fn = config.fn,
14437             scope = config.scope;
14438         if(typeof keyCode == "string"){
14439             var ks = [];
14440             var keyString = keyCode.toUpperCase();
14441             for(var j = 0, len = keyString.length; j < len; j++){
14442                 ks.push(keyString.charCodeAt(j));
14443             }
14444             keyCode = ks;
14445         }
14446         var keyArray = keyCode instanceof Array;
14447         var handler = function(e){
14448             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14449                 var k = e.getKey();
14450                 if(keyArray){
14451                     for(var i = 0, len = keyCode.length; i < len; i++){
14452                         if(keyCode[i] == k){
14453                           if(this.stopEvent){
14454                               e.stopEvent();
14455                           }
14456                           fn.call(scope || window, k, e);
14457                           return;
14458                         }
14459                     }
14460                 }else{
14461                     if(k == keyCode){
14462                         if(this.stopEvent){
14463                            e.stopEvent();
14464                         }
14465                         fn.call(scope || window, k, e);
14466                     }
14467                 }
14468             }
14469         };
14470         this.bindings.push(handler);  
14471         },
14472
14473     /**
14474      * Shorthand for adding a single key listener
14475      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14476      * following options:
14477      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14478      * @param {Function} fn The function to call
14479      * @param {Object} scope (optional) The scope of the function
14480      */
14481     on : function(key, fn, scope){
14482         var keyCode, shift, ctrl, alt;
14483         if(typeof key == "object" && !(key instanceof Array)){
14484             keyCode = key.key;
14485             shift = key.shift;
14486             ctrl = key.ctrl;
14487             alt = key.alt;
14488         }else{
14489             keyCode = key;
14490         }
14491         this.addBinding({
14492             key: keyCode,
14493             shift: shift,
14494             ctrl: ctrl,
14495             alt: alt,
14496             fn: fn,
14497             scope: scope
14498         })
14499     },
14500
14501     // private
14502     handleKeyDown : function(e){
14503             if(this.enabled){ //just in case
14504             var b = this.bindings;
14505             for(var i = 0, len = b.length; i < len; i++){
14506                 b[i].call(this, e);
14507             }
14508             }
14509         },
14510         
14511         /**
14512          * Returns true if this KeyMap is enabled
14513          * @return {Boolean} 
14514          */
14515         isEnabled : function(){
14516             return this.enabled;  
14517         },
14518         
14519         /**
14520          * Enables this KeyMap
14521          */
14522         enable: function(){
14523                 if(!this.enabled){
14524                     this.el.on(this.eventName, this.handleKeyDown, this);
14525                     this.enabled = true;
14526                 }
14527         },
14528
14529         /**
14530          * Disable this KeyMap
14531          */
14532         disable: function(){
14533                 if(this.enabled){
14534                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14535                     this.enabled = false;
14536                 }
14537         }
14538 };/*
14539  * Based on:
14540  * Ext JS Library 1.1.1
14541  * Copyright(c) 2006-2007, Ext JS, LLC.
14542  *
14543  * Originally Released Under LGPL - original licence link has changed is not relivant.
14544  *
14545  * Fork - LGPL
14546  * <script type="text/javascript">
14547  */
14548
14549  
14550 /**
14551  * @class Roo.util.TextMetrics
14552  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14553  * wide, in pixels, a given block of text will be.
14554  * @singleton
14555  */
14556 Roo.util.TextMetrics = function(){
14557     var shared;
14558     return {
14559         /**
14560          * Measures the size of the specified text
14561          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14562          * that can affect the size of the rendered text
14563          * @param {String} text The text to measure
14564          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14565          * in order to accurately measure the text height
14566          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14567          */
14568         measure : function(el, text, fixedWidth){
14569             if(!shared){
14570                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14571             }
14572             shared.bind(el);
14573             shared.setFixedWidth(fixedWidth || 'auto');
14574             return shared.getSize(text);
14575         },
14576
14577         /**
14578          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14579          * the overhead of multiple calls to initialize the style properties on each measurement.
14580          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14581          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14582          * in order to accurately measure the text height
14583          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14584          */
14585         createInstance : function(el, fixedWidth){
14586             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14587         }
14588     };
14589 }();
14590
14591  
14592
14593 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14594     var ml = new Roo.Element(document.createElement('div'));
14595     document.body.appendChild(ml.dom);
14596     ml.position('absolute');
14597     ml.setLeftTop(-1000, -1000);
14598     ml.hide();
14599
14600     if(fixedWidth){
14601         ml.setWidth(fixedWidth);
14602     }
14603      
14604     var instance = {
14605         /**
14606          * Returns the size of the specified text based on the internal element's style and width properties
14607          * @memberOf Roo.util.TextMetrics.Instance#
14608          * @param {String} text The text to measure
14609          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14610          */
14611         getSize : function(text){
14612             ml.update(text);
14613             var s = ml.getSize();
14614             ml.update('');
14615             return s;
14616         },
14617
14618         /**
14619          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14620          * that can affect the size of the rendered text
14621          * @memberOf Roo.util.TextMetrics.Instance#
14622          * @param {String/HTMLElement} el The element, dom node or id
14623          */
14624         bind : function(el){
14625             ml.setStyle(
14626                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14627             );
14628         },
14629
14630         /**
14631          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14632          * to set a fixed width in order to accurately measure the text height.
14633          * @memberOf Roo.util.TextMetrics.Instance#
14634          * @param {Number} width The width to set on the element
14635          */
14636         setFixedWidth : function(width){
14637             ml.setWidth(width);
14638         },
14639
14640         /**
14641          * Returns the measured width of the specified text
14642          * @memberOf Roo.util.TextMetrics.Instance#
14643          * @param {String} text The text to measure
14644          * @return {Number} width The width in pixels
14645          */
14646         getWidth : function(text){
14647             ml.dom.style.width = 'auto';
14648             return this.getSize(text).width;
14649         },
14650
14651         /**
14652          * Returns the measured height of the specified text.  For multiline text, be sure to call
14653          * {@link #setFixedWidth} if necessary.
14654          * @memberOf Roo.util.TextMetrics.Instance#
14655          * @param {String} text The text to measure
14656          * @return {Number} height The height in pixels
14657          */
14658         getHeight : function(text){
14659             return this.getSize(text).height;
14660         }
14661     };
14662
14663     instance.bind(bindTo);
14664
14665     return instance;
14666 };
14667
14668 // backwards compat
14669 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14670  * Based on:
14671  * Ext JS Library 1.1.1
14672  * Copyright(c) 2006-2007, Ext JS, LLC.
14673  *
14674  * Originally Released Under LGPL - original licence link has changed is not relivant.
14675  *
14676  * Fork - LGPL
14677  * <script type="text/javascript">
14678  */
14679
14680 /**
14681  * @class Roo.state.Provider
14682  * Abstract base class for state provider implementations. This class provides methods
14683  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14684  * Provider interface.
14685  */
14686 Roo.state.Provider = function(){
14687     /**
14688      * @event statechange
14689      * Fires when a state change occurs.
14690      * @param {Provider} this This state provider
14691      * @param {String} key The state key which was changed
14692      * @param {String} value The encoded value for the state
14693      */
14694     this.addEvents({
14695         "statechange": true
14696     });
14697     this.state = {};
14698     Roo.state.Provider.superclass.constructor.call(this);
14699 };
14700 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14701     /**
14702      * Returns the current value for a key
14703      * @param {String} name The key name
14704      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14705      * @return {Mixed} The state data
14706      */
14707     get : function(name, defaultValue){
14708         return typeof this.state[name] == "undefined" ?
14709             defaultValue : this.state[name];
14710     },
14711     
14712     /**
14713      * Clears a value from the state
14714      * @param {String} name The key name
14715      */
14716     clear : function(name){
14717         delete this.state[name];
14718         this.fireEvent("statechange", this, name, null);
14719     },
14720     
14721     /**
14722      * Sets the value for a key
14723      * @param {String} name The key name
14724      * @param {Mixed} value The value to set
14725      */
14726     set : function(name, value){
14727         this.state[name] = value;
14728         this.fireEvent("statechange", this, name, value);
14729     },
14730     
14731     /**
14732      * Decodes a string previously encoded with {@link #encodeValue}.
14733      * @param {String} value The value to decode
14734      * @return {Mixed} The decoded value
14735      */
14736     decodeValue : function(cookie){
14737         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14738         var matches = re.exec(unescape(cookie));
14739         if(!matches || !matches[1]) return; // non state cookie
14740         var type = matches[1];
14741         var v = matches[2];
14742         switch(type){
14743             case "n":
14744                 return parseFloat(v);
14745             case "d":
14746                 return new Date(Date.parse(v));
14747             case "b":
14748                 return (v == "1");
14749             case "a":
14750                 var all = [];
14751                 var values = v.split("^");
14752                 for(var i = 0, len = values.length; i < len; i++){
14753                     all.push(this.decodeValue(values[i]));
14754                 }
14755                 return all;
14756            case "o":
14757                 var all = {};
14758                 var values = v.split("^");
14759                 for(var i = 0, len = values.length; i < len; i++){
14760                     var kv = values[i].split("=");
14761                     all[kv[0]] = this.decodeValue(kv[1]);
14762                 }
14763                 return all;
14764            default:
14765                 return v;
14766         }
14767     },
14768     
14769     /**
14770      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14771      * @param {Mixed} value The value to encode
14772      * @return {String} The encoded value
14773      */
14774     encodeValue : function(v){
14775         var enc;
14776         if(typeof v == "number"){
14777             enc = "n:" + v;
14778         }else if(typeof v == "boolean"){
14779             enc = "b:" + (v ? "1" : "0");
14780         }else if(v instanceof Date){
14781             enc = "d:" + v.toGMTString();
14782         }else if(v instanceof Array){
14783             var flat = "";
14784             for(var i = 0, len = v.length; i < len; i++){
14785                 flat += this.encodeValue(v[i]);
14786                 if(i != len-1) flat += "^";
14787             }
14788             enc = "a:" + flat;
14789         }else if(typeof v == "object"){
14790             var flat = "";
14791             for(var key in v){
14792                 if(typeof v[key] != "function"){
14793                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14794                 }
14795             }
14796             enc = "o:" + flat.substring(0, flat.length-1);
14797         }else{
14798             enc = "s:" + v;
14799         }
14800         return escape(enc);        
14801     }
14802 });
14803
14804 /*
14805  * Based on:
14806  * Ext JS Library 1.1.1
14807  * Copyright(c) 2006-2007, Ext JS, LLC.
14808  *
14809  * Originally Released Under LGPL - original licence link has changed is not relivant.
14810  *
14811  * Fork - LGPL
14812  * <script type="text/javascript">
14813  */
14814 /**
14815  * @class Roo.state.Manager
14816  * This is the global state manager. By default all components that are "state aware" check this class
14817  * for state information if you don't pass them a custom state provider. In order for this class
14818  * to be useful, it must be initialized with a provider when your application initializes.
14819  <pre><code>
14820 // in your initialization function
14821 init : function(){
14822    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14823    ...
14824    // supposed you have a {@link Roo.BorderLayout}
14825    var layout = new Roo.BorderLayout(...);
14826    layout.restoreState();
14827    // or a {Roo.BasicDialog}
14828    var dialog = new Roo.BasicDialog(...);
14829    dialog.restoreState();
14830  </code></pre>
14831  * @singleton
14832  */
14833 Roo.state.Manager = function(){
14834     var provider = new Roo.state.Provider();
14835     
14836     return {
14837         /**
14838          * Configures the default state provider for your application
14839          * @param {Provider} stateProvider The state provider to set
14840          */
14841         setProvider : function(stateProvider){
14842             provider = stateProvider;
14843         },
14844         
14845         /**
14846          * Returns the current value for a key
14847          * @param {String} name The key name
14848          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14849          * @return {Mixed} The state data
14850          */
14851         get : function(key, defaultValue){
14852             return provider.get(key, defaultValue);
14853         },
14854         
14855         /**
14856          * Sets the value for a key
14857          * @param {String} name The key name
14858          * @param {Mixed} value The state data
14859          */
14860          set : function(key, value){
14861             provider.set(key, value);
14862         },
14863         
14864         /**
14865          * Clears a value from the state
14866          * @param {String} name The key name
14867          */
14868         clear : function(key){
14869             provider.clear(key);
14870         },
14871         
14872         /**
14873          * Gets the currently configured state provider
14874          * @return {Provider} The state provider
14875          */
14876         getProvider : function(){
14877             return provider;
14878         }
14879     };
14880 }();
14881 /*
14882  * Based on:
14883  * Ext JS Library 1.1.1
14884  * Copyright(c) 2006-2007, Ext JS, LLC.
14885  *
14886  * Originally Released Under LGPL - original licence link has changed is not relivant.
14887  *
14888  * Fork - LGPL
14889  * <script type="text/javascript">
14890  */
14891 /**
14892  * @class Roo.state.CookieProvider
14893  * @extends Roo.state.Provider
14894  * The default Provider implementation which saves state via cookies.
14895  * <br />Usage:
14896  <pre><code>
14897    var cp = new Roo.state.CookieProvider({
14898        path: "/cgi-bin/",
14899        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14900        domain: "roojs.com"
14901    })
14902    Roo.state.Manager.setProvider(cp);
14903  </code></pre>
14904  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14905  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14906  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14907  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14908  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14909  * domain the page is running on including the 'www' like 'www.roojs.com')
14910  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14911  * @constructor
14912  * Create a new CookieProvider
14913  * @param {Object} config The configuration object
14914  */
14915 Roo.state.CookieProvider = function(config){
14916     Roo.state.CookieProvider.superclass.constructor.call(this);
14917     this.path = "/";
14918     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14919     this.domain = null;
14920     this.secure = false;
14921     Roo.apply(this, config);
14922     this.state = this.readCookies();
14923 };
14924
14925 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14926     // private
14927     set : function(name, value){
14928         if(typeof value == "undefined" || value === null){
14929             this.clear(name);
14930             return;
14931         }
14932         this.setCookie(name, value);
14933         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14934     },
14935
14936     // private
14937     clear : function(name){
14938         this.clearCookie(name);
14939         Roo.state.CookieProvider.superclass.clear.call(this, name);
14940     },
14941
14942     // private
14943     readCookies : function(){
14944         var cookies = {};
14945         var c = document.cookie + ";";
14946         var re = /\s?(.*?)=(.*?);/g;
14947         var matches;
14948         while((matches = re.exec(c)) != null){
14949             var name = matches[1];
14950             var value = matches[2];
14951             if(name && name.substring(0,3) == "ys-"){
14952                 cookies[name.substr(3)] = this.decodeValue(value);
14953             }
14954         }
14955         return cookies;
14956     },
14957
14958     // private
14959     setCookie : function(name, value){
14960         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14961            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14962            ((this.path == null) ? "" : ("; path=" + this.path)) +
14963            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14964            ((this.secure == true) ? "; secure" : "");
14965     },
14966
14967     // private
14968     clearCookie : function(name){
14969         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14970            ((this.path == null) ? "" : ("; path=" + this.path)) +
14971            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14972            ((this.secure == true) ? "; secure" : "");
14973     }
14974 });/*
14975  * Based on:
14976  * Ext JS Library 1.1.1
14977  * Copyright(c) 2006-2007, Ext JS, LLC.
14978  *
14979  * Originally Released Under LGPL - original licence link has changed is not relivant.
14980  *
14981  * Fork - LGPL
14982  * <script type="text/javascript">
14983  */
14984  
14985
14986 /**
14987  * @class Roo.ComponentMgr
14988  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14989  * @singleton
14990  */
14991 Roo.ComponentMgr = function(){
14992     var all = new Roo.util.MixedCollection();
14993
14994     return {
14995         /**
14996          * Registers a component.
14997          * @param {Roo.Component} c The component
14998          */
14999         register : function(c){
15000             all.add(c);
15001         },
15002
15003         /**
15004          * Unregisters a component.
15005          * @param {Roo.Component} c The component
15006          */
15007         unregister : function(c){
15008             all.remove(c);
15009         },
15010
15011         /**
15012          * Returns a component by id
15013          * @param {String} id The component id
15014          */
15015         get : function(id){
15016             return all.get(id);
15017         },
15018
15019         /**
15020          * Registers a function that will be called when a specified component is added to ComponentMgr
15021          * @param {String} id The component id
15022          * @param {Funtction} fn The callback function
15023          * @param {Object} scope The scope of the callback
15024          */
15025         onAvailable : function(id, fn, scope){
15026             all.on("add", function(index, o){
15027                 if(o.id == id){
15028                     fn.call(scope || o, o);
15029                     all.un("add", fn, scope);
15030                 }
15031             });
15032         }
15033     };
15034 }();/*
15035  * Based on:
15036  * Ext JS Library 1.1.1
15037  * Copyright(c) 2006-2007, Ext JS, LLC.
15038  *
15039  * Originally Released Under LGPL - original licence link has changed is not relivant.
15040  *
15041  * Fork - LGPL
15042  * <script type="text/javascript">
15043  */
15044  
15045 /**
15046  * @class Roo.Component
15047  * @extends Roo.util.Observable
15048  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15049  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15050  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15051  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15052  * All visual components (widgets) that require rendering into a layout should subclass Component.
15053  * @constructor
15054  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15055  * 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
15056  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15057  */
15058 Roo.Component = function(config){
15059     config = config || {};
15060     if(config.tagName || config.dom || typeof config == "string"){ // element object
15061         config = {el: config, id: config.id || config};
15062     }
15063     this.initialConfig = config;
15064
15065     Roo.apply(this, config);
15066     this.addEvents({
15067         /**
15068          * @event disable
15069          * Fires after the component is disabled.
15070              * @param {Roo.Component} this
15071              */
15072         disable : true,
15073         /**
15074          * @event enable
15075          * Fires after the component is enabled.
15076              * @param {Roo.Component} this
15077              */
15078         enable : true,
15079         /**
15080          * @event beforeshow
15081          * Fires before the component is shown.  Return false to stop the show.
15082              * @param {Roo.Component} this
15083              */
15084         beforeshow : true,
15085         /**
15086          * @event show
15087          * Fires after the component is shown.
15088              * @param {Roo.Component} this
15089              */
15090         show : true,
15091         /**
15092          * @event beforehide
15093          * Fires before the component is hidden. Return false to stop the hide.
15094              * @param {Roo.Component} this
15095              */
15096         beforehide : true,
15097         /**
15098          * @event hide
15099          * Fires after the component is hidden.
15100              * @param {Roo.Component} this
15101              */
15102         hide : true,
15103         /**
15104          * @event beforerender
15105          * Fires before the component is rendered. Return false to stop the render.
15106              * @param {Roo.Component} this
15107              */
15108         beforerender : true,
15109         /**
15110          * @event render
15111          * Fires after the component is rendered.
15112              * @param {Roo.Component} this
15113              */
15114         render : true,
15115         /**
15116          * @event beforedestroy
15117          * Fires before the component is destroyed. Return false to stop the destroy.
15118              * @param {Roo.Component} this
15119              */
15120         beforedestroy : true,
15121         /**
15122          * @event destroy
15123          * Fires after the component is destroyed.
15124              * @param {Roo.Component} this
15125              */
15126         destroy : true
15127     });
15128     if(!this.id){
15129         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15130     }
15131     Roo.ComponentMgr.register(this);
15132     Roo.Component.superclass.constructor.call(this);
15133     this.initComponent();
15134     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15135         this.render(this.renderTo);
15136         delete this.renderTo;
15137     }
15138 };
15139
15140 /** @private */
15141 Roo.Component.AUTO_ID = 1000;
15142
15143 Roo.extend(Roo.Component, Roo.util.Observable, {
15144     /**
15145      * @scope Roo.Component.prototype
15146      * @type {Boolean}
15147      * true if this component is hidden. Read-only.
15148      */
15149     hidden : false,
15150     /**
15151      * @type {Boolean}
15152      * true if this component is disabled. Read-only.
15153      */
15154     disabled : false,
15155     /**
15156      * @type {Boolean}
15157      * true if this component has been rendered. Read-only.
15158      */
15159     rendered : false,
15160     
15161     /** @cfg {String} disableClass
15162      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15163      */
15164     disabledClass : "x-item-disabled",
15165         /** @cfg {Boolean} allowDomMove
15166          * Whether the component can move the Dom node when rendering (defaults to true).
15167          */
15168     allowDomMove : true,
15169     /** @cfg {String} hideMode
15170      * How this component should hidden. Supported values are
15171      * "visibility" (css visibility), "offsets" (negative offset position) and
15172      * "display" (css display) - defaults to "display".
15173      */
15174     hideMode: 'display',
15175
15176     /** @private */
15177     ctype : "Roo.Component",
15178
15179     /**
15180      * @cfg {String} actionMode 
15181      * which property holds the element that used for  hide() / show() / disable() / enable()
15182      * default is 'el' 
15183      */
15184     actionMode : "el",
15185
15186     /** @private */
15187     getActionEl : function(){
15188         return this[this.actionMode];
15189     },
15190
15191     initComponent : Roo.emptyFn,
15192     /**
15193      * If this is a lazy rendering component, render it to its container element.
15194      * @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.
15195      */
15196     render : function(container, position){
15197         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15198             if(!container && this.el){
15199                 this.el = Roo.get(this.el);
15200                 container = this.el.dom.parentNode;
15201                 this.allowDomMove = false;
15202             }
15203             this.container = Roo.get(container);
15204             this.rendered = true;
15205             if(position !== undefined){
15206                 if(typeof position == 'number'){
15207                     position = this.container.dom.childNodes[position];
15208                 }else{
15209                     position = Roo.getDom(position);
15210                 }
15211             }
15212             this.onRender(this.container, position || null);
15213             if(this.cls){
15214                 this.el.addClass(this.cls);
15215                 delete this.cls;
15216             }
15217             if(this.style){
15218                 this.el.applyStyles(this.style);
15219                 delete this.style;
15220             }
15221             this.fireEvent("render", this);
15222             this.afterRender(this.container);
15223             if(this.hidden){
15224                 this.hide();
15225             }
15226             if(this.disabled){
15227                 this.disable();
15228             }
15229         }
15230         return this;
15231     },
15232
15233     /** @private */
15234     // default function is not really useful
15235     onRender : function(ct, position){
15236         if(this.el){
15237             this.el = Roo.get(this.el);
15238             if(this.allowDomMove !== false){
15239                 ct.dom.insertBefore(this.el.dom, position);
15240             }
15241         }
15242     },
15243
15244     /** @private */
15245     getAutoCreate : function(){
15246         var cfg = typeof this.autoCreate == "object" ?
15247                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15248         if(this.id && !cfg.id){
15249             cfg.id = this.id;
15250         }
15251         return cfg;
15252     },
15253
15254     /** @private */
15255     afterRender : Roo.emptyFn,
15256
15257     /**
15258      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15259      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15260      */
15261     destroy : function(){
15262         if(this.fireEvent("beforedestroy", this) !== false){
15263             this.purgeListeners();
15264             this.beforeDestroy();
15265             if(this.rendered){
15266                 this.el.removeAllListeners();
15267                 this.el.remove();
15268                 if(this.actionMode == "container"){
15269                     this.container.remove();
15270                 }
15271             }
15272             this.onDestroy();
15273             Roo.ComponentMgr.unregister(this);
15274             this.fireEvent("destroy", this);
15275         }
15276     },
15277
15278         /** @private */
15279     beforeDestroy : function(){
15280
15281     },
15282
15283         /** @private */
15284         onDestroy : function(){
15285
15286     },
15287
15288     /**
15289      * Returns the underlying {@link Roo.Element}.
15290      * @return {Roo.Element} The element
15291      */
15292     getEl : function(){
15293         return this.el;
15294     },
15295
15296     /**
15297      * Returns the id of this component.
15298      * @return {String}
15299      */
15300     getId : function(){
15301         return this.id;
15302     },
15303
15304     /**
15305      * Try to focus this component.
15306      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15307      * @return {Roo.Component} this
15308      */
15309     focus : function(selectText){
15310         if(this.rendered){
15311             this.el.focus();
15312             if(selectText === true){
15313                 this.el.dom.select();
15314             }
15315         }
15316         return this;
15317     },
15318
15319     /** @private */
15320     blur : function(){
15321         if(this.rendered){
15322             this.el.blur();
15323         }
15324         return this;
15325     },
15326
15327     /**
15328      * Disable this component.
15329      * @return {Roo.Component} this
15330      */
15331     disable : function(){
15332         if(this.rendered){
15333             this.onDisable();
15334         }
15335         this.disabled = true;
15336         this.fireEvent("disable", this);
15337         return this;
15338     },
15339
15340         // private
15341     onDisable : function(){
15342         this.getActionEl().addClass(this.disabledClass);
15343         this.el.dom.disabled = true;
15344     },
15345
15346     /**
15347      * Enable this component.
15348      * @return {Roo.Component} this
15349      */
15350     enable : function(){
15351         if(this.rendered){
15352             this.onEnable();
15353         }
15354         this.disabled = false;
15355         this.fireEvent("enable", this);
15356         return this;
15357     },
15358
15359         // private
15360     onEnable : function(){
15361         this.getActionEl().removeClass(this.disabledClass);
15362         this.el.dom.disabled = false;
15363     },
15364
15365     /**
15366      * Convenience function for setting disabled/enabled by boolean.
15367      * @param {Boolean} disabled
15368      */
15369     setDisabled : function(disabled){
15370         this[disabled ? "disable" : "enable"]();
15371     },
15372
15373     /**
15374      * Show this component.
15375      * @return {Roo.Component} this
15376      */
15377     show: function(){
15378         if(this.fireEvent("beforeshow", this) !== false){
15379             this.hidden = false;
15380             if(this.rendered){
15381                 this.onShow();
15382             }
15383             this.fireEvent("show", this);
15384         }
15385         return this;
15386     },
15387
15388     // private
15389     onShow : function(){
15390         var ae = this.getActionEl();
15391         if(this.hideMode == 'visibility'){
15392             ae.dom.style.visibility = "visible";
15393         }else if(this.hideMode == 'offsets'){
15394             ae.removeClass('x-hidden');
15395         }else{
15396             ae.dom.style.display = "";
15397         }
15398     },
15399
15400     /**
15401      * Hide this component.
15402      * @return {Roo.Component} this
15403      */
15404     hide: function(){
15405         if(this.fireEvent("beforehide", this) !== false){
15406             this.hidden = true;
15407             if(this.rendered){
15408                 this.onHide();
15409             }
15410             this.fireEvent("hide", this);
15411         }
15412         return this;
15413     },
15414
15415     // private
15416     onHide : function(){
15417         var ae = this.getActionEl();
15418         if(this.hideMode == 'visibility'){
15419             ae.dom.style.visibility = "hidden";
15420         }else if(this.hideMode == 'offsets'){
15421             ae.addClass('x-hidden');
15422         }else{
15423             ae.dom.style.display = "none";
15424         }
15425     },
15426
15427     /**
15428      * Convenience function to hide or show this component by boolean.
15429      * @param {Boolean} visible True to show, false to hide
15430      * @return {Roo.Component} this
15431      */
15432     setVisible: function(visible){
15433         if(visible) {
15434             this.show();
15435         }else{
15436             this.hide();
15437         }
15438         return this;
15439     },
15440
15441     /**
15442      * Returns true if this component is visible.
15443      */
15444     isVisible : function(){
15445         return this.getActionEl().isVisible();
15446     },
15447
15448     cloneConfig : function(overrides){
15449         overrides = overrides || {};
15450         var id = overrides.id || Roo.id();
15451         var cfg = Roo.applyIf(overrides, this.initialConfig);
15452         cfg.id = id; // prevent dup id
15453         return new this.constructor(cfg);
15454     }
15455 });/*
15456  * Based on:
15457  * Ext JS Library 1.1.1
15458  * Copyright(c) 2006-2007, Ext JS, LLC.
15459  *
15460  * Originally Released Under LGPL - original licence link has changed is not relivant.
15461  *
15462  * Fork - LGPL
15463  * <script type="text/javascript">
15464  */
15465
15466 /**
15467  * @class Roo.BoxComponent
15468  * @extends Roo.Component
15469  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15470  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15471  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15472  * layout containers.
15473  * @constructor
15474  * @param {Roo.Element/String/Object} config The configuration options.
15475  */
15476 Roo.BoxComponent = function(config){
15477     Roo.Component.call(this, config);
15478     this.addEvents({
15479         /**
15480          * @event resize
15481          * Fires after the component is resized.
15482              * @param {Roo.Component} this
15483              * @param {Number} adjWidth The box-adjusted width that was set
15484              * @param {Number} adjHeight The box-adjusted height that was set
15485              * @param {Number} rawWidth The width that was originally specified
15486              * @param {Number} rawHeight The height that was originally specified
15487              */
15488         resize : true,
15489         /**
15490          * @event move
15491          * Fires after the component is moved.
15492              * @param {Roo.Component} this
15493              * @param {Number} x The new x position
15494              * @param {Number} y The new y position
15495              */
15496         move : true
15497     });
15498 };
15499
15500 Roo.extend(Roo.BoxComponent, Roo.Component, {
15501     // private, set in afterRender to signify that the component has been rendered
15502     boxReady : false,
15503     // private, used to defer height settings to subclasses
15504     deferHeight: false,
15505     /** @cfg {Number} width
15506      * width (optional) size of component
15507      */
15508      /** @cfg {Number} height
15509      * height (optional) size of component
15510      */
15511      
15512     /**
15513      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15514      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15515      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15516      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15517      * @return {Roo.BoxComponent} this
15518      */
15519     setSize : function(w, h){
15520         // support for standard size objects
15521         if(typeof w == 'object'){
15522             h = w.height;
15523             w = w.width;
15524         }
15525         // not rendered
15526         if(!this.boxReady){
15527             this.width = w;
15528             this.height = h;
15529             return this;
15530         }
15531
15532         // prevent recalcs when not needed
15533         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15534             return this;
15535         }
15536         this.lastSize = {width: w, height: h};
15537
15538         var adj = this.adjustSize(w, h);
15539         var aw = adj.width, ah = adj.height;
15540         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15541             var rz = this.getResizeEl();
15542             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15543                 rz.setSize(aw, ah);
15544             }else if(!this.deferHeight && ah !== undefined){
15545                 rz.setHeight(ah);
15546             }else if(aw !== undefined){
15547                 rz.setWidth(aw);
15548             }
15549             this.onResize(aw, ah, w, h);
15550             this.fireEvent('resize', this, aw, ah, w, h);
15551         }
15552         return this;
15553     },
15554
15555     /**
15556      * Gets the current size of the component's underlying element.
15557      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15558      */
15559     getSize : function(){
15560         return this.el.getSize();
15561     },
15562
15563     /**
15564      * Gets the current XY position of the component's underlying element.
15565      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15566      * @return {Array} The XY position of the element (e.g., [100, 200])
15567      */
15568     getPosition : function(local){
15569         if(local === true){
15570             return [this.el.getLeft(true), this.el.getTop(true)];
15571         }
15572         return this.xy || this.el.getXY();
15573     },
15574
15575     /**
15576      * Gets the current box measurements of the component's underlying element.
15577      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15578      * @returns {Object} box An object in the format {x, y, width, height}
15579      */
15580     getBox : function(local){
15581         var s = this.el.getSize();
15582         if(local){
15583             s.x = this.el.getLeft(true);
15584             s.y = this.el.getTop(true);
15585         }else{
15586             var xy = this.xy || this.el.getXY();
15587             s.x = xy[0];
15588             s.y = xy[1];
15589         }
15590         return s;
15591     },
15592
15593     /**
15594      * Sets the current box measurements of the component's underlying element.
15595      * @param {Object} box An object in the format {x, y, width, height}
15596      * @returns {Roo.BoxComponent} this
15597      */
15598     updateBox : function(box){
15599         this.setSize(box.width, box.height);
15600         this.setPagePosition(box.x, box.y);
15601         return this;
15602     },
15603
15604     // protected
15605     getResizeEl : function(){
15606         return this.resizeEl || this.el;
15607     },
15608
15609     // protected
15610     getPositionEl : function(){
15611         return this.positionEl || this.el;
15612     },
15613
15614     /**
15615      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15616      * This method fires the move event.
15617      * @param {Number} left The new left
15618      * @param {Number} top The new top
15619      * @returns {Roo.BoxComponent} this
15620      */
15621     setPosition : function(x, y){
15622         this.x = x;
15623         this.y = y;
15624         if(!this.boxReady){
15625             return this;
15626         }
15627         var adj = this.adjustPosition(x, y);
15628         var ax = adj.x, ay = adj.y;
15629
15630         var el = this.getPositionEl();
15631         if(ax !== undefined || ay !== undefined){
15632             if(ax !== undefined && ay !== undefined){
15633                 el.setLeftTop(ax, ay);
15634             }else if(ax !== undefined){
15635                 el.setLeft(ax);
15636             }else if(ay !== undefined){
15637                 el.setTop(ay);
15638             }
15639             this.onPosition(ax, ay);
15640             this.fireEvent('move', this, ax, ay);
15641         }
15642         return this;
15643     },
15644
15645     /**
15646      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15647      * This method fires the move event.
15648      * @param {Number} x The new x position
15649      * @param {Number} y The new y position
15650      * @returns {Roo.BoxComponent} this
15651      */
15652     setPagePosition : function(x, y){
15653         this.pageX = x;
15654         this.pageY = y;
15655         if(!this.boxReady){
15656             return;
15657         }
15658         if(x === undefined || y === undefined){ // cannot translate undefined points
15659             return;
15660         }
15661         var p = this.el.translatePoints(x, y);
15662         this.setPosition(p.left, p.top);
15663         return this;
15664     },
15665
15666     // private
15667     onRender : function(ct, position){
15668         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15669         if(this.resizeEl){
15670             this.resizeEl = Roo.get(this.resizeEl);
15671         }
15672         if(this.positionEl){
15673             this.positionEl = Roo.get(this.positionEl);
15674         }
15675     },
15676
15677     // private
15678     afterRender : function(){
15679         Roo.BoxComponent.superclass.afterRender.call(this);
15680         this.boxReady = true;
15681         this.setSize(this.width, this.height);
15682         if(this.x || this.y){
15683             this.setPosition(this.x, this.y);
15684         }
15685         if(this.pageX || this.pageY){
15686             this.setPagePosition(this.pageX, this.pageY);
15687         }
15688     },
15689
15690     /**
15691      * Force the component's size to recalculate based on the underlying element's current height and width.
15692      * @returns {Roo.BoxComponent} this
15693      */
15694     syncSize : function(){
15695         delete this.lastSize;
15696         this.setSize(this.el.getWidth(), this.el.getHeight());
15697         return this;
15698     },
15699
15700     /**
15701      * Called after the component is resized, this method is empty by default but can be implemented by any
15702      * subclass that needs to perform custom logic after a resize occurs.
15703      * @param {Number} adjWidth The box-adjusted width that was set
15704      * @param {Number} adjHeight The box-adjusted height that was set
15705      * @param {Number} rawWidth The width that was originally specified
15706      * @param {Number} rawHeight The height that was originally specified
15707      */
15708     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15709
15710     },
15711
15712     /**
15713      * Called after the component is moved, this method is empty by default but can be implemented by any
15714      * subclass that needs to perform custom logic after a move occurs.
15715      * @param {Number} x The new x position
15716      * @param {Number} y The new y position
15717      */
15718     onPosition : function(x, y){
15719
15720     },
15721
15722     // private
15723     adjustSize : function(w, h){
15724         if(this.autoWidth){
15725             w = 'auto';
15726         }
15727         if(this.autoHeight){
15728             h = 'auto';
15729         }
15730         return {width : w, height: h};
15731     },
15732
15733     // private
15734     adjustPosition : function(x, y){
15735         return {x : x, y: y};
15736     }
15737 });/*
15738  * Original code for Roojs - LGPL
15739  * <script type="text/javascript">
15740  */
15741  
15742 /**
15743  * @class Roo.XComponent
15744  * A delayed Element creator...
15745  * Or a way to group chunks of interface together.
15746  * 
15747  * Mypart.xyx = new Roo.XComponent({
15748
15749     parent : 'Mypart.xyz', // empty == document.element.!!
15750     order : '001',
15751     name : 'xxxx'
15752     region : 'xxxx'
15753     disabled : function() {} 
15754      
15755     tree : function() { // return an tree of xtype declared components
15756         var MODULE = this;
15757         return 
15758         {
15759             xtype : 'NestedLayoutPanel',
15760             // technicall
15761         }
15762      ]
15763  *})
15764  *
15765  *
15766  * It can be used to build a big heiracy, with parent etc.
15767  * or you can just use this to render a single compoent to a dom element
15768  * MYPART.render(Roo.Element | String(id) | dom_element )
15769  * 
15770  * @extends Roo.util.Observable
15771  * @constructor
15772  * @param cfg {Object} configuration of component
15773  * 
15774  */
15775 Roo.XComponent = function(cfg) {
15776     Roo.apply(this, cfg);
15777     this.addEvents({ 
15778         /**
15779              * @event built
15780              * Fires when this the componnt is built
15781              * @param {Roo.XComponent} c the component
15782              */
15783         'built' : true
15784         
15785     });
15786     this.region = this.region || 'center'; // default..
15787     Roo.XComponent.register(this);
15788     this.modules = false;
15789     this.el = false; // where the layout goes..
15790     
15791     
15792 }
15793 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15794     /**
15795      * @property el
15796      * The created element (with Roo.factory())
15797      * @type {Roo.Layout}
15798      */
15799     el  : false,
15800     
15801     /**
15802      * @property el
15803      * for BC  - use el in new code
15804      * @type {Roo.Layout}
15805      */
15806     panel : false,
15807     
15808     /**
15809      * @property layout
15810      * for BC  - use el in new code
15811      * @type {Roo.Layout}
15812      */
15813     layout : false,
15814     
15815      /**
15816      * @cfg {Function|boolean} disabled
15817      * If this module is disabled by some rule, return true from the funtion
15818      */
15819     disabled : false,
15820     
15821     /**
15822      * @cfg {String} parent 
15823      * Name of parent element which it get xtype added to..
15824      */
15825     parent: false,
15826     
15827     /**
15828      * @cfg {String} order
15829      * Used to set the order in which elements are created (usefull for multiple tabs)
15830      */
15831     
15832     order : false,
15833     /**
15834      * @cfg {String} name
15835      * String to display while loading.
15836      */
15837     name : false,
15838     /**
15839      * @cfg {String} region
15840      * Region to render component to (defaults to center)
15841      */
15842     region : 'center',
15843     
15844     /**
15845      * @cfg {Array} items
15846      * A single item array - the first element is the root of the tree..
15847      * It's done this way to stay compatible with the Xtype system...
15848      */
15849     items : false,
15850     
15851     /**
15852      * @property _tree
15853      * The method that retuns the tree of parts that make up this compoennt 
15854      * @type {function}
15855      */
15856     _tree  : false,
15857     
15858      /**
15859      * render
15860      * render element to dom or tree
15861      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15862      */
15863     
15864     render : function(el)
15865     {
15866         
15867         el = el || false;
15868         var hp = this.parent ? 1 : 0;
15869         
15870         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15871             // if parent is a '#.....' string, then let's use that..
15872             var ename = this.parent.substr(1)
15873             this.parent = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
15874             el = Roo.get(ename);
15875             if (!el && !this.parent) {
15876                 Roo.log("Warning - element can not be found :#" + ename );
15877                 return;
15878             }
15879         }
15880         var tree = this._tree ? this._tree() : this.tree();
15881
15882         
15883         if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15884             //el = Roo.get(document.body);
15885             this.parent = { el : true };
15886         }
15887             
15888             
15889         
15890         if (!this.parent) {
15891             
15892             Roo.log("no parent - creating one");
15893             
15894             el = el ? Roo.get(el) : false;      
15895             
15896             // it's a top level one..
15897             this.parent =  {
15898                 el : new Roo.BorderLayout(el || document.body, {
15899                 
15900                      center: {
15901                          titlebar: false,
15902                          autoScroll:false,
15903                          closeOnTab: true,
15904                          tabPosition: 'top',
15905                           //resizeTabs: true,
15906                          alwaysShowTabs: el && hp? false :  true,
15907                          hideTabs: el || !hp ? true :  false,
15908                          minTabWidth: 140
15909                      }
15910                  })
15911             }
15912         }
15913         
15914                 if (!this.parent.el) {
15915                         // probably an old style ctor, which has been disabled.
15916                         return;
15917                         
15918                 }
15919                 // The 'tree' method is  '_tree now' 
15920             
15921         tree.region = tree.region || this.region;
15922         
15923         if (this.parent.el === true) {
15924             // bootstrap... - body..
15925             this.parent.el = Roo.factory(tree);
15926         }
15927         
15928         this.el = this.parent.el.addxtype(tree);
15929         this.fireEvent('built', this);
15930         
15931         this.panel = this.el;
15932         this.layout = this.panel.layout;
15933                 this.parentLayout = this.parent.layout  || false;  
15934          
15935     }
15936     
15937 });
15938
15939 Roo.apply(Roo.XComponent, {
15940     /**
15941      * @property  hideProgress
15942      * true to disable the building progress bar.. usefull on single page renders.
15943      * @type Boolean
15944      */
15945     hideProgress : false,
15946     /**
15947      * @property  buildCompleted
15948      * True when the builder has completed building the interface.
15949      * @type Boolean
15950      */
15951     buildCompleted : false,
15952      
15953     /**
15954      * @property  topModule
15955      * the upper most module - uses document.element as it's constructor.
15956      * @type Object
15957      */
15958      
15959     topModule  : false,
15960       
15961     /**
15962      * @property  modules
15963      * array of modules to be created by registration system.
15964      * @type {Array} of Roo.XComponent
15965      */
15966     
15967     modules : [],
15968     /**
15969      * @property  elmodules
15970      * array of modules to be created by which use #ID 
15971      * @type {Array} of Roo.XComponent
15972      */
15973      
15974     elmodules : [],
15975
15976      /**
15977      * @property  build_from_html
15978      * Build elements from html - used by bootstrap HTML stuff 
15979      *    - this is cleared after build is completed
15980      * @type {boolean} true  (default false)
15981      */
15982      
15983     build_from_html : false,
15984
15985     /**
15986      * Register components to be built later.
15987      *
15988      * This solves the following issues
15989      * - Building is not done on page load, but after an authentication process has occured.
15990      * - Interface elements are registered on page load
15991      * - Parent Interface elements may not be loaded before child, so this handles that..
15992      * 
15993      *
15994      * example:
15995      * 
15996      * MyApp.register({
15997           order : '000001',
15998           module : 'Pman.Tab.projectMgr',
15999           region : 'center',
16000           parent : 'Pman.layout',
16001           disabled : false,  // or use a function..
16002         })
16003      
16004      * * @param {Object} details about module
16005      */
16006     register : function(obj) {
16007                 
16008         Roo.XComponent.event.fireEvent('register', obj);
16009         switch(typeof(obj.disabled) ) {
16010                 
16011             case 'undefined':
16012                 break;
16013             
16014             case 'function':
16015                 if ( obj.disabled() ) {
16016                         return;
16017                 }
16018                 break;
16019             
16020             default:
16021                 if (obj.disabled) {
16022                         return;
16023                 }
16024                 break;
16025         }
16026                 
16027         this.modules.push(obj);
16028          
16029     },
16030     /**
16031      * convert a string to an object..
16032      * eg. 'AAA.BBB' -> finds AAA.BBB
16033
16034      */
16035     
16036     toObject : function(str)
16037     {
16038         if (!str || typeof(str) == 'object') {
16039             return str;
16040         }
16041         if (str.substring(0,1) == '#') {
16042             return str;
16043         }
16044
16045         var ar = str.split('.');
16046         var rt, o;
16047         rt = ar.shift();
16048             /** eval:var:o */
16049         try {
16050             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16051         } catch (e) {
16052             throw "Module not found : " + str;
16053         }
16054         
16055         if (o === false) {
16056             throw "Module not found : " + str;
16057         }
16058         Roo.each(ar, function(e) {
16059             if (typeof(o[e]) == 'undefined') {
16060                 throw "Module not found : " + str;
16061             }
16062             o = o[e];
16063         });
16064         
16065         return o;
16066         
16067     },
16068     
16069     
16070     /**
16071      * move modules into their correct place in the tree..
16072      * 
16073      */
16074     preBuild : function ()
16075     {
16076         var _t = this;
16077         Roo.each(this.modules , function (obj)
16078         {
16079             Roo.XComponent.event.fireEvent('beforebuild', obj);
16080             
16081             var opar = obj.parent;
16082             try { 
16083                 obj.parent = this.toObject(opar);
16084             } catch(e) {
16085                 Roo.log("parent:toObject failed: " + e.toString());
16086                 return;
16087             }
16088             
16089             if (!obj.parent) {
16090                 Roo.debug && Roo.log("GOT top level module");
16091                 Roo.debug && Roo.log(obj);
16092                 obj.modules = new Roo.util.MixedCollection(false, 
16093                     function(o) { return o.order + '' }
16094                 );
16095                 this.topModule = obj;
16096                 return;
16097             }
16098                         // parent is a string (usually a dom element name..)
16099             if (typeof(obj.parent) == 'string') {
16100                 this.elmodules.push(obj);
16101                 return;
16102             }
16103             if (obj.parent.constructor != Roo.XComponent) {
16104                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16105             }
16106             if (!obj.parent.modules) {
16107                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16108                     function(o) { return o.order + '' }
16109                 );
16110             }
16111             if (obj.parent.disabled) {
16112                 obj.disabled = true;
16113             }
16114             obj.parent.modules.add(obj);
16115         }, this);
16116     },
16117     
16118      /**
16119      * make a list of modules to build.
16120      * @return {Array} list of modules. 
16121      */ 
16122     
16123     buildOrder : function()
16124     {
16125         var _this = this;
16126         var cmp = function(a,b) {   
16127             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16128         };
16129         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16130             throw "No top level modules to build";
16131         }
16132         
16133         // make a flat list in order of modules to build.
16134         var mods = this.topModule ? [ this.topModule ] : [];
16135                 
16136         
16137         // elmodules (is a list of DOM based modules )
16138         Roo.each(this.elmodules, function(e) {
16139             mods.push(e);
16140             if (!this.topModule &&
16141                 typeof(e.parent) == 'string' &&
16142                 e.parent.substring(0,1) == '#' &&
16143                 Roo.get(e.parent.substr(1))
16144                ) {
16145                 
16146                 _this.topModule = e;
16147             }
16148             
16149         });
16150
16151         
16152         // add modules to their parents..
16153         var addMod = function(m) {
16154             Roo.debug && Roo.log("build Order: add: " + m.name);
16155                 
16156             mods.push(m);
16157             if (m.modules && !m.disabled) {
16158                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16159                 m.modules.keySort('ASC',  cmp );
16160                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16161     
16162                 m.modules.each(addMod);
16163             } else {
16164                 Roo.debug && Roo.log("build Order: no child modules");
16165             }
16166             // not sure if this is used any more..
16167             if (m.finalize) {
16168                 m.finalize.name = m.name + " (clean up) ";
16169                 mods.push(m.finalize);
16170             }
16171             
16172         }
16173         if (this.topModule && this.topModule.modules) { 
16174             this.topModule.modules.keySort('ASC',  cmp );
16175             this.topModule.modules.each(addMod);
16176         } 
16177         return mods;
16178     },
16179     
16180      /**
16181      * Build the registered modules.
16182      * @param {Object} parent element.
16183      * @param {Function} optional method to call after module has been added.
16184      * 
16185      */ 
16186    
16187     build : function(opts) 
16188     {
16189         
16190         if (typeof(opts) != 'undefined') {
16191             Roo.apply(this,opts);
16192         }
16193         
16194         this.preBuild();
16195         var mods = this.buildOrder();
16196       
16197         //this.allmods = mods;
16198         //Roo.debug && Roo.log(mods);
16199         //return;
16200         if (!mods.length) { // should not happen
16201             throw "NO modules!!!";
16202         }
16203         
16204         
16205         var msg = "Building Interface...";
16206         // flash it up as modal - so we store the mask!?
16207         if (!this.hideProgress && Roo.MessageBox) {
16208             Roo.MessageBox.show({ title: 'loading' });
16209             Roo.MessageBox.show({
16210                title: "Please wait...",
16211                msg: msg,
16212                width:450,
16213                progress:true,
16214                closable:false,
16215                modal: false
16216               
16217             });
16218         }
16219         var total = mods.length;
16220         
16221         var _this = this;
16222         var progressRun = function() {
16223             if (!mods.length) {
16224                 Roo.debug && Roo.log('hide?');
16225                 if (!this.hideProgress && Roo.MessageBox) {
16226                     Roo.MessageBox.hide();
16227                 }
16228                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16229                 
16230                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16231                 
16232                 // THE END...
16233                 return false;   
16234             }
16235             
16236             var m = mods.shift();
16237             
16238             
16239             Roo.debug && Roo.log(m);
16240             // not sure if this is supported any more.. - modules that are are just function
16241             if (typeof(m) == 'function') { 
16242                 m.call(this);
16243                 return progressRun.defer(10, _this);
16244             } 
16245             
16246             
16247             msg = "Building Interface " + (total  - mods.length) + 
16248                     " of " + total + 
16249                     (m.name ? (' - ' + m.name) : '');
16250                         Roo.debug && Roo.log(msg);
16251             if (!this.hideProgress &&  Roo.MessageBox) { 
16252                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16253             }
16254             
16255          
16256             // is the module disabled?
16257             var disabled = (typeof(m.disabled) == 'function') ?
16258                 m.disabled.call(m.module.disabled) : m.disabled;    
16259             
16260             
16261             if (disabled) {
16262                 return progressRun(); // we do not update the display!
16263             }
16264             
16265             // now build 
16266             
16267                         
16268                         
16269             m.render();
16270             // it's 10 on top level, and 1 on others??? why...
16271             return progressRun.defer(10, _this);
16272              
16273         }
16274         progressRun.defer(1, _this);
16275      
16276         
16277         
16278     },
16279         
16280         
16281         /**
16282          * Event Object.
16283          *
16284          *
16285          */
16286         event: false, 
16287     /**
16288          * wrapper for event.on - aliased later..  
16289          * Typically use to register a event handler for register:
16290          *
16291          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16292          *
16293          */
16294     on : false
16295    
16296     
16297     
16298 });
16299
16300 Roo.XComponent.event = new Roo.util.Observable({
16301                 events : { 
16302                         /**
16303                          * @event register
16304                          * Fires when an Component is registered,
16305                          * set the disable property on the Component to stop registration.
16306                          * @param {Roo.XComponent} c the component being registerd.
16307                          * 
16308                          */
16309                         'register' : true,
16310             /**
16311                          * @event beforebuild
16312                          * Fires before each Component is built
16313                          * can be used to apply permissions.
16314                          * @param {Roo.XComponent} c the component being registerd.
16315                          * 
16316                          */
16317                         'beforebuild' : true,
16318                         /**
16319                          * @event buildcomplete
16320                          * Fires on the top level element when all elements have been built
16321                          * @param {Roo.XComponent} the top level component.
16322                          */
16323                         'buildcomplete' : true
16324                         
16325                 }
16326 });
16327
16328 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16329