roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64         isTouch =  'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123         
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618         /** @type Boolean */
619         isTouch : isTouch,
620
621         /**
622          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623          * you may want to set this to true.
624          * @type Boolean
625          */
626         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
627         
628         
629                 
630         /**
631          * Selects a single element as a Roo Element
632          * This is about as close as you can get to jQuery's $('do crazy stuff')
633          * @param {String} selector The selector/xpath query
634          * @param {Node} root (optional) The start of the query (defaults to document).
635          * @return {Roo.Element}
636          */
637         selectNode : function(selector, root) 
638         {
639             var node = Roo.DomQuery.selectNode(selector,root);
640             return node ? Roo.get(node) : new Roo.Element(false);
641         }
642         
643     });
644
645
646 })();
647
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 /*
651  * Based on:
652  * Ext JS Library 1.1.1
653  * Copyright(c) 2006-2007, Ext JS, LLC.
654  *
655  * Originally Released Under LGPL - original licence link has changed is not relivant.
656  *
657  * Fork - LGPL
658  * <script type="text/javascript">
659  */
660
661 (function() {    
662     // wrappedn so fnCleanup is not in global scope...
663     if(Roo.isIE) {
664         function fnCleanUp() {
665             var p = Function.prototype;
666             delete p.createSequence;
667             delete p.defer;
668             delete p.createDelegate;
669             delete p.createCallback;
670             delete p.createInterceptor;
671
672             window.detachEvent("onunload", fnCleanUp);
673         }
674         window.attachEvent("onunload", fnCleanUp);
675     }
676 })();
677
678
679 /**
680  * @class Function
681  * These functions are available on every Function object (any JavaScript function).
682  */
683 Roo.apply(Function.prototype, {
684      /**
685      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687      * Will create a function that is bound to those 2 args.
688      * @return {Function} The new function
689     */
690     createCallback : function(/*args...*/){
691         // make args available, in function below
692         var args = arguments;
693         var method = this;
694         return function() {
695             return method.apply(window, args);
696         };
697     },
698
699     /**
700      * Creates a delegate (callback) that sets the scope to obj.
701      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702      * Will create a function that is automatically scoped to this.
703      * @param {Object} obj (optional) The object for which the scope is set
704      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706      *                                             if a number the args are inserted at the specified position
707      * @return {Function} The new function
708      */
709     createDelegate : function(obj, args, appendArgs){
710         var method = this;
711         return function() {
712             var callArgs = args || arguments;
713             if(appendArgs === true){
714                 callArgs = Array.prototype.slice.call(arguments, 0);
715                 callArgs = callArgs.concat(args);
716             }else if(typeof appendArgs == "number"){
717                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
720             }
721             return method.apply(obj || window, callArgs);
722         };
723     },
724
725     /**
726      * Calls this function after the number of millseconds specified.
727      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728      * @param {Object} obj (optional) The object for which the scope is set
729      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731      *                                             if a number the args are inserted at the specified position
732      * @return {Number} The timeout id that can be used with clearTimeout
733      */
734     defer : function(millis, obj, args, appendArgs){
735         var fn = this.createDelegate(obj, args, appendArgs);
736         if(millis){
737             return setTimeout(fn, millis);
738         }
739         fn();
740         return 0;
741     },
742     /**
743      * Create a combined function call sequence of the original function + the passed function.
744      * The resulting function returns the results of the original function.
745      * The passed fcn is called with the parameters of the original function
746      * @param {Function} fcn The function to sequence
747      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748      * @return {Function} The new function
749      */
750     createSequence : function(fcn, scope){
751         if(typeof fcn != "function"){
752             return this;
753         }
754         var method = this;
755         return function() {
756             var retval = method.apply(this || window, arguments);
757             fcn.apply(scope || this || window, arguments);
758             return retval;
759         };
760     },
761
762     /**
763      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function.
766      * @addon
767      * @param {Function} fcn The function to call before the original
768      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769      * @return {Function} The new function
770      */
771     createInterceptor : function(fcn, scope){
772         if(typeof fcn != "function"){
773             return this;
774         }
775         var method = this;
776         return function() {
777             fcn.target = this;
778             fcn.method = method;
779             if(fcn.apply(scope || this || window, arguments) === false){
780                 return;
781             }
782             return method.apply(this || window, arguments);
783         };
784     }
785 });
786 /*
787  * Based on:
788  * Ext JS Library 1.1.1
789  * Copyright(c) 2006-2007, Ext JS, LLC.
790  *
791  * Originally Released Under LGPL - original licence link has changed is not relivant.
792  *
793  * Fork - LGPL
794  * <script type="text/javascript">
795  */
796
797 Roo.applyIf(String, {
798     
799     /** @scope String */
800     
801     /**
802      * Escapes the passed string for ' and \
803      * @param {String} string The string to escape
804      * @return {String} The escaped string
805      * @static
806      */
807     escape : function(string) {
808         return string.replace(/('|\\)/g, "\\$1");
809     },
810
811     /**
812      * Pads the left side of a string with a specified character.  This is especially useful
813      * for normalizing number and date strings.  Example usage:
814      * <pre><code>
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
817 </code></pre>
818      * @param {String} string The original string
819      * @param {Number} size The total length of the output string
820      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821      * @return {String} The padded string
822      * @static
823      */
824     leftPad : function (val, size, ch) {
825         var result = new String(val);
826         if(ch === null || ch === undefined || ch === '') {
827             ch = " ";
828         }
829         while (result.length < size) {
830             result = ch + result;
831         }
832         return result;
833     },
834
835     /**
836      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
837      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
838      * <pre><code>
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
842 </code></pre>
843      * @param {String} string The tokenized string to be formatted
844      * @param {String} value1 The value to replace token {0}
845      * @param {String} value2 Etc...
846      * @return {String} The formatted string
847      * @static
848      */
849     format : function(format){
850         var args = Array.prototype.slice.call(arguments, 1);
851         return format.replace(/\{(\d+)\}/g, function(m, i){
852             return Roo.util.Format.htmlEncode(args[i]);
853         });
854     }
855 });
856
857 /**
858  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
859  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
860  * they are already different, the first value passed in is returned.  Note that this method returns the new value
861  * but does not change the current string.
862  * <pre><code>
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
865
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
868 </code></pre>
869  * @param {String} value The value to compare to the current string
870  * @param {String} other The new value to use if the string already equals the first value passed in
871  * @return {String} The new value
872  */
873  
874 String.prototype.toggle = function(value, other){
875     return this == value ? other : value;
876 };/*
877  * Based on:
878  * Ext JS Library 1.1.1
879  * Copyright(c) 2006-2007, Ext JS, LLC.
880  *
881  * Originally Released Under LGPL - original licence link has changed is not relivant.
882  *
883  * Fork - LGPL
884  * <script type="text/javascript">
885  */
886
887  /**
888  * @class Number
889  */
890 Roo.applyIf(Number.prototype, {
891     /**
892      * Checks whether or not the current number is within a desired range.  If the number is already within the
893      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894      * exceeded.  Note that this method returns the constrained value but does not change the current number.
895      * @param {Number} min The minimum number in the range
896      * @param {Number} max The maximum number in the range
897      * @return {Number} The constrained value if outside the range, otherwise the current value
898      */
899     constrain : function(min, max){
900         return Math.min(Math.max(this, min), max);
901     }
902 });/*
903  * Based on:
904  * Ext JS Library 1.1.1
905  * Copyright(c) 2006-2007, Ext JS, LLC.
906  *
907  * Originally Released Under LGPL - original licence link has changed is not relivant.
908  *
909  * Fork - LGPL
910  * <script type="text/javascript">
911  */
912  /**
913  * @class Array
914  */
915 Roo.applyIf(Array.prototype, {
916     /**
917      * Checks whether or not the specified object exists in the array.
918      * @param {Object} o The object to check for
919      * @return {Number} The index of o in the array (or -1 if it is not found)
920      */
921     indexOf : function(o){
922        for (var i = 0, len = this.length; i < len; i++){
923               if(this[i] == o) return i;
924        }
925            return -1;
926     },
927
928     /**
929      * Removes the specified object from the array.  If the object is not found nothing happens.
930      * @param {Object} o The object to remove
931      */
932     remove : function(o){
933        var index = this.indexOf(o);
934        if(index != -1){
935            this.splice(index, 1);
936        }
937     },
938     /**
939      * Map (JS 1.6 compatibility)
940      * @param {Function} function  to call
941      */
942     map : function(fun )
943     {
944         var len = this.length >>> 0;
945         if (typeof fun != "function")
946             throw new TypeError();
947
948         var res = new Array(len);
949         var thisp = arguments[1];
950         for (var i = 0; i < len; i++)
951         {
952             if (i in this)
953                 res[i] = fun.call(thisp, this[i], i, this);
954         }
955
956         return res;
957     }
958     
959 });
960
961
962  /*
963  * Based on:
964  * Ext JS Library 1.1.1
965  * Copyright(c) 2006-2007, Ext JS, LLC.
966  *
967  * Originally Released Under LGPL - original licence link has changed is not relivant.
968  *
969  * Fork - LGPL
970  * <script type="text/javascript">
971  */
972
973 /**
974  * @class Date
975  *
976  * The date parsing and format syntax is a subset of
977  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978  * supported will provide results equivalent to their PHP versions.
979  *
980  * Following is the list of all currently supported formats:
981  *<pre>
982 Sample date:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
984
985 Format  Output      Description
986 ------  ----------  --------------------------------------------------------------
987   d      10         Day of the month, 2 digits with leading zeros
988   D      Wed        A textual representation of a day, three letters
989   j      10         Day of the month without leading zeros
990   l      Wednesday  A full textual representation of the day of the week
991   S      th         English ordinal day of month suffix, 2 chars (use with j)
992   w      3          Numeric representation of the day of the week
993   z      9          The julian date, or day of the year (0-365)
994   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995   F      January    A full textual representation of the month
996   m      01         Numeric representation of a month, with leading zeros
997   M      Jan        Month name abbreviation, three letters
998   n      1          Numeric representation of a month, without leading zeros
999   t      31         Number of days in the given month
1000   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1001   Y      2007       A full numeric representation of a year, 4 digits
1002   y      07         A two digit representation of a year
1003   a      pm         Lowercase Ante meridiem and Post meridiem
1004   A      PM         Uppercase Ante meridiem and Post meridiem
1005   g      3          12-hour format of an hour without leading zeros
1006   G      15         24-hour format of an hour without leading zeros
1007   h      03         12-hour format of an hour with leading zeros
1008   H      15         24-hour format of an hour with leading zeros
1009   i      05         Minutes with leading zeros
1010   s      01         Seconds, with leading zeros
1011   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1013   T      CST        Timezone setting of the machine running the code
1014   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1015 </pre>
1016  *
1017  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1018  * <pre><code>
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d'));                         //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1023  </code></pre>
1024  *
1025  * Here are some standard date/time patterns that you might find helpful.  They
1026  * are not part of the source of Date.js, but to use them you can simply copy this
1027  * block of code into any script that is included after Date.js and they will also become
1028  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1029  * <pre><code>
1030 Date.patterns = {
1031     ISO8601Long:"Y-m-d H:i:s",
1032     ISO8601Short:"Y-m-d",
1033     ShortDate: "n/j/Y",
1034     LongDate: "l, F d, Y",
1035     FullDateTime: "l, F d, Y g:i:s A",
1036     MonthDay: "F d",
1037     ShortTime: "g:i A",
1038     LongTime: "g:i:s A",
1039     SortableDateTime: "Y-m-d\\TH:i:s",
1040     UniversalSortableDateTime: "Y-m-d H:i:sO",
1041     YearMonth: "F, Y"
1042 };
1043 </code></pre>
1044  *
1045  * Example usage:
1046  * <pre><code>
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1049  </code></pre>
1050  */
1051
1052 /*
1053  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054  * They generate precompiled functions from date formats instead of parsing and
1055  * processing the pattern every time you format a date.  These functions are available
1056  * on every Date object (any javascript function).
1057  *
1058  * The original article and download are here:
1059  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1060  *
1061  */
1062  
1063  
1064  // was in core
1065 /**
1066  Returns the number of milliseconds between this date and date
1067  @param {Date} date (optional) Defaults to now
1068  @return {Number} The diff in milliseconds
1069  @member Date getElapsed
1070  */
1071 Date.prototype.getElapsed = function(date) {
1072         return Math.abs((date || new Date()).getTime()-this.getTime());
1073 };
1074 // was in date file..
1075
1076
1077 // private
1078 Date.parseFunctions = {count:0};
1079 // private
1080 Date.parseRegexes = [];
1081 // private
1082 Date.formatFunctions = {count:0};
1083
1084 // private
1085 Date.prototype.dateFormat = function(format) {
1086     if (Date.formatFunctions[format] == null) {
1087         Date.createNewFormat(format);
1088     }
1089     var func = Date.formatFunctions[format];
1090     return this[func]();
1091 };
1092
1093
1094 /**
1095  * Formats a date given the supplied format string
1096  * @param {String} format The format string
1097  * @return {String} The formatted date
1098  * @method
1099  */
1100 Date.prototype.format = Date.prototype.dateFormat;
1101
1102 // private
1103 Date.createNewFormat = function(format) {
1104     var funcName = "format" + Date.formatFunctions.count++;
1105     Date.formatFunctions[format] = funcName;
1106     var code = "Date.prototype." + funcName + " = function(){return ";
1107     var special = false;
1108     var ch = '';
1109     for (var i = 0; i < format.length; ++i) {
1110         ch = format.charAt(i);
1111         if (!special && ch == "\\") {
1112             special = true;
1113         }
1114         else if (special) {
1115             special = false;
1116             code += "'" + String.escape(ch) + "' + ";
1117         }
1118         else {
1119             code += Date.getFormatCode(ch);
1120         }
1121     }
1122     /** eval:var:zzzzzzzzzzzzz */
1123     eval(code.substring(0, code.length - 3) + ";}");
1124 };
1125
1126 // private
1127 Date.getFormatCode = function(character) {
1128     switch (character) {
1129     case "d":
1130         return "String.leftPad(this.getDate(), 2, '0') + ";
1131     case "D":
1132         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1133     case "j":
1134         return "this.getDate() + ";
1135     case "l":
1136         return "Date.dayNames[this.getDay()] + ";
1137     case "S":
1138         return "this.getSuffix() + ";
1139     case "w":
1140         return "this.getDay() + ";
1141     case "z":
1142         return "this.getDayOfYear() + ";
1143     case "W":
1144         return "this.getWeekOfYear() + ";
1145     case "F":
1146         return "Date.monthNames[this.getMonth()] + ";
1147     case "m":
1148         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1149     case "M":
1150         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1151     case "n":
1152         return "(this.getMonth() + 1) + ";
1153     case "t":
1154         return "this.getDaysInMonth() + ";
1155     case "L":
1156         return "(this.isLeapYear() ? 1 : 0) + ";
1157     case "Y":
1158         return "this.getFullYear() + ";
1159     case "y":
1160         return "('' + this.getFullYear()).substring(2, 4) + ";
1161     case "a":
1162         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1163     case "A":
1164         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1165     case "g":
1166         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1167     case "G":
1168         return "this.getHours() + ";
1169     case "h":
1170         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1171     case "H":
1172         return "String.leftPad(this.getHours(), 2, '0') + ";
1173     case "i":
1174         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1175     case "s":
1176         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1177     case "O":
1178         return "this.getGMTOffset() + ";
1179     case "P":
1180         return "this.getGMTColonOffset() + ";
1181     case "T":
1182         return "this.getTimezone() + ";
1183     case "Z":
1184         return "(this.getTimezoneOffset() * -60) + ";
1185     default:
1186         return "'" + String.escape(character) + "' + ";
1187     }
1188 };
1189
1190 /**
1191  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1193  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1194  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1195  * string or the parse operation will fail.
1196  * Example Usage:
1197 <pre><code>
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1200
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1203
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1206
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1209 </code></pre>
1210  * @param {String} input The unparsed date as a string
1211  * @param {String} format The format the date is in
1212  * @return {Date} The parsed date
1213  * @static
1214  */
1215 Date.parseDate = function(input, format) {
1216     if (Date.parseFunctions[format] == null) {
1217         Date.createParser(format);
1218     }
1219     var func = Date.parseFunctions[format];
1220     return Date[func](input);
1221 };
1222 /**
1223  * @private
1224  */
1225 Date.createParser = function(format) {
1226     var funcName = "parse" + Date.parseFunctions.count++;
1227     var regexNum = Date.parseRegexes.length;
1228     var currentGroup = 1;
1229     Date.parseFunctions[format] = funcName;
1230
1231     var code = "Date." + funcName + " = function(input){\n"
1232         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233         + "var d = new Date();\n"
1234         + "y = d.getFullYear();\n"
1235         + "m = d.getMonth();\n"
1236         + "d = d.getDate();\n"
1237         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238         + "if (results && results.length > 0) {";
1239     var regex = "";
1240
1241     var special = false;
1242     var ch = '';
1243     for (var i = 0; i < format.length; ++i) {
1244         ch = format.charAt(i);
1245         if (!special && ch == "\\") {
1246             special = true;
1247         }
1248         else if (special) {
1249             special = false;
1250             regex += String.escape(ch);
1251         }
1252         else {
1253             var obj = Date.formatCodeToRegex(ch, currentGroup);
1254             currentGroup += obj.g;
1255             regex += obj.s;
1256             if (obj.g && obj.c) {
1257                 code += obj.c;
1258             }
1259         }
1260     }
1261
1262     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i, s);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265         + "{v = new Date(y, m, d, h, i);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267         + "{v = new Date(y, m, d, h);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269         + "{v = new Date(y, m, d);}\n"
1270         + "else if (y >= 0 && m >= 0)\n"
1271         + "{v = new Date(y, m);}\n"
1272         + "else if (y >= 0)\n"
1273         + "{v = new Date(y);}\n"
1274         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277         + ";}";
1278
1279     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280     /** eval:var:zzzzzzzzzzzzz */
1281     eval(code);
1282 };
1283
1284 // private
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286     switch (character) {
1287     case "D":
1288         return {g:0,
1289         c:null,
1290         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291     case "j":
1292         return {g:1,
1293             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294             s:"(\\d{1,2})"}; // day of month without leading zeroes
1295     case "d":
1296         return {g:1,
1297             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{2})"}; // day of month with leading zeroes
1299     case "l":
1300         return {g:0,
1301             c:null,
1302             s:"(?:" + Date.dayNames.join("|") + ")"};
1303     case "S":
1304         return {g:0,
1305             c:null,
1306             s:"(?:st|nd|rd|th)"};
1307     case "w":
1308         return {g:0,
1309             c:null,
1310             s:"\\d"};
1311     case "z":
1312         return {g:0,
1313             c:null,
1314             s:"(?:\\d{1,3})"};
1315     case "W":
1316         return {g:0,
1317             c:null,
1318             s:"(?:\\d{2})"};
1319     case "F":
1320         return {g:1,
1321             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322             s:"(" + Date.monthNames.join("|") + ")"};
1323     case "M":
1324         return {g:1,
1325             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327     case "n":
1328         return {g:1,
1329             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331     case "m":
1332         return {g:1,
1333             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1335     case "t":
1336         return {g:0,
1337             c:null,
1338             s:"\\d{1,2}"};
1339     case "L":
1340         return {g:0,
1341             c:null,
1342             s:"(?:1|0)"};
1343     case "Y":
1344         return {g:1,
1345             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1346             s:"(\\d{4})"};
1347     case "y":
1348         return {g:1,
1349             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1351             s:"(\\d{1,2})"};
1352     case "a":
1353         return {g:1,
1354             c:"if (results[" + currentGroup + "] == 'am') {\n"
1355                 + "if (h == 12) { h = 0; }\n"
1356                 + "} else { if (h < 12) { h += 12; }}",
1357             s:"(am|pm)"};
1358     case "A":
1359         return {g:1,
1360             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361                 + "if (h == 12) { h = 0; }\n"
1362                 + "} else { if (h < 12) { h += 12; }}",
1363             s:"(AM|PM)"};
1364     case "g":
1365     case "G":
1366         return {g:1,
1367             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1369     case "h":
1370     case "H":
1371         return {g:1,
1372             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1374     case "i":
1375         return {g:1,
1376             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1377             s:"(\\d{2})"};
1378     case "s":
1379         return {g:1,
1380             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{2})"};
1382     case "O":
1383         return {g:1,
1384             c:[
1385                 "o = results[", currentGroup, "];\n",
1386                 "var sn = o.substring(0,1);\n", // get + / - sign
1387                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391             ].join(""),
1392             s:"([+\-]\\d{2,4})"};
1393     
1394     
1395     case "P":
1396         return {g:1,
1397                 c:[
1398                    "o = results[", currentGroup, "];\n",
1399                    "var sn = o.substring(0,1);\n",
1400                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401                    "var mn = o.substring(4,6) % 60;\n",
1402                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1404             ].join(""),
1405             s:"([+\-]\\d{4})"};
1406     case "T":
1407         return {g:0,
1408             c:null,
1409             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410     case "Z":
1411         return {g:1,
1412             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1415     default:
1416         return {g:0,
1417             c:null,
1418             s:String.escape(character)};
1419     }
1420 };
1421
1422 /**
1423  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424  * @return {String} The abbreviated timezone name (e.g. 'CST')
1425  */
1426 Date.prototype.getTimezone = function() {
1427     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1428 };
1429
1430 /**
1431  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1433  */
1434 Date.prototype.getGMTOffset = function() {
1435     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1438 };
1439
1440 /**
1441  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442  * @return {String} 2-characters representing hours and 2-characters representing minutes
1443  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1444  */
1445 Date.prototype.getGMTColonOffset = function() {
1446         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1448                 + ":"
1449                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1450 }
1451
1452 /**
1453  * Get the numeric day number of the year, adjusted for leap year.
1454  * @return {Number} 0 through 364 (365 in leap years)
1455  */
1456 Date.prototype.getDayOfYear = function() {
1457     var num = 0;
1458     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459     for (var i = 0; i < this.getMonth(); ++i) {
1460         num += Date.daysInMonth[i];
1461     }
1462     return num + this.getDate() - 1;
1463 };
1464
1465 /**
1466  * Get the string representation of the numeric week number of the year
1467  * (equivalent to the format specifier 'W').
1468  * @return {String} '00' through '52'
1469  */
1470 Date.prototype.getWeekOfYear = function() {
1471     // Skip to Thursday of this week
1472     var now = this.getDayOfYear() + (4 - this.getDay());
1473     // Find the first Thursday of the year
1474     var jan1 = new Date(this.getFullYear(), 0, 1);
1475     var then = (7 - jan1.getDay() + 4);
1476     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1477 };
1478
1479 /**
1480  * Whether or not the current date is in a leap year.
1481  * @return {Boolean} True if the current date is in a leap year, else false
1482  */
1483 Date.prototype.isLeapYear = function() {
1484     var year = this.getFullYear();
1485     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1486 };
1487
1488 /**
1489  * Get the first day of the current month, adjusted for leap year.  The returned value
1490  * is the numeric day index within the week (0-6) which can be used in conjunction with
1491  * the {@link #monthNames} array to retrieve the textual day name.
1492  * Example:
1493  *<pre><code>
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1496 </code></pre>
1497  * @return {Number} The day number (0-6)
1498  */
1499 Date.prototype.getFirstDayOfMonth = function() {
1500     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501     return (day < 0) ? (day + 7) : day;
1502 };
1503
1504 /**
1505  * Get the last day of the current month, adjusted for leap year.  The returned value
1506  * is the numeric day index within the week (0-6) which can be used in conjunction with
1507  * the {@link #monthNames} array to retrieve the textual day name.
1508  * Example:
1509  *<pre><code>
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1512 </code></pre>
1513  * @return {Number} The day number (0-6)
1514  */
1515 Date.prototype.getLastDayOfMonth = function() {
1516     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517     return (day < 0) ? (day + 7) : day;
1518 };
1519
1520
1521 /**
1522  * Get the first date of this date's month
1523  * @return {Date}
1524  */
1525 Date.prototype.getFirstDateOfMonth = function() {
1526     return new Date(this.getFullYear(), this.getMonth(), 1);
1527 };
1528
1529 /**
1530  * Get the last date of this date's month
1531  * @return {Date}
1532  */
1533 Date.prototype.getLastDateOfMonth = function() {
1534     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 };
1536 /**
1537  * Get the number of days in the current month, adjusted for leap year.
1538  * @return {Number} The number of days in the month
1539  */
1540 Date.prototype.getDaysInMonth = function() {
1541     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542     return Date.daysInMonth[this.getMonth()];
1543 };
1544
1545 /**
1546  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547  * @return {String} 'st, 'nd', 'rd' or 'th'
1548  */
1549 Date.prototype.getSuffix = function() {
1550     switch (this.getDate()) {
1551         case 1:
1552         case 21:
1553         case 31:
1554             return "st";
1555         case 2:
1556         case 22:
1557             return "nd";
1558         case 3:
1559         case 23:
1560             return "rd";
1561         default:
1562             return "th";
1563     }
1564 };
1565
1566 // private
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568
1569 /**
1570  * An array of textual month names.
1571  * Override these values for international dates, for example...
1572  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1573  * @type Array
1574  * @static
1575  */
1576 Date.monthNames =
1577    ["January",
1578     "February",
1579     "March",
1580     "April",
1581     "May",
1582     "June",
1583     "July",
1584     "August",
1585     "September",
1586     "October",
1587     "November",
1588     "December"];
1589
1590 /**
1591  * An array of textual day names.
1592  * Override these values for international dates, for example...
1593  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1594  * @type Array
1595  * @static
1596  */
1597 Date.dayNames =
1598    ["Sunday",
1599     "Monday",
1600     "Tuesday",
1601     "Wednesday",
1602     "Thursday",
1603     "Friday",
1604     "Saturday"];
1605
1606 // private
1607 Date.y2kYear = 50;
1608 // private
1609 Date.monthNumbers = {
1610     Jan:0,
1611     Feb:1,
1612     Mar:2,
1613     Apr:3,
1614     May:4,
1615     Jun:5,
1616     Jul:6,
1617     Aug:7,
1618     Sep:8,
1619     Oct:9,
1620     Nov:10,
1621     Dec:11};
1622
1623 /**
1624  * Creates and returns a new Date instance with the exact same date value as the called instance.
1625  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626  * variable will also be changed.  When the intention is to create a new variable that will not
1627  * modify the original instance, you should create a clone.
1628  *
1629  * Example of correctly cloning a date:
1630  * <pre><code>
1631 //wrong way:
1632 var orig = new Date('10/1/2006');
1633 var copy = orig;
1634 copy.setDate(5);
1635 document.write(orig);  //returns 'Thu Oct 05 2006'!
1636
1637 //correct way:
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1640 copy.setDate(5);
1641 document.write(orig);  //returns 'Thu Oct 01 2006'
1642 </code></pre>
1643  * @return {Date} The new Date instance
1644  */
1645 Date.prototype.clone = function() {
1646         return new Date(this.getTime());
1647 };
1648
1649 /**
1650  * Clears any time information from this date
1651  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652  @return {Date} this or the clone
1653  */
1654 Date.prototype.clearTime = function(clone){
1655     if(clone){
1656         return this.clone().clearTime();
1657     }
1658     this.setHours(0);
1659     this.setMinutes(0);
1660     this.setSeconds(0);
1661     this.setMilliseconds(0);
1662     return this;
1663 };
1664
1665 // private
1666 // safari setMonth is broken
1667 if(Roo.isSafari){
1668     Date.brokenSetMonth = Date.prototype.setMonth;
1669         Date.prototype.setMonth = function(num){
1670                 if(num <= -1){
1671                         var n = Math.ceil(-num);
1672                         var back_year = Math.ceil(n/12);
1673                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1674                         this.setFullYear(this.getFullYear() - back_year);
1675                         return Date.brokenSetMonth.call(this, month);
1676                 } else {
1677                         return Date.brokenSetMonth.apply(this, arguments);
1678                 }
1679         };
1680 }
1681
1682 /** Date interval constant 
1683 * @static 
1684 * @type String */
1685 Date.MILLI = "ms";
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.SECOND = "s";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.MINUTE = "mi";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.HOUR = "h";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.DAY = "d";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MONTH = "mo";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.YEAR = "y";
1710
1711 /**
1712  * Provides a convenient method of performing basic date arithmetic.  This method
1713  * does not modify the Date instance being called - it creates and returns
1714  * a new Date instance containing the resulting date value.
1715  *
1716  * Examples:
1717  * <pre><code>
1718 //Basic usage:
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1721
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1725
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729  </code></pre>
1730  *
1731  * @param {String} interval   A valid date interval enum value
1732  * @param {Number} value      The amount to add to the current date
1733  * @return {Date} The new Date instance
1734  */
1735 Date.prototype.add = function(interval, value){
1736   var d = this.clone();
1737   if (!interval || value === 0) return d;
1738   switch(interval.toLowerCase()){
1739     case Date.MILLI:
1740       d.setMilliseconds(this.getMilliseconds() + value);
1741       break;
1742     case Date.SECOND:
1743       d.setSeconds(this.getSeconds() + value);
1744       break;
1745     case Date.MINUTE:
1746       d.setMinutes(this.getMinutes() + value);
1747       break;
1748     case Date.HOUR:
1749       d.setHours(this.getHours() + value);
1750       break;
1751     case Date.DAY:
1752       d.setDate(this.getDate() + value);
1753       break;
1754     case Date.MONTH:
1755       var day = this.getDate();
1756       if(day > 28){
1757           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758       }
1759       d.setDate(day);
1760       d.setMonth(this.getMonth() + value);
1761       break;
1762     case Date.YEAR:
1763       d.setFullYear(this.getFullYear() + value);
1764       break;
1765   }
1766   return d;
1767 };
1768 /*
1769  * Based on:
1770  * Ext JS Library 1.1.1
1771  * Copyright(c) 2006-2007, Ext JS, LLC.
1772  *
1773  * Originally Released Under LGPL - original licence link has changed is not relivant.
1774  *
1775  * Fork - LGPL
1776  * <script type="text/javascript">
1777  */
1778
1779 /**
1780  * @class Roo.lib.Dom
1781  * @static
1782  * 
1783  * Dom utils (from YIU afaik)
1784  * 
1785  **/
1786 Roo.lib.Dom = {
1787     /**
1788      * Get the view width
1789      * @param {Boolean} full True will get the full document, otherwise it's the view width
1790      * @return {Number} The width
1791      */
1792      
1793     getViewWidth : function(full) {
1794         return full ? this.getDocumentWidth() : this.getViewportWidth();
1795     },
1796     /**
1797      * Get the view height
1798      * @param {Boolean} full True will get the full document, otherwise it's the view height
1799      * @return {Number} The height
1800      */
1801     getViewHeight : function(full) {
1802         return full ? this.getDocumentHeight() : this.getViewportHeight();
1803     },
1804
1805     getDocumentHeight: function() {
1806         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807         return Math.max(scrollHeight, this.getViewportHeight());
1808     },
1809
1810     getDocumentWidth: function() {
1811         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812         return Math.max(scrollWidth, this.getViewportWidth());
1813     },
1814
1815     getViewportHeight: function() {
1816         var height = self.innerHeight;
1817         var mode = document.compatMode;
1818
1819         if ((mode || Roo.isIE) && !Roo.isOpera) {
1820             height = (mode == "CSS1Compat") ?
1821                      document.documentElement.clientHeight :
1822                      document.body.clientHeight;
1823         }
1824
1825         return height;
1826     },
1827
1828     getViewportWidth: function() {
1829         var width = self.innerWidth;
1830         var mode = document.compatMode;
1831
1832         if (mode || Roo.isIE) {
1833             width = (mode == "CSS1Compat") ?
1834                     document.documentElement.clientWidth :
1835                     document.body.clientWidth;
1836         }
1837         return width;
1838     },
1839
1840     isAncestor : function(p, c) {
1841         p = Roo.getDom(p);
1842         c = Roo.getDom(c);
1843         if (!p || !c) {
1844             return false;
1845         }
1846
1847         if (p.contains && !Roo.isSafari) {
1848             return p.contains(c);
1849         } else if (p.compareDocumentPosition) {
1850             return !!(p.compareDocumentPosition(c) & 16);
1851         } else {
1852             var parent = c.parentNode;
1853             while (parent) {
1854                 if (parent == p) {
1855                     return true;
1856                 }
1857                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858                     return false;
1859                 }
1860                 parent = parent.parentNode;
1861             }
1862             return false;
1863         }
1864     },
1865
1866     getRegion : function(el) {
1867         return Roo.lib.Region.getRegion(el);
1868     },
1869
1870     getY : function(el) {
1871         return this.getXY(el)[1];
1872     },
1873
1874     getX : function(el) {
1875         return this.getXY(el)[0];
1876     },
1877
1878     getXY : function(el) {
1879         var p, pe, b, scroll, bd = document.body;
1880         el = Roo.getDom(el);
1881         var fly = Roo.lib.AnimBase.fly;
1882         if (el.getBoundingClientRect) {
1883             b = el.getBoundingClientRect();
1884             scroll = fly(document).getScroll();
1885             return [b.left + scroll.left, b.top + scroll.top];
1886         }
1887         var x = 0, y = 0;
1888
1889         p = el;
1890
1891         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1892
1893         while (p) {
1894
1895             x += p.offsetLeft;
1896             y += p.offsetTop;
1897
1898             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1899                 hasAbsolute = true;
1900             }
1901
1902             if (Roo.isGecko) {
1903                 pe = fly(p);
1904
1905                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1907
1908
1909                 x += bl;
1910                 y += bt;
1911
1912
1913                 if (p != el && pe.getStyle('overflow') != 'visible') {
1914                     x += bl;
1915                     y += bt;
1916                 }
1917             }
1918             p = p.offsetParent;
1919         }
1920
1921         if (Roo.isSafari && hasAbsolute) {
1922             x -= bd.offsetLeft;
1923             y -= bd.offsetTop;
1924         }
1925
1926         if (Roo.isGecko && !hasAbsolute) {
1927             var dbd = fly(bd);
1928             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1930         }
1931
1932         p = el.parentNode;
1933         while (p && p != bd) {
1934             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1935                 x -= p.scrollLeft;
1936                 y -= p.scrollTop;
1937             }
1938             p = p.parentNode;
1939         }
1940         return [x, y];
1941     },
1942  
1943   
1944
1945
1946     setXY : function(el, xy) {
1947         el = Roo.fly(el, '_setXY');
1948         el.position();
1949         var pts = el.translatePoints(xy);
1950         if (xy[0] !== false) {
1951             el.dom.style.left = pts.left + "px";
1952         }
1953         if (xy[1] !== false) {
1954             el.dom.style.top = pts.top + "px";
1955         }
1956     },
1957
1958     setX : function(el, x) {
1959         this.setXY(el, [x, false]);
1960     },
1961
1962     setY : function(el, y) {
1963         this.setXY(el, [false, y]);
1964     }
1965 };
1966 /*
1967  * Portions of this file are based on pieces of Yahoo User Interface Library
1968  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969  * YUI licensed under the BSD License:
1970  * http://developer.yahoo.net/yui/license.txt
1971  * <script type="text/javascript">
1972  *
1973  */
1974
1975 Roo.lib.Event = function() {
1976     var loadComplete = false;
1977     var listeners = [];
1978     var unloadListeners = [];
1979     var retryCount = 0;
1980     var onAvailStack = [];
1981     var counter = 0;
1982     var lastError = null;
1983
1984     return {
1985         POLL_RETRYS: 200,
1986         POLL_INTERVAL: 20,
1987         EL: 0,
1988         TYPE: 1,
1989         FN: 2,
1990         WFN: 3,
1991         OBJ: 3,
1992         ADJ_SCOPE: 4,
1993         _interval: null,
1994
1995         startInterval: function() {
1996             if (!this._interval) {
1997                 var self = this;
1998                 var callback = function() {
1999                     self._tryPreloadAttach();
2000                 };
2001                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2002
2003             }
2004         },
2005
2006         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007             onAvailStack.push({ id:         p_id,
2008                 fn:         p_fn,
2009                 obj:        p_obj,
2010                 override:   p_override,
2011                 checkReady: false    });
2012
2013             retryCount = this.POLL_RETRYS;
2014             this.startInterval();
2015         },
2016
2017
2018         addListener: function(el, eventName, fn) {
2019             el = Roo.getDom(el);
2020             if (!el || !fn) {
2021                 return false;
2022             }
2023
2024             if ("unload" == eventName) {
2025                 unloadListeners[unloadListeners.length] =
2026                 [el, eventName, fn];
2027                 return true;
2028             }
2029
2030             var wrappedFn = function(e) {
2031                 return fn(Roo.lib.Event.getEvent(e));
2032             };
2033
2034             var li = [el, eventName, fn, wrappedFn];
2035
2036             var index = listeners.length;
2037             listeners[index] = li;
2038
2039             this.doAdd(el, eventName, wrappedFn, false);
2040             return true;
2041
2042         },
2043
2044
2045         removeListener: function(el, eventName, fn) {
2046             var i, len;
2047
2048             el = Roo.getDom(el);
2049
2050             if(!fn) {
2051                 return this.purgeElement(el, false, eventName);
2052             }
2053
2054
2055             if ("unload" == eventName) {
2056
2057                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058                     var li = unloadListeners[i];
2059                     if (li &&
2060                         li[0] == el &&
2061                         li[1] == eventName &&
2062                         li[2] == fn) {
2063                         unloadListeners.splice(i, 1);
2064                         return true;
2065                     }
2066                 }
2067
2068                 return false;
2069             }
2070
2071             var cacheItem = null;
2072
2073
2074             var index = arguments[3];
2075
2076             if ("undefined" == typeof index) {
2077                 index = this._getCacheIndex(el, eventName, fn);
2078             }
2079
2080             if (index >= 0) {
2081                 cacheItem = listeners[index];
2082             }
2083
2084             if (!el || !cacheItem) {
2085                 return false;
2086             }
2087
2088             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2089
2090             delete listeners[index][this.WFN];
2091             delete listeners[index][this.FN];
2092             listeners.splice(index, 1);
2093
2094             return true;
2095
2096         },
2097
2098
2099         getTarget: function(ev, resolveTextNode) {
2100             ev = ev.browserEvent || ev;
2101             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2102             var t = ev.target || ev.srcElement;
2103             return this.resolveTextNode(t);
2104         },
2105
2106
2107         resolveTextNode: function(node) {
2108             if (Roo.isSafari && node && 3 == node.nodeType) {
2109                 return node.parentNode;
2110             } else {
2111                 return node;
2112             }
2113         },
2114
2115
2116         getPageX: function(ev) {
2117             ev = ev.browserEvent || ev;
2118             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2119             var x = ev.pageX;
2120             if (!x && 0 !== x) {
2121                 x = ev.clientX || 0;
2122
2123                 if (Roo.isIE) {
2124                     x += this.getScroll()[1];
2125                 }
2126             }
2127
2128             return x;
2129         },
2130
2131
2132         getPageY: function(ev) {
2133             ev = ev.browserEvent || ev;
2134             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2135             var y = ev.pageY;
2136             if (!y && 0 !== y) {
2137                 y = ev.clientY || 0;
2138
2139                 if (Roo.isIE) {
2140                     y += this.getScroll()[0];
2141                 }
2142             }
2143
2144
2145             return y;
2146         },
2147
2148
2149         getXY: function(ev) {
2150             ev = ev.browserEvent || ev;
2151             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2152             return [this.getPageX(ev), this.getPageY(ev)];
2153         },
2154
2155
2156         getRelatedTarget: function(ev) {
2157             ev = ev.browserEvent || ev;
2158             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2159             var t = ev.relatedTarget;
2160             if (!t) {
2161                 if (ev.type == "mouseout") {
2162                     t = ev.toElement;
2163                 } else if (ev.type == "mouseover") {
2164                     t = ev.fromElement;
2165                 }
2166             }
2167
2168             return this.resolveTextNode(t);
2169         },
2170
2171
2172         getTime: function(ev) {
2173             ev = ev.browserEvent || ev;
2174             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2175             if (!ev.time) {
2176                 var t = new Date().getTime();
2177                 try {
2178                     ev.time = t;
2179                 } catch(ex) {
2180                     this.lastError = ex;
2181                     return t;
2182                 }
2183             }
2184
2185             return ev.time;
2186         },
2187
2188
2189         stopEvent: function(ev) {
2190             this.stopPropagation(ev);
2191             this.preventDefault(ev);
2192         },
2193
2194
2195         stopPropagation: function(ev) {
2196             ev = ev.browserEvent || ev;
2197             if (ev.stopPropagation) {
2198                 ev.stopPropagation();
2199             } else {
2200                 ev.cancelBubble = true;
2201             }
2202         },
2203
2204
2205         preventDefault: function(ev) {
2206             ev = ev.browserEvent || ev;
2207             if(ev.preventDefault) {
2208                 ev.preventDefault();
2209             } else {
2210                 ev.returnValue = false;
2211             }
2212         },
2213
2214
2215         getEvent: function(e) {
2216             var ev = e || window.event;
2217             if (!ev) {
2218                 var c = this.getEvent.caller;
2219                 while (c) {
2220                     ev = c.arguments[0];
2221                     if (ev && Event == ev.constructor) {
2222                         break;
2223                     }
2224                     c = c.caller;
2225                 }
2226             }
2227             return ev;
2228         },
2229
2230
2231         getCharCode: function(ev) {
2232             ev = ev.browserEvent || ev;
2233             return ev.charCode || ev.keyCode || 0;
2234         },
2235
2236
2237         _getCacheIndex: function(el, eventName, fn) {
2238             for (var i = 0,len = listeners.length; i < len; ++i) {
2239                 var li = listeners[i];
2240                 if (li &&
2241                     li[this.FN] == fn &&
2242                     li[this.EL] == el &&
2243                     li[this.TYPE] == eventName) {
2244                     return i;
2245                 }
2246             }
2247
2248             return -1;
2249         },
2250
2251
2252         elCache: {},
2253
2254
2255         getEl: function(id) {
2256             return document.getElementById(id);
2257         },
2258
2259
2260         clearCache: function() {
2261         },
2262
2263
2264         _load: function(e) {
2265             loadComplete = true;
2266             var EU = Roo.lib.Event;
2267
2268
2269             if (Roo.isIE) {
2270                 EU.doRemove(window, "load", EU._load);
2271             }
2272         },
2273
2274
2275         _tryPreloadAttach: function() {
2276
2277             if (this.locked) {
2278                 return false;
2279             }
2280
2281             this.locked = true;
2282
2283
2284             var tryAgain = !loadComplete;
2285             if (!tryAgain) {
2286                 tryAgain = (retryCount > 0);
2287             }
2288
2289
2290             var notAvail = [];
2291             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292                 var item = onAvailStack[i];
2293                 if (item) {
2294                     var el = this.getEl(item.id);
2295
2296                     if (el) {
2297                         if (!item.checkReady ||
2298                             loadComplete ||
2299                             el.nextSibling ||
2300                             (document && document.body)) {
2301
2302                             var scope = el;
2303                             if (item.override) {
2304                                 if (item.override === true) {
2305                                     scope = item.obj;
2306                                 } else {
2307                                     scope = item.override;
2308                                 }
2309                             }
2310                             item.fn.call(scope, item.obj);
2311                             onAvailStack[i] = null;
2312                         }
2313                     } else {
2314                         notAvail.push(item);
2315                     }
2316                 }
2317             }
2318
2319             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2320
2321             if (tryAgain) {
2322
2323                 this.startInterval();
2324             } else {
2325                 clearInterval(this._interval);
2326                 this._interval = null;
2327             }
2328
2329             this.locked = false;
2330
2331             return true;
2332
2333         },
2334
2335
2336         purgeElement: function(el, recurse, eventName) {
2337             var elListeners = this.getListeners(el, eventName);
2338             if (elListeners) {
2339                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340                     var l = elListeners[i];
2341                     this.removeListener(el, l.type, l.fn);
2342                 }
2343             }
2344
2345             if (recurse && el && el.childNodes) {
2346                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347                     this.purgeElement(el.childNodes[i], recurse, eventName);
2348                 }
2349             }
2350         },
2351
2352
2353         getListeners: function(el, eventName) {
2354             var results = [], searchLists;
2355             if (!eventName) {
2356                 searchLists = [listeners, unloadListeners];
2357             } else if (eventName == "unload") {
2358                 searchLists = [unloadListeners];
2359             } else {
2360                 searchLists = [listeners];
2361             }
2362
2363             for (var j = 0; j < searchLists.length; ++j) {
2364                 var searchList = searchLists[j];
2365                 if (searchList && searchList.length > 0) {
2366                     for (var i = 0,len = searchList.length; i < len; ++i) {
2367                         var l = searchList[i];
2368                         if (l && l[this.EL] === el &&
2369                             (!eventName || eventName === l[this.TYPE])) {
2370                             results.push({
2371                                 type:   l[this.TYPE],
2372                                 fn:     l[this.FN],
2373                                 obj:    l[this.OBJ],
2374                                 adjust: l[this.ADJ_SCOPE],
2375                                 index:  i
2376                             });
2377                         }
2378                     }
2379                 }
2380             }
2381
2382             return (results.length) ? results : null;
2383         },
2384
2385
2386         _unload: function(e) {
2387
2388             var EU = Roo.lib.Event, i, j, l, len, index;
2389
2390             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391                 l = unloadListeners[i];
2392                 if (l) {
2393                     var scope = window;
2394                     if (l[EU.ADJ_SCOPE]) {
2395                         if (l[EU.ADJ_SCOPE] === true) {
2396                             scope = l[EU.OBJ];
2397                         } else {
2398                             scope = l[EU.ADJ_SCOPE];
2399                         }
2400                     }
2401                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402                     unloadListeners[i] = null;
2403                     l = null;
2404                     scope = null;
2405                 }
2406             }
2407
2408             unloadListeners = null;
2409
2410             if (listeners && listeners.length > 0) {
2411                 j = listeners.length;
2412                 while (j) {
2413                     index = j - 1;
2414                     l = listeners[index];
2415                     if (l) {
2416                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2417                                 l[EU.FN], index);
2418                     }
2419                     j = j - 1;
2420                 }
2421                 l = null;
2422
2423                 EU.clearCache();
2424             }
2425
2426             EU.doRemove(window, "unload", EU._unload);
2427
2428         },
2429
2430
2431         getScroll: function() {
2432             var dd = document.documentElement, db = document.body;
2433             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434                 return [dd.scrollTop, dd.scrollLeft];
2435             } else if (db) {
2436                 return [db.scrollTop, db.scrollLeft];
2437             } else {
2438                 return [0, 0];
2439             }
2440         },
2441
2442
2443         doAdd: function () {
2444             if (window.addEventListener) {
2445                 return function(el, eventName, fn, capture) {
2446                     el.addEventListener(eventName, fn, (capture));
2447                 };
2448             } else if (window.attachEvent) {
2449                 return function(el, eventName, fn, capture) {
2450                     el.attachEvent("on" + eventName, fn);
2451                 };
2452             } else {
2453                 return function() {
2454                 };
2455             }
2456         }(),
2457
2458
2459         doRemove: function() {
2460             if (window.removeEventListener) {
2461                 return function (el, eventName, fn, capture) {
2462                     el.removeEventListener(eventName, fn, (capture));
2463                 };
2464             } else if (window.detachEvent) {
2465                 return function (el, eventName, fn) {
2466                     el.detachEvent("on" + eventName, fn);
2467                 };
2468             } else {
2469                 return function() {
2470                 };
2471             }
2472         }()
2473     };
2474     
2475 }();
2476 (function() {     
2477    
2478     var E = Roo.lib.Event;
2479     E.on = E.addListener;
2480     E.un = E.removeListener;
2481
2482     if (document && document.body) {
2483         E._load();
2484     } else {
2485         E.doAdd(window, "load", E._load);
2486     }
2487     E.doAdd(window, "unload", E._unload);
2488     E._tryPreloadAttach();
2489 })();
2490
2491 /*
2492  * Portions of this file are based on pieces of Yahoo User Interface Library
2493  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494  * YUI licensed under the BSD License:
2495  * http://developer.yahoo.net/yui/license.txt
2496  * <script type="text/javascript">
2497  *
2498  */
2499
2500 (function() {
2501     /**
2502      * @class Roo.lib.Ajax
2503      *
2504      */
2505     Roo.lib.Ajax = {
2506         /**
2507          * @static 
2508          */
2509         request : function(method, uri, cb, data, options) {
2510             if(options){
2511                 var hs = options.headers;
2512                 if(hs){
2513                     for(var h in hs){
2514                         if(hs.hasOwnProperty(h)){
2515                             this.initHeader(h, hs[h], false);
2516                         }
2517                     }
2518                 }
2519                 if(options.xmlData){
2520                     this.initHeader('Content-Type', 'text/xml', false);
2521                     method = 'POST';
2522                     data = options.xmlData;
2523                 }
2524             }
2525
2526             return this.asyncRequest(method, uri, cb, data);
2527         },
2528
2529         serializeForm : function(form) {
2530             if(typeof form == 'string') {
2531                 form = (document.getElementById(form) || document.forms[form]);
2532             }
2533
2534             var el, name, val, disabled, data = '', hasSubmit = false;
2535             for (var i = 0; i < form.elements.length; i++) {
2536                 el = form.elements[i];
2537                 disabled = form.elements[i].disabled;
2538                 name = form.elements[i].name;
2539                 val = form.elements[i].value;
2540
2541                 if (!disabled && name){
2542                     switch (el.type)
2543                             {
2544                         case 'select-one':
2545                         case 'select-multiple':
2546                             for (var j = 0; j < el.options.length; j++) {
2547                                 if (el.options[j].selected) {
2548                                     if (Roo.isIE) {
2549                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2550                                     }
2551                                     else {
2552                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2553                                     }
2554                                 }
2555                             }
2556                             break;
2557                         case 'radio':
2558                         case 'checkbox':
2559                             if (el.checked) {
2560                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2561                             }
2562                             break;
2563                         case 'file':
2564
2565                         case undefined:
2566
2567                         case 'reset':
2568
2569                         case 'button':
2570
2571                             break;
2572                         case 'submit':
2573                             if(hasSubmit == false) {
2574                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2575                                 hasSubmit = true;
2576                             }
2577                             break;
2578                         default:
2579                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2580                             break;
2581                     }
2582                 }
2583             }
2584             data = data.substr(0, data.length - 1);
2585             return data;
2586         },
2587
2588         headers:{},
2589
2590         hasHeaders:false,
2591
2592         useDefaultHeader:true,
2593
2594         defaultPostHeader:'application/x-www-form-urlencoded',
2595
2596         useDefaultXhrHeader:true,
2597
2598         defaultXhrHeader:'XMLHttpRequest',
2599
2600         hasDefaultHeaders:true,
2601
2602         defaultHeaders:{},
2603
2604         poll:{},
2605
2606         timeout:{},
2607
2608         pollInterval:50,
2609
2610         transactionId:0,
2611
2612         setProgId:function(id)
2613         {
2614             this.activeX.unshift(id);
2615         },
2616
2617         setDefaultPostHeader:function(b)
2618         {
2619             this.useDefaultHeader = b;
2620         },
2621
2622         setDefaultXhrHeader:function(b)
2623         {
2624             this.useDefaultXhrHeader = b;
2625         },
2626
2627         setPollingInterval:function(i)
2628         {
2629             if (typeof i == 'number' && isFinite(i)) {
2630                 this.pollInterval = i;
2631             }
2632         },
2633
2634         createXhrObject:function(transactionId)
2635         {
2636             var obj,http;
2637             try
2638             {
2639
2640                 http = new XMLHttpRequest();
2641
2642                 obj = { conn:http, tId:transactionId };
2643             }
2644             catch(e)
2645             {
2646                 for (var i = 0; i < this.activeX.length; ++i) {
2647                     try
2648                     {
2649
2650                         http = new ActiveXObject(this.activeX[i]);
2651
2652                         obj = { conn:http, tId:transactionId };
2653                         break;
2654                     }
2655                     catch(e) {
2656                     }
2657                 }
2658             }
2659             finally
2660             {
2661                 return obj;
2662             }
2663         },
2664
2665         getConnectionObject:function()
2666         {
2667             var o;
2668             var tId = this.transactionId;
2669
2670             try
2671             {
2672                 o = this.createXhrObject(tId);
2673                 if (o) {
2674                     this.transactionId++;
2675                 }
2676             }
2677             catch(e) {
2678             }
2679             finally
2680             {
2681                 return o;
2682             }
2683         },
2684
2685         asyncRequest:function(method, uri, callback, postData)
2686         {
2687             var o = this.getConnectionObject();
2688
2689             if (!o) {
2690                 return null;
2691             }
2692             else {
2693                 o.conn.open(method, uri, true);
2694
2695                 if (this.useDefaultXhrHeader) {
2696                     if (!this.defaultHeaders['X-Requested-With']) {
2697                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2698                     }
2699                 }
2700
2701                 if(postData && this.useDefaultHeader){
2702                     this.initHeader('Content-Type', this.defaultPostHeader);
2703                 }
2704
2705                  if (this.hasDefaultHeaders || this.hasHeaders) {
2706                     this.setHeader(o);
2707                 }
2708
2709                 this.handleReadyState(o, callback);
2710                 o.conn.send(postData || null);
2711
2712                 return o;
2713             }
2714         },
2715
2716         handleReadyState:function(o, callback)
2717         {
2718             var oConn = this;
2719
2720             if (callback && callback.timeout) {
2721                 
2722                 this.timeout[o.tId] = window.setTimeout(function() {
2723                     oConn.abort(o, callback, true);
2724                 }, callback.timeout);
2725             }
2726
2727             this.poll[o.tId] = window.setInterval(
2728                     function() {
2729                         if (o.conn && o.conn.readyState == 4) {
2730                             window.clearInterval(oConn.poll[o.tId]);
2731                             delete oConn.poll[o.tId];
2732
2733                             if(callback && callback.timeout) {
2734                                 window.clearTimeout(oConn.timeout[o.tId]);
2735                                 delete oConn.timeout[o.tId];
2736                             }
2737
2738                             oConn.handleTransactionResponse(o, callback);
2739                         }
2740                     }
2741                     , this.pollInterval);
2742         },
2743
2744         handleTransactionResponse:function(o, callback, isAbort)
2745         {
2746
2747             if (!callback) {
2748                 this.releaseObject(o);
2749                 return;
2750             }
2751
2752             var httpStatus, responseObject;
2753
2754             try
2755             {
2756                 if (o.conn.status !== undefined && o.conn.status != 0) {
2757                     httpStatus = o.conn.status;
2758                 }
2759                 else {
2760                     httpStatus = 13030;
2761                 }
2762             }
2763             catch(e) {
2764
2765
2766                 httpStatus = 13030;
2767             }
2768
2769             if (httpStatus >= 200 && httpStatus < 300) {
2770                 responseObject = this.createResponseObject(o, callback.argument);
2771                 if (callback.success) {
2772                     if (!callback.scope) {
2773                         callback.success(responseObject);
2774                     }
2775                     else {
2776
2777
2778                         callback.success.apply(callback.scope, [responseObject]);
2779                     }
2780                 }
2781             }
2782             else {
2783                 switch (httpStatus) {
2784
2785                     case 12002:
2786                     case 12029:
2787                     case 12030:
2788                     case 12031:
2789                     case 12152:
2790                     case 13030:
2791                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792                         if (callback.failure) {
2793                             if (!callback.scope) {
2794                                 callback.failure(responseObject);
2795                             }
2796                             else {
2797                                 callback.failure.apply(callback.scope, [responseObject]);
2798                             }
2799                         }
2800                         break;
2801                     default:
2802                         responseObject = this.createResponseObject(o, callback.argument);
2803                         if (callback.failure) {
2804                             if (!callback.scope) {
2805                                 callback.failure(responseObject);
2806                             }
2807                             else {
2808                                 callback.failure.apply(callback.scope, [responseObject]);
2809                             }
2810                         }
2811                 }
2812             }
2813
2814             this.releaseObject(o);
2815             responseObject = null;
2816         },
2817
2818         createResponseObject:function(o, callbackArg)
2819         {
2820             var obj = {};
2821             var headerObj = {};
2822
2823             try
2824             {
2825                 var headerStr = o.conn.getAllResponseHeaders();
2826                 var header = headerStr.split('\n');
2827                 for (var i = 0; i < header.length; i++) {
2828                     var delimitPos = header[i].indexOf(':');
2829                     if (delimitPos != -1) {
2830                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2831                     }
2832                 }
2833             }
2834             catch(e) {
2835             }
2836
2837             obj.tId = o.tId;
2838             obj.status = o.conn.status;
2839             obj.statusText = o.conn.statusText;
2840             obj.getResponseHeader = headerObj;
2841             obj.getAllResponseHeaders = headerStr;
2842             obj.responseText = o.conn.responseText;
2843             obj.responseXML = o.conn.responseXML;
2844
2845             if (typeof callbackArg !== undefined) {
2846                 obj.argument = callbackArg;
2847             }
2848
2849             return obj;
2850         },
2851
2852         createExceptionObject:function(tId, callbackArg, isAbort)
2853         {
2854             var COMM_CODE = 0;
2855             var COMM_ERROR = 'communication failure';
2856             var ABORT_CODE = -1;
2857             var ABORT_ERROR = 'transaction aborted';
2858
2859             var obj = {};
2860
2861             obj.tId = tId;
2862             if (isAbort) {
2863                 obj.status = ABORT_CODE;
2864                 obj.statusText = ABORT_ERROR;
2865             }
2866             else {
2867                 obj.status = COMM_CODE;
2868                 obj.statusText = COMM_ERROR;
2869             }
2870
2871             if (callbackArg) {
2872                 obj.argument = callbackArg;
2873             }
2874
2875             return obj;
2876         },
2877
2878         initHeader:function(label, value, isDefault)
2879         {
2880             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2881
2882             if (headerObj[label] === undefined) {
2883                 headerObj[label] = value;
2884             }
2885             else {
2886
2887
2888                 headerObj[label] = value + "," + headerObj[label];
2889             }
2890
2891             if (isDefault) {
2892                 this.hasDefaultHeaders = true;
2893             }
2894             else {
2895                 this.hasHeaders = true;
2896             }
2897         },
2898
2899
2900         setHeader:function(o)
2901         {
2902             if (this.hasDefaultHeaders) {
2903                 for (var prop in this.defaultHeaders) {
2904                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2905                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2906                     }
2907                 }
2908             }
2909
2910             if (this.hasHeaders) {
2911                 for (var prop in this.headers) {
2912                     if (this.headers.hasOwnProperty(prop)) {
2913                         o.conn.setRequestHeader(prop, this.headers[prop]);
2914                     }
2915                 }
2916                 this.headers = {};
2917                 this.hasHeaders = false;
2918             }
2919         },
2920
2921         resetDefaultHeaders:function() {
2922             delete this.defaultHeaders;
2923             this.defaultHeaders = {};
2924             this.hasDefaultHeaders = false;
2925         },
2926
2927         abort:function(o, callback, isTimeout)
2928         {
2929             if(this.isCallInProgress(o)) {
2930                 o.conn.abort();
2931                 window.clearInterval(this.poll[o.tId]);
2932                 delete this.poll[o.tId];
2933                 if (isTimeout) {
2934                     delete this.timeout[o.tId];
2935                 }
2936
2937                 this.handleTransactionResponse(o, callback, true);
2938
2939                 return true;
2940             }
2941             else {
2942                 return false;
2943             }
2944         },
2945
2946
2947         isCallInProgress:function(o)
2948         {
2949             if (o && o.conn) {
2950                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2951             }
2952             else {
2953
2954                 return false;
2955             }
2956         },
2957
2958
2959         releaseObject:function(o)
2960         {
2961
2962             o.conn = null;
2963
2964             o = null;
2965         },
2966
2967         activeX:[
2968         'MSXML2.XMLHTTP.3.0',
2969         'MSXML2.XMLHTTP',
2970         'Microsoft.XMLHTTP'
2971         ]
2972
2973
2974     };
2975 })();/*
2976  * Portions of this file are based on pieces of Yahoo User Interface Library
2977  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978  * YUI licensed under the BSD License:
2979  * http://developer.yahoo.net/yui/license.txt
2980  * <script type="text/javascript">
2981  *
2982  */
2983
2984 Roo.lib.Region = function(t, r, b, l) {
2985     this.top = t;
2986     this[1] = t;
2987     this.right = r;
2988     this.bottom = b;
2989     this.left = l;
2990     this[0] = l;
2991 };
2992
2993
2994 Roo.lib.Region.prototype = {
2995     contains : function(region) {
2996         return ( region.left >= this.left &&
2997                  region.right <= this.right &&
2998                  region.top >= this.top &&
2999                  region.bottom <= this.bottom    );
3000
3001     },
3002
3003     getArea : function() {
3004         return ( (this.bottom - this.top) * (this.right - this.left) );
3005     },
3006
3007     intersect : function(region) {
3008         var t = Math.max(this.top, region.top);
3009         var r = Math.min(this.right, region.right);
3010         var b = Math.min(this.bottom, region.bottom);
3011         var l = Math.max(this.left, region.left);
3012
3013         if (b >= t && r >= l) {
3014             return new Roo.lib.Region(t, r, b, l);
3015         } else {
3016             return null;
3017         }
3018     },
3019     union : function(region) {
3020         var t = Math.min(this.top, region.top);
3021         var r = Math.max(this.right, region.right);
3022         var b = Math.max(this.bottom, region.bottom);
3023         var l = Math.min(this.left, region.left);
3024
3025         return new Roo.lib.Region(t, r, b, l);
3026     },
3027
3028     adjust : function(t, l, b, r) {
3029         this.top += t;
3030         this.left += l;
3031         this.right += r;
3032         this.bottom += b;
3033         return this;
3034     }
3035 };
3036
3037 Roo.lib.Region.getRegion = function(el) {
3038     var p = Roo.lib.Dom.getXY(el);
3039
3040     var t = p[1];
3041     var r = p[0] + el.offsetWidth;
3042     var b = p[1] + el.offsetHeight;
3043     var l = p[0];
3044
3045     return new Roo.lib.Region(t, r, b, l);
3046 };
3047 /*
3048  * Portions of this file are based on pieces of Yahoo User Interface Library
3049  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050  * YUI licensed under the BSD License:
3051  * http://developer.yahoo.net/yui/license.txt
3052  * <script type="text/javascript">
3053  *
3054  */
3055 //@@dep Roo.lib.Region
3056
3057
3058 Roo.lib.Point = function(x, y) {
3059     if (x instanceof Array) {
3060         y = x[1];
3061         x = x[0];
3062     }
3063     this.x = this.right = this.left = this[0] = x;
3064     this.y = this.top = this.bottom = this[1] = y;
3065 };
3066
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3068 /*
3069  * Portions of this file are based on pieces of Yahoo User Interface Library
3070  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071  * YUI licensed under the BSD License:
3072  * http://developer.yahoo.net/yui/license.txt
3073  * <script type="text/javascript">
3074  *
3075  */
3076  
3077 (function() {   
3078
3079     Roo.lib.Anim = {
3080         scroll : function(el, args, duration, easing, cb, scope) {
3081             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3082         },
3083
3084         motion : function(el, args, duration, easing, cb, scope) {
3085             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3086         },
3087
3088         color : function(el, args, duration, easing, cb, scope) {
3089             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3090         },
3091
3092         run : function(el, args, duration, easing, cb, scope, type) {
3093             type = type || Roo.lib.AnimBase;
3094             if (typeof easing == "string") {
3095                 easing = Roo.lib.Easing[easing];
3096             }
3097             var anim = new type(el, args, duration, easing);
3098             anim.animateX(function() {
3099                 Roo.callback(cb, scope);
3100             });
3101             return anim;
3102         }
3103     };
3104 })();/*
3105  * Portions of this file are based on pieces of Yahoo User Interface Library
3106  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107  * YUI licensed under the BSD License:
3108  * http://developer.yahoo.net/yui/license.txt
3109  * <script type="text/javascript">
3110  *
3111  */
3112
3113 (function() {    
3114     var libFlyweight;
3115     
3116     function fly(el) {
3117         if (!libFlyweight) {
3118             libFlyweight = new Roo.Element.Flyweight();
3119         }
3120         libFlyweight.dom = el;
3121         return libFlyweight;
3122     }
3123
3124     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3125     
3126    
3127     
3128     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3129         if (el) {
3130             this.init(el, attributes, duration, method);
3131         }
3132     };
3133
3134     Roo.lib.AnimBase.fly = fly;
3135     
3136     
3137     
3138     Roo.lib.AnimBase.prototype = {
3139
3140         toString: function() {
3141             var el = this.getEl();
3142             var id = el.id || el.tagName;
3143             return ("Anim " + id);
3144         },
3145
3146         patterns: {
3147             noNegatives:        /width|height|opacity|padding/i,
3148             offsetAttribute:  /^((width|height)|(top|left))$/,
3149             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3150             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3151         },
3152
3153
3154         doMethod: function(attr, start, end) {
3155             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3156         },
3157
3158
3159         setAttribute: function(attr, val, unit) {
3160             if (this.patterns.noNegatives.test(attr)) {
3161                 val = (val > 0) ? val : 0;
3162             }
3163
3164             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3165         },
3166
3167
3168         getAttribute: function(attr) {
3169             var el = this.getEl();
3170             var val = fly(el).getStyle(attr);
3171
3172             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173                 return parseFloat(val);
3174             }
3175
3176             var a = this.patterns.offsetAttribute.exec(attr) || [];
3177             var pos = !!( a[3] );
3178             var box = !!( a[2] );
3179
3180
3181             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3183             } else {
3184                 val = 0;
3185             }
3186
3187             return val;
3188         },
3189
3190
3191         getDefaultUnit: function(attr) {
3192             if (this.patterns.defaultUnit.test(attr)) {
3193                 return 'px';
3194             }
3195
3196             return '';
3197         },
3198
3199         animateX : function(callback, scope) {
3200             var f = function() {
3201                 this.onComplete.removeListener(f);
3202                 if (typeof callback == "function") {
3203                     callback.call(scope || this, this);
3204                 }
3205             };
3206             this.onComplete.addListener(f, this);
3207             this.animate();
3208         },
3209
3210
3211         setRuntimeAttribute: function(attr) {
3212             var start;
3213             var end;
3214             var attributes = this.attributes;
3215
3216             this.runtimeAttributes[attr] = {};
3217
3218             var isset = function(prop) {
3219                 return (typeof prop !== 'undefined');
3220             };
3221
3222             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3223                 return false;
3224             }
3225
3226             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3227
3228
3229             if (isset(attributes[attr]['to'])) {
3230                 end = attributes[attr]['to'];
3231             } else if (isset(attributes[attr]['by'])) {
3232                 if (start.constructor == Array) {
3233                     end = [];
3234                     for (var i = 0, len = start.length; i < len; ++i) {
3235                         end[i] = start[i] + attributes[attr]['by'][i];
3236                     }
3237                 } else {
3238                     end = start + attributes[attr]['by'];
3239                 }
3240             }
3241
3242             this.runtimeAttributes[attr].start = start;
3243             this.runtimeAttributes[attr].end = end;
3244
3245
3246             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3247         },
3248
3249
3250         init: function(el, attributes, duration, method) {
3251
3252             var isAnimated = false;
3253
3254
3255             var startTime = null;
3256
3257
3258             var actualFrames = 0;
3259
3260
3261             el = Roo.getDom(el);
3262
3263
3264             this.attributes = attributes || {};
3265
3266
3267             this.duration = duration || 1;
3268
3269
3270             this.method = method || Roo.lib.Easing.easeNone;
3271
3272
3273             this.useSeconds = true;
3274
3275
3276             this.currentFrame = 0;
3277
3278
3279             this.totalFrames = Roo.lib.AnimMgr.fps;
3280
3281
3282             this.getEl = function() {
3283                 return el;
3284             };
3285
3286
3287             this.isAnimated = function() {
3288                 return isAnimated;
3289             };
3290
3291
3292             this.getStartTime = function() {
3293                 return startTime;
3294             };
3295
3296             this.runtimeAttributes = {};
3297
3298
3299             this.animate = function() {
3300                 if (this.isAnimated()) {
3301                     return false;
3302                 }
3303
3304                 this.currentFrame = 0;
3305
3306                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3307
3308                 Roo.lib.AnimMgr.registerElement(this);
3309             };
3310
3311
3312             this.stop = function(finish) {
3313                 if (finish) {
3314                     this.currentFrame = this.totalFrames;
3315                     this._onTween.fire();
3316                 }
3317                 Roo.lib.AnimMgr.stop(this);
3318             };
3319
3320             var onStart = function() {
3321                 this.onStart.fire();
3322
3323                 this.runtimeAttributes = {};
3324                 for (var attr in this.attributes) {
3325                     this.setRuntimeAttribute(attr);
3326                 }
3327
3328                 isAnimated = true;
3329                 actualFrames = 0;
3330                 startTime = new Date();
3331             };
3332
3333
3334             var onTween = function() {
3335                 var data = {
3336                     duration: new Date() - this.getStartTime(),
3337                     currentFrame: this.currentFrame
3338                 };
3339
3340                 data.toString = function() {
3341                     return (
3342                             'duration: ' + data.duration +
3343                             ', currentFrame: ' + data.currentFrame
3344                             );
3345                 };
3346
3347                 this.onTween.fire(data);
3348
3349                 var runtimeAttributes = this.runtimeAttributes;
3350
3351                 for (var attr in runtimeAttributes) {
3352                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3353                 }
3354
3355                 actualFrames += 1;
3356             };
3357
3358             var onComplete = function() {
3359                 var actual_duration = (new Date() - startTime) / 1000 ;
3360
3361                 var data = {
3362                     duration: actual_duration,
3363                     frames: actualFrames,
3364                     fps: actualFrames / actual_duration
3365                 };
3366
3367                 data.toString = function() {
3368                     return (
3369                             'duration: ' + data.duration +
3370                             ', frames: ' + data.frames +
3371                             ', fps: ' + data.fps
3372                             );
3373                 };
3374
3375                 isAnimated = false;
3376                 actualFrames = 0;
3377                 this.onComplete.fire(data);
3378             };
3379
3380
3381             this._onStart = new Roo.util.Event(this);
3382             this.onStart = new Roo.util.Event(this);
3383             this.onTween = new Roo.util.Event(this);
3384             this._onTween = new Roo.util.Event(this);
3385             this.onComplete = new Roo.util.Event(this);
3386             this._onComplete = new Roo.util.Event(this);
3387             this._onStart.addListener(onStart);
3388             this._onTween.addListener(onTween);
3389             this._onComplete.addListener(onComplete);
3390         }
3391     };
3392 })();
3393 /*
3394  * Portions of this file are based on pieces of Yahoo User Interface Library
3395  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396  * YUI licensed under the BSD License:
3397  * http://developer.yahoo.net/yui/license.txt
3398  * <script type="text/javascript">
3399  *
3400  */
3401
3402 Roo.lib.AnimMgr = new function() {
3403
3404     var thread = null;
3405
3406
3407     var queue = [];
3408
3409
3410     var tweenCount = 0;
3411
3412
3413     this.fps = 1000;
3414
3415
3416     this.delay = 1;
3417
3418
3419     this.registerElement = function(tween) {
3420         queue[queue.length] = tween;
3421         tweenCount += 1;
3422         tween._onStart.fire();
3423         this.start();
3424     };
3425
3426
3427     this.unRegister = function(tween, index) {
3428         tween._onComplete.fire();
3429         index = index || getIndex(tween);
3430         if (index != -1) {
3431             queue.splice(index, 1);
3432         }
3433
3434         tweenCount -= 1;
3435         if (tweenCount <= 0) {
3436             this.stop();
3437         }
3438     };
3439
3440
3441     this.start = function() {
3442         if (thread === null) {
3443             thread = setInterval(this.run, this.delay);
3444         }
3445     };
3446
3447
3448     this.stop = function(tween) {
3449         if (!tween) {
3450             clearInterval(thread);
3451
3452             for (var i = 0, len = queue.length; i < len; ++i) {
3453                 if (queue[0].isAnimated()) {
3454                     this.unRegister(queue[0], 0);
3455                 }
3456             }
3457
3458             queue = [];
3459             thread = null;
3460             tweenCount = 0;
3461         }
3462         else {
3463             this.unRegister(tween);
3464         }
3465     };
3466
3467
3468     this.run = function() {
3469         for (var i = 0, len = queue.length; i < len; ++i) {
3470             var tween = queue[i];
3471             if (!tween || !tween.isAnimated()) {
3472                 continue;
3473             }
3474
3475             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3476             {
3477                 tween.currentFrame += 1;
3478
3479                 if (tween.useSeconds) {
3480                     correctFrame(tween);
3481                 }
3482                 tween._onTween.fire();
3483             }
3484             else {
3485                 Roo.lib.AnimMgr.stop(tween, i);
3486             }
3487         }
3488     };
3489
3490     var getIndex = function(anim) {
3491         for (var i = 0, len = queue.length; i < len; ++i) {
3492             if (queue[i] == anim) {
3493                 return i;
3494             }
3495         }
3496         return -1;
3497     };
3498
3499
3500     var correctFrame = function(tween) {
3501         var frames = tween.totalFrames;
3502         var frame = tween.currentFrame;
3503         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504         var elapsed = (new Date() - tween.getStartTime());
3505         var tweak = 0;
3506
3507         if (elapsed < tween.duration * 1000) {
3508             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3509         } else {
3510             tweak = frames - (frame + 1);
3511         }
3512         if (tweak > 0 && isFinite(tweak)) {
3513             if (tween.currentFrame + tweak >= frames) {
3514                 tweak = frames - (frame + 1);
3515             }
3516
3517             tween.currentFrame += tweak;
3518         }
3519     };
3520 };
3521
3522     /*
3523  * Portions of this file are based on pieces of Yahoo User Interface Library
3524  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525  * YUI licensed under the BSD License:
3526  * http://developer.yahoo.net/yui/license.txt
3527  * <script type="text/javascript">
3528  *
3529  */
3530 Roo.lib.Bezier = new function() {
3531
3532         this.getPosition = function(points, t) {
3533             var n = points.length;
3534             var tmp = [];
3535
3536             for (var i = 0; i < n; ++i) {
3537                 tmp[i] = [points[i][0], points[i][1]];
3538             }
3539
3540             for (var j = 1; j < n; ++j) {
3541                 for (i = 0; i < n - j; ++i) {
3542                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3544                 }
3545             }
3546
3547             return [ tmp[0][0], tmp[0][1] ];
3548
3549         };
3550     };/*
3551  * Portions of this file are based on pieces of Yahoo User Interface Library
3552  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553  * YUI licensed under the BSD License:
3554  * http://developer.yahoo.net/yui/license.txt
3555  * <script type="text/javascript">
3556  *
3557  */
3558 (function() {
3559
3560     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3562     };
3563
3564     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3565
3566     var fly = Roo.lib.AnimBase.fly;
3567     var Y = Roo.lib;
3568     var superclass = Y.ColorAnim.superclass;
3569     var proto = Y.ColorAnim.prototype;
3570
3571     proto.toString = function() {
3572         var el = this.getEl();
3573         var id = el.id || el.tagName;
3574         return ("ColorAnim " + id);
3575     };
3576
3577     proto.patterns.color = /color$/i;
3578     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3582
3583
3584     proto.parseColor = function(s) {
3585         if (s.length == 3) {
3586             return s;
3587         }
3588
3589         var c = this.patterns.hex.exec(s);
3590         if (c && c.length == 4) {
3591             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3592         }
3593
3594         c = this.patterns.rgb.exec(s);
3595         if (c && c.length == 4) {
3596             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3597         }
3598
3599         c = this.patterns.hex3.exec(s);
3600         if (c && c.length == 4) {
3601             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3602         }
3603
3604         return null;
3605     };
3606     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607     proto.getAttribute = function(attr) {
3608         var el = this.getEl();
3609         if (this.patterns.color.test(attr)) {
3610             var val = fly(el).getStyle(attr);
3611
3612             if (this.patterns.transparent.test(val)) {
3613                 var parent = el.parentNode;
3614                 val = fly(parent).getStyle(attr);
3615
3616                 while (parent && this.patterns.transparent.test(val)) {
3617                     parent = parent.parentNode;
3618                     val = fly(parent).getStyle(attr);
3619                     if (parent.tagName.toUpperCase() == 'HTML') {
3620                         val = '#fff';
3621                     }
3622                 }
3623             }
3624         } else {
3625             val = superclass.getAttribute.call(this, attr);
3626         }
3627
3628         return val;
3629     };
3630     proto.getAttribute = function(attr) {
3631         var el = this.getEl();
3632         if (this.patterns.color.test(attr)) {
3633             var val = fly(el).getStyle(attr);
3634
3635             if (this.patterns.transparent.test(val)) {
3636                 var parent = el.parentNode;
3637                 val = fly(parent).getStyle(attr);
3638
3639                 while (parent && this.patterns.transparent.test(val)) {
3640                     parent = parent.parentNode;
3641                     val = fly(parent).getStyle(attr);
3642                     if (parent.tagName.toUpperCase() == 'HTML') {
3643                         val = '#fff';
3644                     }
3645                 }
3646             }
3647         } else {
3648             val = superclass.getAttribute.call(this, attr);
3649         }
3650
3651         return val;
3652     };
3653
3654     proto.doMethod = function(attr, start, end) {
3655         var val;
3656
3657         if (this.patterns.color.test(attr)) {
3658             val = [];
3659             for (var i = 0, len = start.length; i < len; ++i) {
3660                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3661             }
3662
3663             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3664         }
3665         else {
3666             val = superclass.doMethod.call(this, attr, start, end);
3667         }
3668
3669         return val;
3670     };
3671
3672     proto.setRuntimeAttribute = function(attr) {
3673         superclass.setRuntimeAttribute.call(this, attr);
3674
3675         if (this.patterns.color.test(attr)) {
3676             var attributes = this.attributes;
3677             var start = this.parseColor(this.runtimeAttributes[attr].start);
3678             var end = this.parseColor(this.runtimeAttributes[attr].end);
3679
3680             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681                 end = this.parseColor(attributes[attr].by);
3682
3683                 for (var i = 0, len = start.length; i < len; ++i) {
3684                     end[i] = start[i] + end[i];
3685                 }
3686             }
3687
3688             this.runtimeAttributes[attr].start = start;
3689             this.runtimeAttributes[attr].end = end;
3690         }
3691     };
3692 })();
3693
3694 /*
3695  * Portions of this file are based on pieces of Yahoo User Interface Library
3696  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697  * YUI licensed under the BSD License:
3698  * http://developer.yahoo.net/yui/license.txt
3699  * <script type="text/javascript">
3700  *
3701  */
3702 Roo.lib.Easing = {
3703
3704
3705     easeNone: function (t, b, c, d) {
3706         return c * t / d + b;
3707     },
3708
3709
3710     easeIn: function (t, b, c, d) {
3711         return c * (t /= d) * t + b;
3712     },
3713
3714
3715     easeOut: function (t, b, c, d) {
3716         return -c * (t /= d) * (t - 2) + b;
3717     },
3718
3719
3720     easeBoth: function (t, b, c, d) {
3721         if ((t /= d / 2) < 1) {
3722             return c / 2 * t * t + b;
3723         }
3724
3725         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3726     },
3727
3728
3729     easeInStrong: function (t, b, c, d) {
3730         return c * (t /= d) * t * t * t + b;
3731     },
3732
3733
3734     easeOutStrong: function (t, b, c, d) {
3735         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3736     },
3737
3738
3739     easeBothStrong: function (t, b, c, d) {
3740         if ((t /= d / 2) < 1) {
3741             return c / 2 * t * t * t * t + b;
3742         }
3743
3744         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3745     },
3746
3747
3748
3749     elasticIn: function (t, b, c, d, a, p) {
3750         if (t == 0) {
3751             return b;
3752         }
3753         if ((t /= d) == 1) {
3754             return b + c;
3755         }
3756         if (!p) {
3757             p = d * .3;
3758         }
3759
3760         if (!a || a < Math.abs(c)) {
3761             a = c;
3762             var s = p / 4;
3763         }
3764         else {
3765             var s = p / (2 * Math.PI) * Math.asin(c / a);
3766         }
3767
3768         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3769     },
3770
3771
3772     elasticOut: function (t, b, c, d, a, p) {
3773         if (t == 0) {
3774             return b;
3775         }
3776         if ((t /= d) == 1) {
3777             return b + c;
3778         }
3779         if (!p) {
3780             p = d * .3;
3781         }
3782
3783         if (!a || a < Math.abs(c)) {
3784             a = c;
3785             var s = p / 4;
3786         }
3787         else {
3788             var s = p / (2 * Math.PI) * Math.asin(c / a);
3789         }
3790
3791         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3792     },
3793
3794
3795     elasticBoth: function (t, b, c, d, a, p) {
3796         if (t == 0) {
3797             return b;
3798         }
3799
3800         if ((t /= d / 2) == 2) {
3801             return b + c;
3802         }
3803
3804         if (!p) {
3805             p = d * (.3 * 1.5);
3806         }
3807
3808         if (!a || a < Math.abs(c)) {
3809             a = c;
3810             var s = p / 4;
3811         }
3812         else {
3813             var s = p / (2 * Math.PI) * Math.asin(c / a);
3814         }
3815
3816         if (t < 1) {
3817             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3819         }
3820         return a * Math.pow(2, -10 * (t -= 1)) *
3821                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3822     },
3823
3824
3825
3826     backIn: function (t, b, c, d, s) {
3827         if (typeof s == 'undefined') {
3828             s = 1.70158;
3829         }
3830         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3831     },
3832
3833
3834     backOut: function (t, b, c, d, s) {
3835         if (typeof s == 'undefined') {
3836             s = 1.70158;
3837         }
3838         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3839     },
3840
3841
3842     backBoth: function (t, b, c, d, s) {
3843         if (typeof s == 'undefined') {
3844             s = 1.70158;
3845         }
3846
3847         if ((t /= d / 2 ) < 1) {
3848             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3849         }
3850         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3851     },
3852
3853
3854     bounceIn: function (t, b, c, d) {
3855         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3856     },
3857
3858
3859     bounceOut: function (t, b, c, d) {
3860         if ((t /= d) < (1 / 2.75)) {
3861             return c * (7.5625 * t * t) + b;
3862         } else if (t < (2 / 2.75)) {
3863             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864         } else if (t < (2.5 / 2.75)) {
3865             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3866         }
3867         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3868     },
3869
3870
3871     bounceBoth: function (t, b, c, d) {
3872         if (t < d / 2) {
3873             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3874         }
3875         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3876     }
3877 };/*
3878  * Portions of this file are based on pieces of Yahoo User Interface Library
3879  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880  * YUI licensed under the BSD License:
3881  * http://developer.yahoo.net/yui/license.txt
3882  * <script type="text/javascript">
3883  *
3884  */
3885     (function() {
3886         Roo.lib.Motion = function(el, attributes, duration, method) {
3887             if (el) {
3888                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3889             }
3890         };
3891
3892         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3893
3894
3895         var Y = Roo.lib;
3896         var superclass = Y.Motion.superclass;
3897         var proto = Y.Motion.prototype;
3898
3899         proto.toString = function() {
3900             var el = this.getEl();
3901             var id = el.id || el.tagName;
3902             return ("Motion " + id);
3903         };
3904
3905         proto.patterns.points = /^points$/i;
3906
3907         proto.setAttribute = function(attr, val, unit) {
3908             if (this.patterns.points.test(attr)) {
3909                 unit = unit || 'px';
3910                 superclass.setAttribute.call(this, 'left', val[0], unit);
3911                 superclass.setAttribute.call(this, 'top', val[1], unit);
3912             } else {
3913                 superclass.setAttribute.call(this, attr, val, unit);
3914             }
3915         };
3916
3917         proto.getAttribute = function(attr) {
3918             if (this.patterns.points.test(attr)) {
3919                 var val = [
3920                         superclass.getAttribute.call(this, 'left'),
3921                         superclass.getAttribute.call(this, 'top')
3922                         ];
3923             } else {
3924                 val = superclass.getAttribute.call(this, attr);
3925             }
3926
3927             return val;
3928         };
3929
3930         proto.doMethod = function(attr, start, end) {
3931             var val = null;
3932
3933             if (this.patterns.points.test(attr)) {
3934                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3936             } else {
3937                 val = superclass.doMethod.call(this, attr, start, end);
3938             }
3939             return val;
3940         };
3941
3942         proto.setRuntimeAttribute = function(attr) {
3943             if (this.patterns.points.test(attr)) {
3944                 var el = this.getEl();
3945                 var attributes = this.attributes;
3946                 var start;
3947                 var control = attributes['points']['control'] || [];
3948                 var end;
3949                 var i, len;
3950
3951                 if (control.length > 0 && !(control[0] instanceof Array)) {
3952                     control = [control];
3953                 } else {
3954                     var tmp = [];
3955                     for (i = 0,len = control.length; i < len; ++i) {
3956                         tmp[i] = control[i];
3957                     }
3958                     control = tmp;
3959                 }
3960
3961                 Roo.fly(el).position();
3962
3963                 if (isset(attributes['points']['from'])) {
3964                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3965                 }
3966                 else {
3967                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3968                 }
3969
3970                 start = this.getAttribute('points');
3971
3972
3973                 if (isset(attributes['points']['to'])) {
3974                     end = translateValues.call(this, attributes['points']['to'], start);
3975
3976                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977                     for (i = 0,len = control.length; i < len; ++i) {
3978                         control[i] = translateValues.call(this, control[i], start);
3979                     }
3980
3981
3982                 } else if (isset(attributes['points']['by'])) {
3983                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3984
3985                     for (i = 0,len = control.length; i < len; ++i) {
3986                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3987                     }
3988                 }
3989
3990                 this.runtimeAttributes[attr] = [start];
3991
3992                 if (control.length > 0) {
3993                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3994                 }
3995
3996                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3997             }
3998             else {
3999                 superclass.setRuntimeAttribute.call(this, attr);
4000             }
4001         };
4002
4003         var translateValues = function(val, start) {
4004             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4006
4007             return val;
4008         };
4009
4010         var isset = function(prop) {
4011             return (typeof prop !== 'undefined');
4012         };
4013     })();
4014 /*
4015  * Portions of this file are based on pieces of Yahoo User Interface Library
4016  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017  * YUI licensed under the BSD License:
4018  * http://developer.yahoo.net/yui/license.txt
4019  * <script type="text/javascript">
4020  *
4021  */
4022     (function() {
4023         Roo.lib.Scroll = function(el, attributes, duration, method) {
4024             if (el) {
4025                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4026             }
4027         };
4028
4029         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4030
4031
4032         var Y = Roo.lib;
4033         var superclass = Y.Scroll.superclass;
4034         var proto = Y.Scroll.prototype;
4035
4036         proto.toString = function() {
4037             var el = this.getEl();
4038             var id = el.id || el.tagName;
4039             return ("Scroll " + id);
4040         };
4041
4042         proto.doMethod = function(attr, start, end) {
4043             var val = null;
4044
4045             if (attr == 'scroll') {
4046                 val = [
4047                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4049                         ];
4050
4051             } else {
4052                 val = superclass.doMethod.call(this, attr, start, end);
4053             }
4054             return val;
4055         };
4056
4057         proto.getAttribute = function(attr) {
4058             var val = null;
4059             var el = this.getEl();
4060
4061             if (attr == 'scroll') {
4062                 val = [ el.scrollLeft, el.scrollTop ];
4063             } else {
4064                 val = superclass.getAttribute.call(this, attr);
4065             }
4066
4067             return val;
4068         };
4069
4070         proto.setAttribute = function(attr, val, unit) {
4071             var el = this.getEl();
4072
4073             if (attr == 'scroll') {
4074                 el.scrollLeft = val[0];
4075                 el.scrollTop = val[1];
4076             } else {
4077                 superclass.setAttribute.call(this, attr, val, unit);
4078             }
4079         };
4080     })();
4081 /*
4082  * Based on:
4083  * Ext JS Library 1.1.1
4084  * Copyright(c) 2006-2007, Ext JS, LLC.
4085  *
4086  * Originally Released Under LGPL - original licence link has changed is not relivant.
4087  *
4088  * Fork - LGPL
4089  * <script type="text/javascript">
4090  */
4091
4092
4093 // nasty IE9 hack - what a pile of crap that is..
4094
4095  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096     Range.prototype.createContextualFragment = function (html) {
4097         var doc = window.document;
4098         var container = doc.createElement("div");
4099         container.innerHTML = html;
4100         var frag = doc.createDocumentFragment(), n;
4101         while ((n = container.firstChild)) {
4102             frag.appendChild(n);
4103         }
4104         return frag;
4105     };
4106 }
4107
4108 /**
4109  * @class Roo.DomHelper
4110  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4112  * @singleton
4113  */
4114 Roo.DomHelper = function(){
4115     var tempTableEl = null;
4116     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117     var tableRe = /^table|tbody|tr|td$/i;
4118     var xmlns = {};
4119     // build as innerHTML where available
4120     /** @ignore */
4121     var createHtml = function(o){
4122         if(typeof o == 'string'){
4123             return o;
4124         }
4125         var b = "";
4126         if(!o.tag){
4127             o.tag = "div";
4128         }
4129         b += "<" + o.tag;
4130         for(var attr in o){
4131             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132             if(attr == "style"){
4133                 var s = o["style"];
4134                 if(typeof s == "function"){
4135                     s = s.call();
4136                 }
4137                 if(typeof s == "string"){
4138                     b += ' style="' + s + '"';
4139                 }else if(typeof s == "object"){
4140                     b += ' style="';
4141                     for(var key in s){
4142                         if(typeof s[key] != "function"){
4143                             b += key + ":" + s[key] + ";";
4144                         }
4145                     }
4146                     b += '"';
4147                 }
4148             }else{
4149                 if(attr == "cls"){
4150                     b += ' class="' + o["cls"] + '"';
4151                 }else if(attr == "htmlFor"){
4152                     b += ' for="' + o["htmlFor"] + '"';
4153                 }else{
4154                     b += " " + attr + '="' + o[attr] + '"';
4155                 }
4156             }
4157         }
4158         if(emptyTags.test(o.tag)){
4159             b += "/>";
4160         }else{
4161             b += ">";
4162             var cn = o.children || o.cn;
4163             if(cn){
4164                 //http://bugs.kde.org/show_bug.cgi?id=71506
4165                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166                     for(var i = 0, len = cn.length; i < len; i++) {
4167                         b += createHtml(cn[i], b);
4168                     }
4169                 }else{
4170                     b += createHtml(cn, b);
4171                 }
4172             }
4173             if(o.html){
4174                 b += o.html;
4175             }
4176             b += "</" + o.tag + ">";
4177         }
4178         return b;
4179     };
4180
4181     // build as dom
4182     /** @ignore */
4183     var createDom = function(o, parentNode){
4184          
4185         // defininition craeted..
4186         var ns = false;
4187         if (o.ns && o.ns != 'html') {
4188                
4189             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190                 xmlns[o.ns] = o.xmlns;
4191                 ns = o.xmlns;
4192             }
4193             if (typeof(xmlns[o.ns]) == 'undefined') {
4194                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4195             }
4196             ns = xmlns[o.ns];
4197         }
4198         
4199         
4200         if (typeof(o) == 'string') {
4201             return parentNode.appendChild(document.createTextNode(o));
4202         }
4203         o.tag = o.tag || div;
4204         if (o.ns && Roo.isIE) {
4205             ns = false;
4206             o.tag = o.ns + ':' + o.tag;
4207             
4208         }
4209         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4210         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4211         for(var attr in o){
4212             
4213             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4214                     attr == "style" || typeof o[attr] == "function") continue;
4215                     
4216             if(attr=="cls" && Roo.isIE){
4217                 el.className = o["cls"];
4218             }else{
4219                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220                 else el[attr] = o[attr];
4221             }
4222         }
4223         Roo.DomHelper.applyStyles(el, o.style);
4224         var cn = o.children || o.cn;
4225         if(cn){
4226             //http://bugs.kde.org/show_bug.cgi?id=71506
4227              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228                 for(var i = 0, len = cn.length; i < len; i++) {
4229                     createDom(cn[i], el);
4230                 }
4231             }else{
4232                 createDom(cn, el);
4233             }
4234         }
4235         if(o.html){
4236             el.innerHTML = o.html;
4237         }
4238         if(parentNode){
4239            parentNode.appendChild(el);
4240         }
4241         return el;
4242     };
4243
4244     var ieTable = function(depth, s, h, e){
4245         tempTableEl.innerHTML = [s, h, e].join('');
4246         var i = -1, el = tempTableEl;
4247         while(++i < depth){
4248             el = el.firstChild;
4249         }
4250         return el;
4251     };
4252
4253     // kill repeat to save bytes
4254     var ts = '<table>',
4255         te = '</table>',
4256         tbs = ts+'<tbody>',
4257         tbe = '</tbody>'+te,
4258         trs = tbs + '<tr>',
4259         tre = '</tr>'+tbe;
4260
4261     /**
4262      * @ignore
4263      * Nasty code for IE's broken table implementation
4264      */
4265     var insertIntoTable = function(tag, where, el, html){
4266         if(!tempTableEl){
4267             tempTableEl = document.createElement('div');
4268         }
4269         var node;
4270         var before = null;
4271         if(tag == 'td'){
4272             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4273                 return;
4274             }
4275             if(where == 'beforebegin'){
4276                 before = el;
4277                 el = el.parentNode;
4278             } else{
4279                 before = el.nextSibling;
4280                 el = el.parentNode;
4281             }
4282             node = ieTable(4, trs, html, tre);
4283         }
4284         else if(tag == 'tr'){
4285             if(where == 'beforebegin'){
4286                 before = el;
4287                 el = el.parentNode;
4288                 node = ieTable(3, tbs, html, tbe);
4289             } else if(where == 'afterend'){
4290                 before = el.nextSibling;
4291                 el = el.parentNode;
4292                 node = ieTable(3, tbs, html, tbe);
4293             } else{ // INTO a TR
4294                 if(where == 'afterbegin'){
4295                     before = el.firstChild;
4296                 }
4297                 node = ieTable(4, trs, html, tre);
4298             }
4299         } else if(tag == 'tbody'){
4300             if(where == 'beforebegin'){
4301                 before = el;
4302                 el = el.parentNode;
4303                 node = ieTable(2, ts, html, te);
4304             } else if(where == 'afterend'){
4305                 before = el.nextSibling;
4306                 el = el.parentNode;
4307                 node = ieTable(2, ts, html, te);
4308             } else{
4309                 if(where == 'afterbegin'){
4310                     before = el.firstChild;
4311                 }
4312                 node = ieTable(3, tbs, html, tbe);
4313             }
4314         } else{ // TABLE
4315             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4316                 return;
4317             }
4318             if(where == 'afterbegin'){
4319                 before = el.firstChild;
4320             }
4321             node = ieTable(2, ts, html, te);
4322         }
4323         el.insertBefore(node, before);
4324         return node;
4325     };
4326
4327     return {
4328     /** True to force the use of DOM instead of html fragments @type Boolean */
4329     useDom : false,
4330
4331     /**
4332      * Returns the markup for the passed Element(s) config
4333      * @param {Object} o The Dom object spec (and children)
4334      * @return {String}
4335      */
4336     markup : function(o){
4337         return createHtml(o);
4338     },
4339
4340     /**
4341      * Applies a style specification to an element
4342      * @param {String/HTMLElement} el The element to apply styles to
4343      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344      * a function which returns such a specification.
4345      */
4346     applyStyles : function(el, styles){
4347         if(styles){
4348            el = Roo.fly(el);
4349            if(typeof styles == "string"){
4350                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4351                var matches;
4352                while ((matches = re.exec(styles)) != null){
4353                    el.setStyle(matches[1], matches[2]);
4354                }
4355            }else if (typeof styles == "object"){
4356                for (var style in styles){
4357                   el.setStyle(style, styles[style]);
4358                }
4359            }else if (typeof styles == "function"){
4360                 Roo.DomHelper.applyStyles(el, styles.call());
4361            }
4362         }
4363     },
4364
4365     /**
4366      * Inserts an HTML fragment into the Dom
4367      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368      * @param {HTMLElement} el The context element
4369      * @param {String} html The HTML fragmenet
4370      * @return {HTMLElement} The new node
4371      */
4372     insertHtml : function(where, el, html){
4373         where = where.toLowerCase();
4374         if(el.insertAdjacentHTML){
4375             if(tableRe.test(el.tagName)){
4376                 var rs;
4377                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4378                     return rs;
4379                 }
4380             }
4381             switch(where){
4382                 case "beforebegin":
4383                     el.insertAdjacentHTML('BeforeBegin', html);
4384                     return el.previousSibling;
4385                 case "afterbegin":
4386                     el.insertAdjacentHTML('AfterBegin', html);
4387                     return el.firstChild;
4388                 case "beforeend":
4389                     el.insertAdjacentHTML('BeforeEnd', html);
4390                     return el.lastChild;
4391                 case "afterend":
4392                     el.insertAdjacentHTML('AfterEnd', html);
4393                     return el.nextSibling;
4394             }
4395             throw 'Illegal insertion point -> "' + where + '"';
4396         }
4397         var range = el.ownerDocument.createRange();
4398         var frag;
4399         switch(where){
4400              case "beforebegin":
4401                 range.setStartBefore(el);
4402                 frag = range.createContextualFragment(html);
4403                 el.parentNode.insertBefore(frag, el);
4404                 return el.previousSibling;
4405              case "afterbegin":
4406                 if(el.firstChild){
4407                     range.setStartBefore(el.firstChild);
4408                     frag = range.createContextualFragment(html);
4409                     el.insertBefore(frag, el.firstChild);
4410                     return el.firstChild;
4411                 }else{
4412                     el.innerHTML = html;
4413                     return el.firstChild;
4414                 }
4415             case "beforeend":
4416                 if(el.lastChild){
4417                     range.setStartAfter(el.lastChild);
4418                     frag = range.createContextualFragment(html);
4419                     el.appendChild(frag);
4420                     return el.lastChild;
4421                 }else{
4422                     el.innerHTML = html;
4423                     return el.lastChild;
4424                 }
4425             case "afterend":
4426                 range.setStartAfter(el);
4427                 frag = range.createContextualFragment(html);
4428                 el.parentNode.insertBefore(frag, el.nextSibling);
4429                 return el.nextSibling;
4430             }
4431             throw 'Illegal insertion point -> "' + where + '"';
4432     },
4433
4434     /**
4435      * Creates new Dom element(s) and inserts them before el
4436      * @param {String/HTMLElement/Element} el The context element
4437      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439      * @return {HTMLElement/Roo.Element} The new node
4440      */
4441     insertBefore : function(el, o, returnElement){
4442         return this.doInsert(el, o, returnElement, "beforeBegin");
4443     },
4444
4445     /**
4446      * Creates new Dom element(s) and inserts them after el
4447      * @param {String/HTMLElement/Element} el The context element
4448      * @param {Object} o The Dom object spec (and children)
4449      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450      * @return {HTMLElement/Roo.Element} The new node
4451      */
4452     insertAfter : function(el, o, returnElement){
4453         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4454     },
4455
4456     /**
4457      * Creates new Dom element(s) and inserts them as the first child of el
4458      * @param {String/HTMLElement/Element} el The context element
4459      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461      * @return {HTMLElement/Roo.Element} The new node
4462      */
4463     insertFirst : function(el, o, returnElement){
4464         return this.doInsert(el, o, returnElement, "afterBegin");
4465     },
4466
4467     // private
4468     doInsert : function(el, o, returnElement, pos, sibling){
4469         el = Roo.getDom(el);
4470         var newNode;
4471         if(this.useDom || o.ns){
4472             newNode = createDom(o, null);
4473             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4474         }else{
4475             var html = createHtml(o);
4476             newNode = this.insertHtml(pos, el, html);
4477         }
4478         return returnElement ? Roo.get(newNode, true) : newNode;
4479     },
4480
4481     /**
4482      * Creates new Dom element(s) and appends them to el
4483      * @param {String/HTMLElement/Element} el The context element
4484      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486      * @return {HTMLElement/Roo.Element} The new node
4487      */
4488     append : function(el, o, returnElement){
4489         el = Roo.getDom(el);
4490         var newNode;
4491         if(this.useDom || o.ns){
4492             newNode = createDom(o, null);
4493             el.appendChild(newNode);
4494         }else{
4495             var html = createHtml(o);
4496             newNode = this.insertHtml("beforeEnd", el, html);
4497         }
4498         return returnElement ? Roo.get(newNode, true) : newNode;
4499     },
4500
4501     /**
4502      * Creates new Dom element(s) and overwrites the contents of el with them
4503      * @param {String/HTMLElement/Element} el The context element
4504      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506      * @return {HTMLElement/Roo.Element} The new node
4507      */
4508     overwrite : function(el, o, returnElement){
4509         el = Roo.getDom(el);
4510         if (o.ns) {
4511           
4512             while (el.childNodes.length) {
4513                 el.removeChild(el.firstChild);
4514             }
4515             createDom(o, el);
4516         } else {
4517             el.innerHTML = createHtml(o);   
4518         }
4519         
4520         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4521     },
4522
4523     /**
4524      * Creates a new Roo.DomHelper.Template from the Dom object spec
4525      * @param {Object} o The Dom object spec (and children)
4526      * @return {Roo.DomHelper.Template} The new template
4527      */
4528     createTemplate : function(o){
4529         var html = createHtml(o);
4530         return new Roo.Template(html);
4531     }
4532     };
4533 }();
4534 /*
4535  * Based on:
4536  * Ext JS Library 1.1.1
4537  * Copyright(c) 2006-2007, Ext JS, LLC.
4538  *
4539  * Originally Released Under LGPL - original licence link has changed is not relivant.
4540  *
4541  * Fork - LGPL
4542  * <script type="text/javascript">
4543  */
4544  
4545 /**
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4549 * Usage:
4550 <pre><code>
4551 var t = new Roo.Template({
4552     html :  '&lt;div name="{id}"&gt;' + 
4553         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4554         '&lt;/div&gt;',
4555     myformat: function (value, allValues) {
4556         return 'XX' + value;
4557     }
4558 });
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4560 </code></pre>
4561 * For more information see this blog post with examples:
4562 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563      - Create Elements using DOM, HTML fragments and Templates</a>. 
4564 * @constructor
4565 * @param {Object} cfg - Configuration object.
4566 */
4567 Roo.Template = function(cfg){
4568     // BC!
4569     if(cfg instanceof Array){
4570         cfg = cfg.join("");
4571     }else if(arguments.length > 1){
4572         cfg = Array.prototype.join.call(arguments, "");
4573     }
4574     
4575     
4576     if (typeof(cfg) == 'object') {
4577         Roo.apply(this,cfg)
4578     } else {
4579         // bc
4580         this.html = cfg;
4581     }
4582     if (this.url) {
4583         this.load();
4584     }
4585     
4586 };
4587 Roo.Template.prototype = {
4588     
4589     /**
4590      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4591      *                    it should be fixed so that template is observable...
4592      */
4593     url : false,
4594     /**
4595      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4596      */
4597     html : '',
4598     /**
4599      * Returns an HTML fragment of this template with the specified values applied.
4600      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4601      * @return {String} The HTML fragment
4602      */
4603     applyTemplate : function(values){
4604         try {
4605            
4606             if(this.compiled){
4607                 return this.compiled(values);
4608             }
4609             var useF = this.disableFormats !== true;
4610             var fm = Roo.util.Format, tpl = this;
4611             var fn = function(m, name, format, args){
4612                 if(format && useF){
4613                     if(format.substr(0, 5) == "this."){
4614                         return tpl.call(format.substr(5), values[name], values);
4615                     }else{
4616                         if(args){
4617                             // quoted values are required for strings in compiled templates, 
4618                             // but for non compiled we need to strip them
4619                             // quoted reversed for jsmin
4620                             var re = /^\s*['"](.*)["']\s*$/;
4621                             args = args.split(',');
4622                             for(var i = 0, len = args.length; i < len; i++){
4623                                 args[i] = args[i].replace(re, "$1");
4624                             }
4625                             args = [values[name]].concat(args);
4626                         }else{
4627                             args = [values[name]];
4628                         }
4629                         return fm[format].apply(fm, args);
4630                     }
4631                 }else{
4632                     return values[name] !== undefined ? values[name] : "";
4633                 }
4634             };
4635             return this.html.replace(this.re, fn);
4636         } catch (e) {
4637             Roo.log(e);
4638             throw e;
4639         }
4640          
4641     },
4642     
4643     loading : false,
4644       
4645     load : function ()
4646     {
4647          
4648         if (this.loading) {
4649             return;
4650         }
4651         var _t = this;
4652         
4653         this.loading = true;
4654         this.compiled = false;
4655         
4656         var cx = new Roo.data.Connection();
4657         cx.request({
4658             url : this.url,
4659             method : 'GET',
4660             success : function (response) {
4661                 _t.loading = false;
4662                 _t.html = response.responseText;
4663                 _t.url = false;
4664                 _t.compile();
4665              },
4666             failure : function(response) {
4667                 Roo.log("Template failed to load from " + _t.url);
4668                 _t.loading = false;
4669             }
4670         });
4671     },
4672
4673     /**
4674      * Sets the HTML used as the template and optionally compiles it.
4675      * @param {String} html
4676      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677      * @return {Roo.Template} this
4678      */
4679     set : function(html, compile){
4680         this.html = html;
4681         this.compiled = null;
4682         if(compile){
4683             this.compile();
4684         }
4685         return this;
4686     },
4687     
4688     /**
4689      * True to disable format functions (defaults to false)
4690      * @type Boolean
4691      */
4692     disableFormats : false,
4693     
4694     /**
4695     * The regular expression used to match template variables 
4696     * @type RegExp
4697     * @property 
4698     */
4699     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4700     
4701     /**
4702      * Compiles the template into an internal function, eliminating the RegEx overhead.
4703      * @return {Roo.Template} this
4704      */
4705     compile : function(){
4706         var fm = Roo.util.Format;
4707         var useF = this.disableFormats !== true;
4708         var sep = Roo.isGecko ? "+" : ",";
4709         var fn = function(m, name, format, args){
4710             if(format && useF){
4711                 args = args ? ',' + args : "";
4712                 if(format.substr(0, 5) != "this."){
4713                     format = "fm." + format + '(';
4714                 }else{
4715                     format = 'this.call("'+ format.substr(5) + '", ';
4716                     args = ", values";
4717                 }
4718             }else{
4719                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4720             }
4721             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4722         };
4723         var body;
4724         // branched to use + in gecko and [].join() in others
4725         if(Roo.isGecko){
4726             body = "this.compiled = function(values){ return '" +
4727                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4728                     "';};";
4729         }else{
4730             body = ["this.compiled = function(values){ return ['"];
4731             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732             body.push("'].join('');};");
4733             body = body.join('');
4734         }
4735         /**
4736          * eval:var:values
4737          * eval:var:fm
4738          */
4739         eval(body);
4740         return this;
4741     },
4742     
4743     // private function used to call members
4744     call : function(fnName, value, allValues){
4745         return this[fnName](value, allValues);
4746     },
4747     
4748     /**
4749      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750      * @param {String/HTMLElement/Roo.Element} el The context element
4751      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753      * @return {HTMLElement/Roo.Element} The new node or Element
4754      */
4755     insertFirst: function(el, values, returnElement){
4756         return this.doInsert('afterBegin', el, values, returnElement);
4757     },
4758
4759     /**
4760      * Applies the supplied values to the template and inserts the new node(s) before el.
4761      * @param {String/HTMLElement/Roo.Element} el The context element
4762      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764      * @return {HTMLElement/Roo.Element} The new node or Element
4765      */
4766     insertBefore: function(el, values, returnElement){
4767         return this.doInsert('beforeBegin', el, values, returnElement);
4768     },
4769
4770     /**
4771      * Applies the supplied values to the template and inserts the new node(s) after el.
4772      * @param {String/HTMLElement/Roo.Element} el The context element
4773      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775      * @return {HTMLElement/Roo.Element} The new node or Element
4776      */
4777     insertAfter : function(el, values, returnElement){
4778         return this.doInsert('afterEnd', el, values, returnElement);
4779     },
4780     
4781     /**
4782      * Applies the supplied values to the template and appends the new node(s) to el.
4783      * @param {String/HTMLElement/Roo.Element} el The context element
4784      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4785      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786      * @return {HTMLElement/Roo.Element} The new node or Element
4787      */
4788     append : function(el, values, returnElement){
4789         return this.doInsert('beforeEnd', el, values, returnElement);
4790     },
4791
4792     doInsert : function(where, el, values, returnEl){
4793         el = Roo.getDom(el);
4794         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795         return returnEl ? Roo.get(newNode, true) : newNode;
4796     },
4797
4798     /**
4799      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800      * @param {String/HTMLElement/Roo.Element} el The context element
4801      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4802      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803      * @return {HTMLElement/Roo.Element} The new node or Element
4804      */
4805     overwrite : function(el, values, returnElement){
4806         el = Roo.getDom(el);
4807         el.innerHTML = this.applyTemplate(values);
4808         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4809     }
4810 };
4811 /**
4812  * Alias for {@link #applyTemplate}
4813  * @method
4814  */
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4816
4817 // backwards compat
4818 Roo.DomHelper.Template = Roo.Template;
4819
4820 /**
4821  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822  * @param {String/HTMLElement} el A DOM element or its id
4823  * @returns {Roo.Template} The created template
4824  * @static
4825  */
4826 Roo.Template.from = function(el){
4827     el = Roo.getDom(el);
4828     return new Roo.Template(el.value || el.innerHTML);
4829 };/*
4830  * Based on:
4831  * Ext JS Library 1.1.1
4832  * Copyright(c) 2006-2007, Ext JS, LLC.
4833  *
4834  * Originally Released Under LGPL - original licence link has changed is not relivant.
4835  *
4836  * Fork - LGPL
4837  * <script type="text/javascript">
4838  */
4839  
4840
4841 /*
4842  * This is code is also distributed under MIT license for use
4843  * with jQuery and prototype JavaScript libraries.
4844  */
4845 /**
4846  * @class Roo.DomQuery
4847 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4848 <p>
4849 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4850
4851 <p>
4852 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4853 </p>
4854 <h4>Element Selectors:</h4>
4855 <ul class="list">
4856     <li> <b>*</b> any element</li>
4857     <li> <b>E</b> an element with the tag E</li>
4858     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4862 </ul>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4865 <ul class="list">
4866     <li> <b>E[foo]</b> has an attribute "foo"</li>
4867     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4873 </ul>
4874 <h4>Pseudo Classes:</h4>
4875 <ul class="list">
4876     <li> <b>E:first-child</b> E is the first child of its parent</li>
4877     <li> <b>E:last-child</b> E is the last child of its parent</li>
4878     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4879     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881     <li> <b>E:only-child</b> E is the only child of its parent</li>
4882     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4883     <li> <b>E:first</b> the first E in the resultset</li>
4884     <li> <b>E:last</b> the last E in the resultset</li>
4885     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4894 </ul>
4895 <h4>CSS Value Selectors:</h4>
4896 <ul class="list">
4897     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4903 </ul>
4904  * @singleton
4905  */
4906 Roo.DomQuery = function(){
4907     var cache = {}, simpleCache = {}, valueCache = {};
4908     var nonSpace = /\S/;
4909     var trimRe = /^\s+|\s+$/g;
4910     var tplRe = /\{(\d+)\}/g;
4911     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912     var tagTokenRe = /^(#)?([\w-\*]+)/;
4913     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4914
4915     function child(p, index){
4916         var i = 0;
4917         var n = p.firstChild;
4918         while(n){
4919             if(n.nodeType == 1){
4920                if(++i == index){
4921                    return n;
4922                }
4923             }
4924             n = n.nextSibling;
4925         }
4926         return null;
4927     };
4928
4929     function next(n){
4930         while((n = n.nextSibling) && n.nodeType != 1);
4931         return n;
4932     };
4933
4934     function prev(n){
4935         while((n = n.previousSibling) && n.nodeType != 1);
4936         return n;
4937     };
4938
4939     function children(d){
4940         var n = d.firstChild, ni = -1;
4941             while(n){
4942                 var nx = n.nextSibling;
4943                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4944                     d.removeChild(n);
4945                 }else{
4946                     n.nodeIndex = ++ni;
4947                 }
4948                 n = nx;
4949             }
4950             return this;
4951         };
4952
4953     function byClassName(c, a, v){
4954         if(!v){
4955             return c;
4956         }
4957         var r = [], ri = -1, cn;
4958         for(var i = 0, ci; ci = c[i]; i++){
4959             if((' '+ci.className+' ').indexOf(v) != -1){
4960                 r[++ri] = ci;
4961             }
4962         }
4963         return r;
4964     };
4965
4966     function attrValue(n, attr){
4967         if(!n.tagName && typeof n.length != "undefined"){
4968             n = n[0];
4969         }
4970         if(!n){
4971             return null;
4972         }
4973         if(attr == "for"){
4974             return n.htmlFor;
4975         }
4976         if(attr == "class" || attr == "className"){
4977             return n.className;
4978         }
4979         return n.getAttribute(attr) || n[attr];
4980
4981     };
4982
4983     function getNodes(ns, mode, tagName){
4984         var result = [], ri = -1, cs;
4985         if(!ns){
4986             return result;
4987         }
4988         tagName = tagName || "*";
4989         if(typeof ns.getElementsByTagName != "undefined"){
4990             ns = [ns];
4991         }
4992         if(!mode){
4993             for(var i = 0, ni; ni = ns[i]; i++){
4994                 cs = ni.getElementsByTagName(tagName);
4995                 for(var j = 0, ci; ci = cs[j]; j++){
4996                     result[++ri] = ci;
4997                 }
4998             }
4999         }else if(mode == "/" || mode == ">"){
5000             var utag = tagName.toUpperCase();
5001             for(var i = 0, ni, cn; ni = ns[i]; i++){
5002                 cn = ni.children || ni.childNodes;
5003                 for(var j = 0, cj; cj = cn[j]; j++){
5004                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5005                         result[++ri] = cj;
5006                     }
5007                 }
5008             }
5009         }else if(mode == "+"){
5010             var utag = tagName.toUpperCase();
5011             for(var i = 0, n; n = ns[i]; i++){
5012                 while((n = n.nextSibling) && n.nodeType != 1);
5013                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5014                     result[++ri] = n;
5015                 }
5016             }
5017         }else if(mode == "~"){
5018             for(var i = 0, n; n = ns[i]; i++){
5019                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5020                 if(n){
5021                     result[++ri] = n;
5022                 }
5023             }
5024         }
5025         return result;
5026     };
5027
5028     function concat(a, b){
5029         if(b.slice){
5030             return a.concat(b);
5031         }
5032         for(var i = 0, l = b.length; i < l; i++){
5033             a[a.length] = b[i];
5034         }
5035         return a;
5036     }
5037
5038     function byTag(cs, tagName){
5039         if(cs.tagName || cs == document){
5040             cs = [cs];
5041         }
5042         if(!tagName){
5043             return cs;
5044         }
5045         var r = [], ri = -1;
5046         tagName = tagName.toLowerCase();
5047         for(var i = 0, ci; ci = cs[i]; i++){
5048             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5049                 r[++ri] = ci;
5050             }
5051         }
5052         return r;
5053     };
5054
5055     function byId(cs, attr, id){
5056         if(cs.tagName || cs == document){
5057             cs = [cs];
5058         }
5059         if(!id){
5060             return cs;
5061         }
5062         var r = [], ri = -1;
5063         for(var i = 0,ci; ci = cs[i]; i++){
5064             if(ci && ci.id == id){
5065                 r[++ri] = ci;
5066                 return r;
5067             }
5068         }
5069         return r;
5070     };
5071
5072     function byAttribute(cs, attr, value, op, custom){
5073         var r = [], ri = -1, st = custom=="{";
5074         var f = Roo.DomQuery.operators[op];
5075         for(var i = 0, ci; ci = cs[i]; i++){
5076             var a;
5077             if(st){
5078                 a = Roo.DomQuery.getStyle(ci, attr);
5079             }
5080             else if(attr == "class" || attr == "className"){
5081                 a = ci.className;
5082             }else if(attr == "for"){
5083                 a = ci.htmlFor;
5084             }else if(attr == "href"){
5085                 a = ci.getAttribute("href", 2);
5086             }else{
5087                 a = ci.getAttribute(attr);
5088             }
5089             if((f && f(a, value)) || (!f && a)){
5090                 r[++ri] = ci;
5091             }
5092         }
5093         return r;
5094     };
5095
5096     function byPseudo(cs, name, value){
5097         return Roo.DomQuery.pseudos[name](cs, value);
5098     };
5099
5100     // This is for IE MSXML which does not support expandos.
5101     // IE runs the same speed using setAttribute, however FF slows way down
5102     // and Safari completely fails so they need to continue to use expandos.
5103     var isIE = window.ActiveXObject ? true : false;
5104
5105     // this eval is stop the compressor from
5106     // renaming the variable to something shorter
5107     
5108     /** eval:var:batch */
5109     var batch = 30803; 
5110
5111     var key = 30803;
5112
5113     function nodupIEXml(cs){
5114         var d = ++key;
5115         cs[0].setAttribute("_nodup", d);
5116         var r = [cs[0]];
5117         for(var i = 1, len = cs.length; i < len; i++){
5118             var c = cs[i];
5119             if(!c.getAttribute("_nodup") != d){
5120                 c.setAttribute("_nodup", d);
5121                 r[r.length] = c;
5122             }
5123         }
5124         for(var i = 0, len = cs.length; i < len; i++){
5125             cs[i].removeAttribute("_nodup");
5126         }
5127         return r;
5128     }
5129
5130     function nodup(cs){
5131         if(!cs){
5132             return [];
5133         }
5134         var len = cs.length, c, i, r = cs, cj, ri = -1;
5135         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5136             return cs;
5137         }
5138         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139             return nodupIEXml(cs);
5140         }
5141         var d = ++key;
5142         cs[0]._nodup = d;
5143         for(i = 1; c = cs[i]; i++){
5144             if(c._nodup != d){
5145                 c._nodup = d;
5146             }else{
5147                 r = [];
5148                 for(var j = 0; j < i; j++){
5149                     r[++ri] = cs[j];
5150                 }
5151                 for(j = i+1; cj = cs[j]; j++){
5152                     if(cj._nodup != d){
5153                         cj._nodup = d;
5154                         r[++ri] = cj;
5155                     }
5156                 }
5157                 return r;
5158             }
5159         }
5160         return r;
5161     }
5162
5163     function quickDiffIEXml(c1, c2){
5164         var d = ++key;
5165         for(var i = 0, len = c1.length; i < len; i++){
5166             c1[i].setAttribute("_qdiff", d);
5167         }
5168         var r = [];
5169         for(var i = 0, len = c2.length; i < len; i++){
5170             if(c2[i].getAttribute("_qdiff") != d){
5171                 r[r.length] = c2[i];
5172             }
5173         }
5174         for(var i = 0, len = c1.length; i < len; i++){
5175            c1[i].removeAttribute("_qdiff");
5176         }
5177         return r;
5178     }
5179
5180     function quickDiff(c1, c2){
5181         var len1 = c1.length;
5182         if(!len1){
5183             return c2;
5184         }
5185         if(isIE && c1[0].selectSingleNode){
5186             return quickDiffIEXml(c1, c2);
5187         }
5188         var d = ++key;
5189         for(var i = 0; i < len1; i++){
5190             c1[i]._qdiff = d;
5191         }
5192         var r = [];
5193         for(var i = 0, len = c2.length; i < len; i++){
5194             if(c2[i]._qdiff != d){
5195                 r[r.length] = c2[i];
5196             }
5197         }
5198         return r;
5199     }
5200
5201     function quickId(ns, mode, root, id){
5202         if(ns == root){
5203            var d = root.ownerDocument || root;
5204            return d.getElementById(id);
5205         }
5206         ns = getNodes(ns, mode, "*");
5207         return byId(ns, null, id);
5208     }
5209
5210     return {
5211         getStyle : function(el, name){
5212             return Roo.fly(el).getStyle(name);
5213         },
5214         /**
5215          * Compiles a selector/xpath query into a reusable function. The returned function
5216          * takes one parameter "root" (optional), which is the context node from where the query should start.
5217          * @param {String} selector The selector/xpath query
5218          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219          * @return {Function}
5220          */
5221         compile : function(path, type){
5222             type = type || "select";
5223             
5224             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225             var q = path, mode, lq;
5226             var tk = Roo.DomQuery.matchers;
5227             var tklen = tk.length;
5228             var mm;
5229
5230             // accept leading mode switch
5231             var lmode = q.match(modeRe);
5232             if(lmode && lmode[1]){
5233                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5234                 q = q.replace(lmode[1], "");
5235             }
5236             // strip leading slashes
5237             while(path.substr(0, 1)=="/"){
5238                 path = path.substr(1);
5239             }
5240
5241             while(q && lq != q){
5242                 lq = q;
5243                 var tm = q.match(tagTokenRe);
5244                 if(type == "select"){
5245                     Roo.log('tm');
5246                     Roo.log(tm);
5247                     if(tm){
5248                         if(tm[1] == "#"){
5249                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5250                         }else{
5251                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5252                         }
5253                         q = q.replace(tm[0], "");
5254                         
5255                     }else if(q.substr(0, 1) != '@'){
5256                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5257                     }
5258                     Roo.log('fn');
5259                         Roo.log(fn);
5260                         Roo.log(q);
5261                 }else{
5262                     if(tm){
5263                         if(tm[1] == "#"){
5264                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5265                         }else{
5266                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5267                         }
5268                         q = q.replace(tm[0], "");
5269                     }
5270                 }
5271                 while(!(mm = q.match(modeRe))){
5272                     var matched = false;
5273                     for(var j = 0; j < tklen; j++){
5274                         var t = tk[j];
5275                         var m = q.match(t.re);
5276                         if(m){
5277                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5278                                                     return m[i];
5279                                                 });
5280                             q = q.replace(m[0], "");
5281                             matched = true;
5282                             break;
5283                         }
5284                     }
5285                     // prevent infinite loop on bad selector
5286                     if(!matched){
5287                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5288                     }
5289                 }
5290                 if(mm[1]){
5291                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5292                     q = q.replace(mm[1], "");
5293                 }
5294             }
5295             fn[fn.length] = "return nodup(n);\n}";
5296             
5297              /** 
5298               * list of variables that need from compression as they are used by eval.
5299              *  eval:var:batch 
5300              *  eval:var:nodup
5301              *  eval:var:byTag
5302              *  eval:var:ById
5303              *  eval:var:getNodes
5304              *  eval:var:quickId
5305              *  eval:var:mode
5306              *  eval:var:root
5307              *  eval:var:n
5308              *  eval:var:byClassName
5309              *  eval:var:byPseudo
5310              *  eval:var:byAttribute
5311              *  eval:var:attrValue
5312              * 
5313              **/ 
5314             eval(fn.join(""));
5315             return f;
5316         },
5317
5318         /**
5319          * Selects a group of elements.
5320          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5321          * @param {Node} root (optional) The start of the query (defaults to document).
5322          * @return {Array}
5323          */
5324         select : function(path, root, type){
5325             if(!root || root == document){
5326                 root = document;
5327             }
5328             if(typeof root == "string"){
5329                 root = document.getElementById(root);
5330             }
5331             var paths = path.split(",");
5332             var results = [];
5333             for(var i = 0, len = paths.length; i < len; i++){
5334                 var p = paths[i].replace(trimRe, "");
5335                 if(!cache[p]){
5336                     cache[p] = Roo.DomQuery.compile(p);
5337                     if(!cache[p]){
5338                         throw p + " is not a valid selector";
5339                     }
5340                 }
5341                 var result = cache[p](root);
5342                 if(result && result != document){
5343                     results = results.concat(result);
5344                 }
5345             }
5346             if(paths.length > 1){
5347                 return nodup(results);
5348             }
5349             return results;
5350         },
5351
5352         /**
5353          * Selects a single element.
5354          * @param {String} selector The selector/xpath query
5355          * @param {Node} root (optional) The start of the query (defaults to document).
5356          * @return {Element}
5357          */
5358         selectNode : function(path, root){
5359             return Roo.DomQuery.select(path, root)[0];
5360         },
5361
5362         /**
5363          * Selects the value of a node, optionally replacing null with the defaultValue.
5364          * @param {String} selector The selector/xpath query
5365          * @param {Node} root (optional) The start of the query (defaults to document).
5366          * @param {String} defaultValue
5367          */
5368         selectValue : function(path, root, defaultValue){
5369             path = path.replace(trimRe, "");
5370             if(!valueCache[path]){
5371                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5372             }
5373             var n = valueCache[path](root);
5374             n = n[0] ? n[0] : n;
5375             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5376             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5377         },
5378
5379         /**
5380          * Selects the value of a node, parsing integers and floats.
5381          * @param {String} selector The selector/xpath query
5382          * @param {Node} root (optional) The start of the query (defaults to document).
5383          * @param {Number} defaultValue
5384          * @return {Number}
5385          */
5386         selectNumber : function(path, root, defaultValue){
5387             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5388             return parseFloat(v);
5389         },
5390
5391         /**
5392          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5393          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5394          * @param {String} selector The simple selector to test
5395          * @return {Boolean}
5396          */
5397         is : function(el, ss){
5398             if(typeof el == "string"){
5399                 el = document.getElementById(el);
5400             }
5401             var isArray = (el instanceof Array);
5402             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5403             return isArray ? (result.length == el.length) : (result.length > 0);
5404         },
5405
5406         /**
5407          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5408          * @param {Array} el An array of elements to filter
5409          * @param {String} selector The simple selector to test
5410          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5411          * the selector instead of the ones that match
5412          * @return {Array}
5413          */
5414         filter : function(els, ss, nonMatches){
5415             ss = ss.replace(trimRe, "");
5416             if(!simpleCache[ss]){
5417                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5418             }
5419             var result = simpleCache[ss](els);
5420             return nonMatches ? quickDiff(result, els) : result;
5421         },
5422
5423         /**
5424          * Collection of matching regular expressions and code snippets.
5425          */
5426         matchers : [{
5427                 re: /^\.([\w-]+)/,
5428                 select: 'n = byClassName(n, null, " {1} ");'
5429             }, {
5430                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5431                 select: 'n = byPseudo(n, "{1}", "{2}");'
5432             },{
5433                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5434                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5435             }, {
5436                 re: /^#([\w-]+)/,
5437                 select: 'n = byId(n, null, "{1}");'
5438             },{
5439                 re: /^@([\w-]+)/,
5440                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5441             }
5442         ],
5443
5444         /**
5445          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5446          * 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;.
5447          */
5448         operators : {
5449             "=" : function(a, v){
5450                 return a == v;
5451             },
5452             "!=" : function(a, v){
5453                 return a != v;
5454             },
5455             "^=" : function(a, v){
5456                 return a && a.substr(0, v.length) == v;
5457             },
5458             "$=" : function(a, v){
5459                 return a && a.substr(a.length-v.length) == v;
5460             },
5461             "*=" : function(a, v){
5462                 return a && a.indexOf(v) !== -1;
5463             },
5464             "%=" : function(a, v){
5465                 return (a % v) == 0;
5466             },
5467             "|=" : function(a, v){
5468                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5469             },
5470             "~=" : function(a, v){
5471                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5472             }
5473         },
5474
5475         /**
5476          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5477          * and the argument (if any) supplied in the selector.
5478          */
5479         pseudos : {
5480             "first-child" : function(c){
5481                 var r = [], ri = -1, n;
5482                 for(var i = 0, ci; ci = n = c[i]; i++){
5483                     while((n = n.previousSibling) && n.nodeType != 1);
5484                     if(!n){
5485                         r[++ri] = ci;
5486                     }
5487                 }
5488                 return r;
5489             },
5490
5491             "last-child" : function(c){
5492                 var r = [], ri = -1, n;
5493                 for(var i = 0, ci; ci = n = c[i]; i++){
5494                     while((n = n.nextSibling) && n.nodeType != 1);
5495                     if(!n){
5496                         r[++ri] = ci;
5497                     }
5498                 }
5499                 return r;
5500             },
5501
5502             "nth-child" : function(c, a) {
5503                 var r = [], ri = -1;
5504                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5505                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5506                 for(var i = 0, n; n = c[i]; i++){
5507                     var pn = n.parentNode;
5508                     if (batch != pn._batch) {
5509                         var j = 0;
5510                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5511                             if(cn.nodeType == 1){
5512                                cn.nodeIndex = ++j;
5513                             }
5514                         }
5515                         pn._batch = batch;
5516                     }
5517                     if (f == 1) {
5518                         if (l == 0 || n.nodeIndex == l){
5519                             r[++ri] = n;
5520                         }
5521                     } else if ((n.nodeIndex + l) % f == 0){
5522                         r[++ri] = n;
5523                     }
5524                 }
5525
5526                 return r;
5527             },
5528
5529             "only-child" : function(c){
5530                 var r = [], ri = -1;;
5531                 for(var i = 0, ci; ci = c[i]; i++){
5532                     if(!prev(ci) && !next(ci)){
5533                         r[++ri] = ci;
5534                     }
5535                 }
5536                 return r;
5537             },
5538
5539             "empty" : function(c){
5540                 var r = [], ri = -1;
5541                 for(var i = 0, ci; ci = c[i]; i++){
5542                     var cns = ci.childNodes, j = 0, cn, empty = true;
5543                     while(cn = cns[j]){
5544                         ++j;
5545                         if(cn.nodeType == 1 || cn.nodeType == 3){
5546                             empty = false;
5547                             break;
5548                         }
5549                     }
5550                     if(empty){
5551                         r[++ri] = ci;
5552                     }
5553                 }
5554                 return r;
5555             },
5556
5557             "contains" : function(c, v){
5558                 var r = [], ri = -1;
5559                 for(var i = 0, ci; ci = c[i]; i++){
5560                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5561                         r[++ri] = ci;
5562                     }
5563                 }
5564                 return r;
5565             },
5566
5567             "nodeValue" : function(c, v){
5568                 var r = [], ri = -1;
5569                 for(var i = 0, ci; ci = c[i]; i++){
5570                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5571                         r[++ri] = ci;
5572                     }
5573                 }
5574                 return r;
5575             },
5576
5577             "checked" : function(c){
5578                 var r = [], ri = -1;
5579                 for(var i = 0, ci; ci = c[i]; i++){
5580                     if(ci.checked == true){
5581                         r[++ri] = ci;
5582                     }
5583                 }
5584                 return r;
5585             },
5586
5587             "not" : function(c, ss){
5588                 return Roo.DomQuery.filter(c, ss, true);
5589             },
5590
5591             "odd" : function(c){
5592                 return this["nth-child"](c, "odd");
5593             },
5594
5595             "even" : function(c){
5596                 return this["nth-child"](c, "even");
5597             },
5598
5599             "nth" : function(c, a){
5600                 return c[a-1] || [];
5601             },
5602
5603             "first" : function(c){
5604                 return c[0] || [];
5605             },
5606
5607             "last" : function(c){
5608                 return c[c.length-1] || [];
5609             },
5610
5611             "has" : function(c, ss){
5612                 var s = Roo.DomQuery.select;
5613                 var r = [], ri = -1;
5614                 for(var i = 0, ci; ci = c[i]; i++){
5615                     if(s(ss, ci).length > 0){
5616                         r[++ri] = ci;
5617                     }
5618                 }
5619                 return r;
5620             },
5621
5622             "next" : function(c, ss){
5623                 var is = Roo.DomQuery.is;
5624                 var r = [], ri = -1;
5625                 for(var i = 0, ci; ci = c[i]; i++){
5626                     var n = next(ci);
5627                     if(n && is(n, ss)){
5628                         r[++ri] = ci;
5629                     }
5630                 }
5631                 return r;
5632             },
5633
5634             "prev" : function(c, ss){
5635                 var is = Roo.DomQuery.is;
5636                 var r = [], ri = -1;
5637                 for(var i = 0, ci; ci = c[i]; i++){
5638                     var n = prev(ci);
5639                     if(n && is(n, ss)){
5640                         r[++ri] = ci;
5641                     }
5642                 }
5643                 return r;
5644             }
5645         }
5646     };
5647 }();
5648
5649 /**
5650  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5651  * @param {String} path The selector/xpath query
5652  * @param {Node} root (optional) The start of the query (defaults to document).
5653  * @return {Array}
5654  * @member Roo
5655  * @method query
5656  */
5657 Roo.query = Roo.DomQuery.select;
5658 /*
5659  * Based on:
5660  * Ext JS Library 1.1.1
5661  * Copyright(c) 2006-2007, Ext JS, LLC.
5662  *
5663  * Originally Released Under LGPL - original licence link has changed is not relivant.
5664  *
5665  * Fork - LGPL
5666  * <script type="text/javascript">
5667  */
5668
5669 /**
5670  * @class Roo.util.Observable
5671  * Base class that provides a common interface for publishing events. Subclasses are expected to
5672  * to have a property "events" with all the events defined.<br>
5673  * For example:
5674  * <pre><code>
5675  Employee = function(name){
5676     this.name = name;
5677     this.addEvents({
5678         "fired" : true,
5679         "quit" : true
5680     });
5681  }
5682  Roo.extend(Employee, Roo.util.Observable);
5683 </code></pre>
5684  * @param {Object} config properties to use (incuding events / listeners)
5685  */
5686
5687 Roo.util.Observable = function(cfg){
5688     
5689     cfg = cfg|| {};
5690     this.addEvents(cfg.events || {});
5691     if (cfg.events) {
5692         delete cfg.events; // make sure
5693     }
5694      
5695     Roo.apply(this, cfg);
5696     
5697     if(this.listeners){
5698         this.on(this.listeners);
5699         delete this.listeners;
5700     }
5701 };
5702 Roo.util.Observable.prototype = {
5703     /** 
5704  * @cfg {Object} listeners  list of events and functions to call for this object, 
5705  * For example :
5706  * <pre><code>
5707     listeners :  { 
5708        'click' : function(e) {
5709            ..... 
5710         } ,
5711         .... 
5712     } 
5713   </code></pre>
5714  */
5715     
5716     
5717     /**
5718      * Fires the specified event with the passed parameters (minus the event name).
5719      * @param {String} eventName
5720      * @param {Object...} args Variable number of parameters are passed to handlers
5721      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5722      */
5723     fireEvent : function(){
5724         var ce = this.events[arguments[0].toLowerCase()];
5725         if(typeof ce == "object"){
5726             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5727         }else{
5728             return true;
5729         }
5730     },
5731
5732     // private
5733     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5734
5735     /**
5736      * Appends an event handler to this component
5737      * @param {String}   eventName The type of event to listen for
5738      * @param {Function} handler The method the event invokes
5739      * @param {Object}   scope (optional) The scope in which to execute the handler
5740      * function. The handler function's "this" context.
5741      * @param {Object}   options (optional) An object containing handler configuration
5742      * properties. This may contain any of the following properties:<ul>
5743      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5744      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5745      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5746      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5747      * by the specified number of milliseconds. If the event fires again within that time, the original
5748      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5749      * </ul><br>
5750      * <p>
5751      * <b>Combining Options</b><br>
5752      * Using the options argument, it is possible to combine different types of listeners:<br>
5753      * <br>
5754      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5755                 <pre><code>
5756                 el.on('click', this.onClick, this, {
5757                         single: true,
5758                 delay: 100,
5759                 forumId: 4
5760                 });
5761                 </code></pre>
5762      * <p>
5763      * <b>Attaching multiple handlers in 1 call</b><br>
5764      * The method also allows for a single argument to be passed which is a config object containing properties
5765      * which specify multiple handlers.
5766      * <pre><code>
5767                 el.on({
5768                         'click': {
5769                         fn: this.onClick,
5770                         scope: this,
5771                         delay: 100
5772                 }, 
5773                 'mouseover': {
5774                         fn: this.onMouseOver,
5775                         scope: this
5776                 },
5777                 'mouseout': {
5778                         fn: this.onMouseOut,
5779                         scope: this
5780                 }
5781                 });
5782                 </code></pre>
5783      * <p>
5784      * Or a shorthand syntax which passes the same scope object to all handlers:
5785         <pre><code>
5786                 el.on({
5787                         'click': this.onClick,
5788                 'mouseover': this.onMouseOver,
5789                 'mouseout': this.onMouseOut,
5790                 scope: this
5791                 });
5792                 </code></pre>
5793      */
5794     addListener : function(eventName, fn, scope, o){
5795         if(typeof eventName == "object"){
5796             o = eventName;
5797             for(var e in o){
5798                 if(this.filterOptRe.test(e)){
5799                     continue;
5800                 }
5801                 if(typeof o[e] == "function"){
5802                     // shared options
5803                     this.addListener(e, o[e], o.scope,  o);
5804                 }else{
5805                     // individual options
5806                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5807                 }
5808             }
5809             return;
5810         }
5811         o = (!o || typeof o == "boolean") ? {} : o;
5812         eventName = eventName.toLowerCase();
5813         var ce = this.events[eventName] || true;
5814         if(typeof ce == "boolean"){
5815             ce = new Roo.util.Event(this, eventName);
5816             this.events[eventName] = ce;
5817         }
5818         ce.addListener(fn, scope, o);
5819     },
5820
5821     /**
5822      * Removes a listener
5823      * @param {String}   eventName     The type of event to listen for
5824      * @param {Function} handler        The handler to remove
5825      * @param {Object}   scope  (optional) The scope (this object) for the handler
5826      */
5827     removeListener : function(eventName, fn, scope){
5828         var ce = this.events[eventName.toLowerCase()];
5829         if(typeof ce == "object"){
5830             ce.removeListener(fn, scope);
5831         }
5832     },
5833
5834     /**
5835      * Removes all listeners for this object
5836      */
5837     purgeListeners : function(){
5838         for(var evt in this.events){
5839             if(typeof this.events[evt] == "object"){
5840                  this.events[evt].clearListeners();
5841             }
5842         }
5843     },
5844
5845     relayEvents : function(o, events){
5846         var createHandler = function(ename){
5847             return function(){
5848                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5849             };
5850         };
5851         for(var i = 0, len = events.length; i < len; i++){
5852             var ename = events[i];
5853             if(!this.events[ename]){ this.events[ename] = true; };
5854             o.on(ename, createHandler(ename), this);
5855         }
5856     },
5857
5858     /**
5859      * Used to define events on this Observable
5860      * @param {Object} object The object with the events defined
5861      */
5862     addEvents : function(o){
5863         if(!this.events){
5864             this.events = {};
5865         }
5866         Roo.applyIf(this.events, o);
5867     },
5868
5869     /**
5870      * Checks to see if this object has any listeners for a specified event
5871      * @param {String} eventName The name of the event to check for
5872      * @return {Boolean} True if the event is being listened for, else false
5873      */
5874     hasListener : function(eventName){
5875         var e = this.events[eventName];
5876         return typeof e == "object" && e.listeners.length > 0;
5877     }
5878 };
5879 /**
5880  * Appends an event handler to this element (shorthand for addListener)
5881  * @param {String}   eventName     The type of event to listen for
5882  * @param {Function} handler        The method the event invokes
5883  * @param {Object}   scope (optional) The scope in which to execute the handler
5884  * function. The handler function's "this" context.
5885  * @param {Object}   options  (optional)
5886  * @method
5887  */
5888 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5889 /**
5890  * Removes a listener (shorthand for removeListener)
5891  * @param {String}   eventName     The type of event to listen for
5892  * @param {Function} handler        The handler to remove
5893  * @param {Object}   scope  (optional) The scope (this object) for the handler
5894  * @method
5895  */
5896 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5897
5898 /**
5899  * Starts capture on the specified Observable. All events will be passed
5900  * to the supplied function with the event name + standard signature of the event
5901  * <b>before</b> the event is fired. If the supplied function returns false,
5902  * the event will not fire.
5903  * @param {Observable} o The Observable to capture
5904  * @param {Function} fn The function to call
5905  * @param {Object} scope (optional) The scope (this object) for the fn
5906  * @static
5907  */
5908 Roo.util.Observable.capture = function(o, fn, scope){
5909     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5910 };
5911
5912 /**
5913  * Removes <b>all</b> added captures from the Observable.
5914  * @param {Observable} o The Observable to release
5915  * @static
5916  */
5917 Roo.util.Observable.releaseCapture = function(o){
5918     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5919 };
5920
5921 (function(){
5922
5923     var createBuffered = function(h, o, scope){
5924         var task = new Roo.util.DelayedTask();
5925         return function(){
5926             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5927         };
5928     };
5929
5930     var createSingle = function(h, e, fn, scope){
5931         return function(){
5932             e.removeListener(fn, scope);
5933             return h.apply(scope, arguments);
5934         };
5935     };
5936
5937     var createDelayed = function(h, o, scope){
5938         return function(){
5939             var args = Array.prototype.slice.call(arguments, 0);
5940             setTimeout(function(){
5941                 h.apply(scope, args);
5942             }, o.delay || 10);
5943         };
5944     };
5945
5946     Roo.util.Event = function(obj, name){
5947         this.name = name;
5948         this.obj = obj;
5949         this.listeners = [];
5950     };
5951
5952     Roo.util.Event.prototype = {
5953         addListener : function(fn, scope, options){
5954             var o = options || {};
5955             scope = scope || this.obj;
5956             if(!this.isListening(fn, scope)){
5957                 var l = {fn: fn, scope: scope, options: o};
5958                 var h = fn;
5959                 if(o.delay){
5960                     h = createDelayed(h, o, scope);
5961                 }
5962                 if(o.single){
5963                     h = createSingle(h, this, fn, scope);
5964                 }
5965                 if(o.buffer){
5966                     h = createBuffered(h, o, scope);
5967                 }
5968                 l.fireFn = h;
5969                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5970                     this.listeners.push(l);
5971                 }else{
5972                     this.listeners = this.listeners.slice(0);
5973                     this.listeners.push(l);
5974                 }
5975             }
5976         },
5977
5978         findListener : function(fn, scope){
5979             scope = scope || this.obj;
5980             var ls = this.listeners;
5981             for(var i = 0, len = ls.length; i < len; i++){
5982                 var l = ls[i];
5983                 if(l.fn == fn && l.scope == scope){
5984                     return i;
5985                 }
5986             }
5987             return -1;
5988         },
5989
5990         isListening : function(fn, scope){
5991             return this.findListener(fn, scope) != -1;
5992         },
5993
5994         removeListener : function(fn, scope){
5995             var index;
5996             if((index = this.findListener(fn, scope)) != -1){
5997                 if(!this.firing){
5998                     this.listeners.splice(index, 1);
5999                 }else{
6000                     this.listeners = this.listeners.slice(0);
6001                     this.listeners.splice(index, 1);
6002                 }
6003                 return true;
6004             }
6005             return false;
6006         },
6007
6008         clearListeners : function(){
6009             this.listeners = [];
6010         },
6011
6012         fire : function(){
6013             var ls = this.listeners, scope, len = ls.length;
6014             if(len > 0){
6015                 this.firing = true;
6016                 var args = Array.prototype.slice.call(arguments, 0);
6017                 for(var i = 0; i < len; i++){
6018                     var l = ls[i];
6019                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6020                         this.firing = false;
6021                         return false;
6022                     }
6023                 }
6024                 this.firing = false;
6025             }
6026             return true;
6027         }
6028     };
6029 })();/*
6030  * Based on:
6031  * Ext JS Library 1.1.1
6032  * Copyright(c) 2006-2007, Ext JS, LLC.
6033  *
6034  * Originally Released Under LGPL - original licence link has changed is not relivant.
6035  *
6036  * Fork - LGPL
6037  * <script type="text/javascript">
6038  */
6039
6040 /**
6041  * @class Roo.EventManager
6042  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6043  * several useful events directly.
6044  * See {@link Roo.EventObject} for more details on normalized event objects.
6045  * @singleton
6046  */
6047 Roo.EventManager = function(){
6048     var docReadyEvent, docReadyProcId, docReadyState = false;
6049     var resizeEvent, resizeTask, textEvent, textSize;
6050     var E = Roo.lib.Event;
6051     var D = Roo.lib.Dom;
6052
6053
6054     var fireDocReady = function(){
6055         if(!docReadyState){
6056             docReadyState = true;
6057             Roo.isReady = true;
6058             if(docReadyProcId){
6059                 clearInterval(docReadyProcId);
6060             }
6061             if(Roo.isGecko || Roo.isOpera) {
6062                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6063             }
6064             if(Roo.isIE){
6065                 var defer = document.getElementById("ie-deferred-loader");
6066                 if(defer){
6067                     defer.onreadystatechange = null;
6068                     defer.parentNode.removeChild(defer);
6069                 }
6070             }
6071             if(docReadyEvent){
6072                 docReadyEvent.fire();
6073                 docReadyEvent.clearListeners();
6074             }
6075         }
6076     };
6077     
6078     var initDocReady = function(){
6079         docReadyEvent = new Roo.util.Event();
6080         if(Roo.isGecko || Roo.isOpera) {
6081             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6082         }else if(Roo.isIE){
6083             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6084             var defer = document.getElementById("ie-deferred-loader");
6085             defer.onreadystatechange = function(){
6086                 if(this.readyState == "complete"){
6087                     fireDocReady();
6088                 }
6089             };
6090         }else if(Roo.isSafari){ 
6091             docReadyProcId = setInterval(function(){
6092                 var rs = document.readyState;
6093                 if(rs == "complete") {
6094                     fireDocReady();     
6095                  }
6096             }, 10);
6097         }
6098         // no matter what, make sure it fires on load
6099         E.on(window, "load", fireDocReady);
6100     };
6101
6102     var createBuffered = function(h, o){
6103         var task = new Roo.util.DelayedTask(h);
6104         return function(e){
6105             // create new event object impl so new events don't wipe out properties
6106             e = new Roo.EventObjectImpl(e);
6107             task.delay(o.buffer, h, null, [e]);
6108         };
6109     };
6110
6111     var createSingle = function(h, el, ename, fn){
6112         return function(e){
6113             Roo.EventManager.removeListener(el, ename, fn);
6114             h(e);
6115         };
6116     };
6117
6118     var createDelayed = function(h, o){
6119         return function(e){
6120             // create new event object impl so new events don't wipe out properties
6121             e = new Roo.EventObjectImpl(e);
6122             setTimeout(function(){
6123                 h(e);
6124             }, o.delay || 10);
6125         };
6126     };
6127
6128     var listen = function(element, ename, opt, fn, scope){
6129         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6130         fn = fn || o.fn; scope = scope || o.scope;
6131         var el = Roo.getDom(element);
6132         if(!el){
6133             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6134         }
6135         var h = function(e){
6136             e = Roo.EventObject.setEvent(e);
6137             var t;
6138             if(o.delegate){
6139                 t = e.getTarget(o.delegate, el);
6140                 if(!t){
6141                     return;
6142                 }
6143             }else{
6144                 t = e.target;
6145             }
6146             if(o.stopEvent === true){
6147                 e.stopEvent();
6148             }
6149             if(o.preventDefault === true){
6150                e.preventDefault();
6151             }
6152             if(o.stopPropagation === true){
6153                 e.stopPropagation();
6154             }
6155
6156             if(o.normalized === false){
6157                 e = e.browserEvent;
6158             }
6159
6160             fn.call(scope || el, e, t, o);
6161         };
6162         if(o.delay){
6163             h = createDelayed(h, o);
6164         }
6165         if(o.single){
6166             h = createSingle(h, el, ename, fn);
6167         }
6168         if(o.buffer){
6169             h = createBuffered(h, o);
6170         }
6171         fn._handlers = fn._handlers || [];
6172         fn._handlers.push([Roo.id(el), ename, h]);
6173
6174         E.on(el, ename, h);
6175         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6176             el.addEventListener("DOMMouseScroll", h, false);
6177             E.on(window, 'unload', function(){
6178                 el.removeEventListener("DOMMouseScroll", h, false);
6179             });
6180         }
6181         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6182             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6183         }
6184         return h;
6185     };
6186
6187     var stopListening = function(el, ename, fn){
6188         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6189         if(hds){
6190             for(var i = 0, len = hds.length; i < len; i++){
6191                 var h = hds[i];
6192                 if(h[0] == id && h[1] == ename){
6193                     hd = h[2];
6194                     hds.splice(i, 1);
6195                     break;
6196                 }
6197             }
6198         }
6199         E.un(el, ename, hd);
6200         el = Roo.getDom(el);
6201         if(ename == "mousewheel" && el.addEventListener){
6202             el.removeEventListener("DOMMouseScroll", hd, false);
6203         }
6204         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6205             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6206         }
6207     };
6208
6209     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6210     
6211     var pub = {
6212         
6213         
6214         /** 
6215          * Fix for doc tools
6216          * @scope Roo.EventManager
6217          */
6218         
6219         
6220         /** 
6221          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6222          * object with a Roo.EventObject
6223          * @param {Function} fn        The method the event invokes
6224          * @param {Object}   scope    An object that becomes the scope of the handler
6225          * @param {boolean}  override If true, the obj passed in becomes
6226          *                             the execution scope of the listener
6227          * @return {Function} The wrapped function
6228          * @deprecated
6229          */
6230         wrap : function(fn, scope, override){
6231             return function(e){
6232                 Roo.EventObject.setEvent(e);
6233                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6234             };
6235         },
6236         
6237         /**
6238      * Appends an event handler to an element (shorthand for addListener)
6239      * @param {String/HTMLElement}   element        The html element or id to assign the
6240      * @param {String}   eventName The type of event to listen for
6241      * @param {Function} handler The method the event invokes
6242      * @param {Object}   scope (optional) The scope in which to execute the handler
6243      * function. The handler function's "this" context.
6244      * @param {Object}   options (optional) An object containing handler configuration
6245      * properties. This may contain any of the following properties:<ul>
6246      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6247      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6248      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6249      * <li>preventDefault {Boolean} True to prevent the default action</li>
6250      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6251      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6252      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6253      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6254      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6255      * by the specified number of milliseconds. If the event fires again within that time, the original
6256      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6257      * </ul><br>
6258      * <p>
6259      * <b>Combining Options</b><br>
6260      * Using the options argument, it is possible to combine different types of listeners:<br>
6261      * <br>
6262      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6263      * Code:<pre><code>
6264 el.on('click', this.onClick, this, {
6265     single: true,
6266     delay: 100,
6267     stopEvent : true,
6268     forumId: 4
6269 });</code></pre>
6270      * <p>
6271      * <b>Attaching multiple handlers in 1 call</b><br>
6272       * The method also allows for a single argument to be passed which is a config object containing properties
6273      * which specify multiple handlers.
6274      * <p>
6275      * Code:<pre><code>
6276 el.on({
6277     'click' : {
6278         fn: this.onClick
6279         scope: this,
6280         delay: 100
6281     },
6282     'mouseover' : {
6283         fn: this.onMouseOver
6284         scope: this
6285     },
6286     'mouseout' : {
6287         fn: this.onMouseOut
6288         scope: this
6289     }
6290 });</code></pre>
6291      * <p>
6292      * Or a shorthand syntax:<br>
6293      * Code:<pre><code>
6294 el.on({
6295     'click' : this.onClick,
6296     'mouseover' : this.onMouseOver,
6297     'mouseout' : this.onMouseOut
6298     scope: this
6299 });</code></pre>
6300      */
6301         addListener : function(element, eventName, fn, scope, options){
6302             if(typeof eventName == "object"){
6303                 var o = eventName;
6304                 for(var e in o){
6305                     if(propRe.test(e)){
6306                         continue;
6307                     }
6308                     if(typeof o[e] == "function"){
6309                         // shared options
6310                         listen(element, e, o, o[e], o.scope);
6311                     }else{
6312                         // individual options
6313                         listen(element, e, o[e]);
6314                     }
6315                 }
6316                 return;
6317             }
6318             return listen(element, eventName, options, fn, scope);
6319         },
6320         
6321         /**
6322          * Removes an event handler
6323          *
6324          * @param {String/HTMLElement}   element        The id or html element to remove the 
6325          *                             event from
6326          * @param {String}   eventName     The type of event
6327          * @param {Function} fn
6328          * @return {Boolean} True if a listener was actually removed
6329          */
6330         removeListener : function(element, eventName, fn){
6331             return stopListening(element, eventName, fn);
6332         },
6333         
6334         /**
6335          * Fires when the document is ready (before onload and before images are loaded). Can be 
6336          * accessed shorthanded Roo.onReady().
6337          * @param {Function} fn        The method the event invokes
6338          * @param {Object}   scope    An  object that becomes the scope of the handler
6339          * @param {boolean}  options
6340          */
6341         onDocumentReady : function(fn, scope, options){
6342             if(docReadyState){ // if it already fired
6343                 docReadyEvent.addListener(fn, scope, options);
6344                 docReadyEvent.fire();
6345                 docReadyEvent.clearListeners();
6346                 return;
6347             }
6348             if(!docReadyEvent){
6349                 initDocReady();
6350             }
6351             docReadyEvent.addListener(fn, scope, options);
6352         },
6353         
6354         /**
6355          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6356          * @param {Function} fn        The method the event invokes
6357          * @param {Object}   scope    An object that becomes the scope of the handler
6358          * @param {boolean}  options
6359          */
6360         onWindowResize : function(fn, scope, options){
6361             if(!resizeEvent){
6362                 resizeEvent = new Roo.util.Event();
6363                 resizeTask = new Roo.util.DelayedTask(function(){
6364                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6365                 });
6366                 E.on(window, "resize", function(){
6367                     if(Roo.isIE){
6368                         resizeTask.delay(50);
6369                     }else{
6370                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6371                     }
6372                 });
6373             }
6374             resizeEvent.addListener(fn, scope, options);
6375         },
6376
6377         /**
6378          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6379          * @param {Function} fn        The method the event invokes
6380          * @param {Object}   scope    An object that becomes the scope of the handler
6381          * @param {boolean}  options
6382          */
6383         onTextResize : function(fn, scope, options){
6384             if(!textEvent){
6385                 textEvent = new Roo.util.Event();
6386                 var textEl = new Roo.Element(document.createElement('div'));
6387                 textEl.dom.className = 'x-text-resize';
6388                 textEl.dom.innerHTML = 'X';
6389                 textEl.appendTo(document.body);
6390                 textSize = textEl.dom.offsetHeight;
6391                 setInterval(function(){
6392                     if(textEl.dom.offsetHeight != textSize){
6393                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6394                     }
6395                 }, this.textResizeInterval);
6396             }
6397             textEvent.addListener(fn, scope, options);
6398         },
6399
6400         /**
6401          * Removes the passed window resize listener.
6402          * @param {Function} fn        The method the event invokes
6403          * @param {Object}   scope    The scope of handler
6404          */
6405         removeResizeListener : function(fn, scope){
6406             if(resizeEvent){
6407                 resizeEvent.removeListener(fn, scope);
6408             }
6409         },
6410
6411         // private
6412         fireResize : function(){
6413             if(resizeEvent){
6414                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6415             }   
6416         },
6417         /**
6418          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6419          */
6420         ieDeferSrc : false,
6421         /**
6422          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6423          */
6424         textResizeInterval : 50
6425     };
6426     
6427     /**
6428      * Fix for doc tools
6429      * @scopeAlias pub=Roo.EventManager
6430      */
6431     
6432      /**
6433      * Appends an event handler to an element (shorthand for addListener)
6434      * @param {String/HTMLElement}   element        The html element or id to assign the
6435      * @param {String}   eventName The type of event to listen for
6436      * @param {Function} handler The method the event invokes
6437      * @param {Object}   scope (optional) The scope in which to execute the handler
6438      * function. The handler function's "this" context.
6439      * @param {Object}   options (optional) An object containing handler configuration
6440      * properties. This may contain any of the following properties:<ul>
6441      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6442      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6443      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6444      * <li>preventDefault {Boolean} True to prevent the default action</li>
6445      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6446      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6447      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6448      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6449      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6450      * by the specified number of milliseconds. If the event fires again within that time, the original
6451      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6452      * </ul><br>
6453      * <p>
6454      * <b>Combining Options</b><br>
6455      * Using the options argument, it is possible to combine different types of listeners:<br>
6456      * <br>
6457      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6458      * Code:<pre><code>
6459 el.on('click', this.onClick, this, {
6460     single: true,
6461     delay: 100,
6462     stopEvent : true,
6463     forumId: 4
6464 });</code></pre>
6465      * <p>
6466      * <b>Attaching multiple handlers in 1 call</b><br>
6467       * The method also allows for a single argument to be passed which is a config object containing properties
6468      * which specify multiple handlers.
6469      * <p>
6470      * Code:<pre><code>
6471 el.on({
6472     'click' : {
6473         fn: this.onClick
6474         scope: this,
6475         delay: 100
6476     },
6477     'mouseover' : {
6478         fn: this.onMouseOver
6479         scope: this
6480     },
6481     'mouseout' : {
6482         fn: this.onMouseOut
6483         scope: this
6484     }
6485 });</code></pre>
6486      * <p>
6487      * Or a shorthand syntax:<br>
6488      * Code:<pre><code>
6489 el.on({
6490     'click' : this.onClick,
6491     'mouseover' : this.onMouseOver,
6492     'mouseout' : this.onMouseOut
6493     scope: this
6494 });</code></pre>
6495      */
6496     pub.on = pub.addListener;
6497     pub.un = pub.removeListener;
6498
6499     pub.stoppedMouseDownEvent = new Roo.util.Event();
6500     return pub;
6501 }();
6502 /**
6503   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6504   * @param {Function} fn        The method the event invokes
6505   * @param {Object}   scope    An  object that becomes the scope of the handler
6506   * @param {boolean}  override If true, the obj passed in becomes
6507   *                             the execution scope of the listener
6508   * @member Roo
6509   * @method onReady
6510  */
6511 Roo.onReady = Roo.EventManager.onDocumentReady;
6512
6513 Roo.onReady(function(){
6514     var bd = Roo.get(document.body);
6515     if(!bd){ return; }
6516
6517     var cls = [
6518             Roo.isIE ? "roo-ie"
6519             : Roo.isGecko ? "roo-gecko"
6520             : Roo.isOpera ? "roo-opera"
6521             : Roo.isSafari ? "roo-safari" : ""];
6522
6523     if(Roo.isMac){
6524         cls.push("roo-mac");
6525     }
6526     if(Roo.isLinux){
6527         cls.push("roo-linux");
6528     }
6529     if(Roo.isBorderBox){
6530         cls.push('roo-border-box');
6531     }
6532     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6533         var p = bd.dom.parentNode;
6534         if(p){
6535             p.className += ' roo-strict';
6536         }
6537     }
6538     bd.addClass(cls.join(' '));
6539 });
6540
6541 /**
6542  * @class Roo.EventObject
6543  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6544  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6545  * Example:
6546  * <pre><code>
6547  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6548     e.preventDefault();
6549     var target = e.getTarget();
6550     ...
6551  }
6552  var myDiv = Roo.get("myDiv");
6553  myDiv.on("click", handleClick);
6554  //or
6555  Roo.EventManager.on("myDiv", 'click', handleClick);
6556  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6557  </code></pre>
6558  * @singleton
6559  */
6560 Roo.EventObject = function(){
6561     
6562     var E = Roo.lib.Event;
6563     
6564     // safari keypress events for special keys return bad keycodes
6565     var safariKeys = {
6566         63234 : 37, // left
6567         63235 : 39, // right
6568         63232 : 38, // up
6569         63233 : 40, // down
6570         63276 : 33, // page up
6571         63277 : 34, // page down
6572         63272 : 46, // delete
6573         63273 : 36, // home
6574         63275 : 35  // end
6575     };
6576
6577     // normalize button clicks
6578     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6579                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6580
6581     Roo.EventObjectImpl = function(e){
6582         if(e){
6583             this.setEvent(e.browserEvent || e);
6584         }
6585     };
6586     Roo.EventObjectImpl.prototype = {
6587         /**
6588          * Used to fix doc tools.
6589          * @scope Roo.EventObject.prototype
6590          */
6591             
6592
6593         
6594         
6595         /** The normal browser event */
6596         browserEvent : null,
6597         /** The button pressed in a mouse event */
6598         button : -1,
6599         /** True if the shift key was down during the event */
6600         shiftKey : false,
6601         /** True if the control key was down during the event */
6602         ctrlKey : false,
6603         /** True if the alt key was down during the event */
6604         altKey : false,
6605
6606         /** Key constant 
6607         * @type Number */
6608         BACKSPACE : 8,
6609         /** Key constant 
6610         * @type Number */
6611         TAB : 9,
6612         /** Key constant 
6613         * @type Number */
6614         RETURN : 13,
6615         /** Key constant 
6616         * @type Number */
6617         ENTER : 13,
6618         /** Key constant 
6619         * @type Number */
6620         SHIFT : 16,
6621         /** Key constant 
6622         * @type Number */
6623         CONTROL : 17,
6624         /** Key constant 
6625         * @type Number */
6626         ESC : 27,
6627         /** Key constant 
6628         * @type Number */
6629         SPACE : 32,
6630         /** Key constant 
6631         * @type Number */
6632         PAGEUP : 33,
6633         /** Key constant 
6634         * @type Number */
6635         PAGEDOWN : 34,
6636         /** Key constant 
6637         * @type Number */
6638         END : 35,
6639         /** Key constant 
6640         * @type Number */
6641         HOME : 36,
6642         /** Key constant 
6643         * @type Number */
6644         LEFT : 37,
6645         /** Key constant 
6646         * @type Number */
6647         UP : 38,
6648         /** Key constant 
6649         * @type Number */
6650         RIGHT : 39,
6651         /** Key constant 
6652         * @type Number */
6653         DOWN : 40,
6654         /** Key constant 
6655         * @type Number */
6656         DELETE : 46,
6657         /** Key constant 
6658         * @type Number */
6659         F5 : 116,
6660
6661            /** @private */
6662         setEvent : function(e){
6663             if(e == this || (e && e.browserEvent)){ // already wrapped
6664                 return e;
6665             }
6666             this.browserEvent = e;
6667             if(e){
6668                 // normalize buttons
6669                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6670                 if(e.type == 'click' && this.button == -1){
6671                     this.button = 0;
6672                 }
6673                 this.type = e.type;
6674                 this.shiftKey = e.shiftKey;
6675                 // mac metaKey behaves like ctrlKey
6676                 this.ctrlKey = e.ctrlKey || e.metaKey;
6677                 this.altKey = e.altKey;
6678                 // in getKey these will be normalized for the mac
6679                 this.keyCode = e.keyCode;
6680                 // keyup warnings on firefox.
6681                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6682                 // cache the target for the delayed and or buffered events
6683                 this.target = E.getTarget(e);
6684                 // same for XY
6685                 this.xy = E.getXY(e);
6686             }else{
6687                 this.button = -1;
6688                 this.shiftKey = false;
6689                 this.ctrlKey = false;
6690                 this.altKey = false;
6691                 this.keyCode = 0;
6692                 this.charCode =0;
6693                 this.target = null;
6694                 this.xy = [0, 0];
6695             }
6696             return this;
6697         },
6698
6699         /**
6700          * Stop the event (preventDefault and stopPropagation)
6701          */
6702         stopEvent : function(){
6703             if(this.browserEvent){
6704                 if(this.browserEvent.type == 'mousedown'){
6705                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6706                 }
6707                 E.stopEvent(this.browserEvent);
6708             }
6709         },
6710
6711         /**
6712          * Prevents the browsers default handling of the event.
6713          */
6714         preventDefault : function(){
6715             if(this.browserEvent){
6716                 E.preventDefault(this.browserEvent);
6717             }
6718         },
6719
6720         /** @private */
6721         isNavKeyPress : function(){
6722             var k = this.keyCode;
6723             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6724             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6725         },
6726
6727         isSpecialKey : function(){
6728             var k = this.keyCode;
6729             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6730             (k == 16) || (k == 17) ||
6731             (k >= 18 && k <= 20) ||
6732             (k >= 33 && k <= 35) ||
6733             (k >= 36 && k <= 39) ||
6734             (k >= 44 && k <= 45);
6735         },
6736         /**
6737          * Cancels bubbling of the event.
6738          */
6739         stopPropagation : function(){
6740             if(this.browserEvent){
6741                 if(this.type == 'mousedown'){
6742                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6743                 }
6744                 E.stopPropagation(this.browserEvent);
6745             }
6746         },
6747
6748         /**
6749          * Gets the key code for the event.
6750          * @return {Number}
6751          */
6752         getCharCode : function(){
6753             return this.charCode || this.keyCode;
6754         },
6755
6756         /**
6757          * Returns a normalized keyCode for the event.
6758          * @return {Number} The key code
6759          */
6760         getKey : function(){
6761             var k = this.keyCode || this.charCode;
6762             return Roo.isSafari ? (safariKeys[k] || k) : k;
6763         },
6764
6765         /**
6766          * Gets the x coordinate of the event.
6767          * @return {Number}
6768          */
6769         getPageX : function(){
6770             return this.xy[0];
6771         },
6772
6773         /**
6774          * Gets the y coordinate of the event.
6775          * @return {Number}
6776          */
6777         getPageY : function(){
6778             return this.xy[1];
6779         },
6780
6781         /**
6782          * Gets the time of the event.
6783          * @return {Number}
6784          */
6785         getTime : function(){
6786             if(this.browserEvent){
6787                 return E.getTime(this.browserEvent);
6788             }
6789             return null;
6790         },
6791
6792         /**
6793          * Gets the page coordinates of the event.
6794          * @return {Array} The xy values like [x, y]
6795          */
6796         getXY : function(){
6797             return this.xy;
6798         },
6799
6800         /**
6801          * Gets the target for the event.
6802          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6803          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6804                 search as a number or element (defaults to 10 || document.body)
6805          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6806          * @return {HTMLelement}
6807          */
6808         getTarget : function(selector, maxDepth, returnEl){
6809             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6810         },
6811         /**
6812          * Gets the related target.
6813          * @return {HTMLElement}
6814          */
6815         getRelatedTarget : function(){
6816             if(this.browserEvent){
6817                 return E.getRelatedTarget(this.browserEvent);
6818             }
6819             return null;
6820         },
6821
6822         /**
6823          * Normalizes mouse wheel delta across browsers
6824          * @return {Number} The delta
6825          */
6826         getWheelDelta : function(){
6827             var e = this.browserEvent;
6828             var delta = 0;
6829             if(e.wheelDelta){ /* IE/Opera. */
6830                 delta = e.wheelDelta/120;
6831             }else if(e.detail){ /* Mozilla case. */
6832                 delta = -e.detail/3;
6833             }
6834             return delta;
6835         },
6836
6837         /**
6838          * Returns true if the control, meta, shift or alt key was pressed during this event.
6839          * @return {Boolean}
6840          */
6841         hasModifier : function(){
6842             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6843         },
6844
6845         /**
6846          * Returns true if the target of this event equals el or is a child of el
6847          * @param {String/HTMLElement/Element} el
6848          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6849          * @return {Boolean}
6850          */
6851         within : function(el, related){
6852             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6853             return t && Roo.fly(el).contains(t);
6854         },
6855
6856         getPoint : function(){
6857             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6858         }
6859     };
6860
6861     return new Roo.EventObjectImpl();
6862 }();
6863             
6864     /*
6865  * Based on:
6866  * Ext JS Library 1.1.1
6867  * Copyright(c) 2006-2007, Ext JS, LLC.
6868  *
6869  * Originally Released Under LGPL - original licence link has changed is not relivant.
6870  *
6871  * Fork - LGPL
6872  * <script type="text/javascript">
6873  */
6874
6875  
6876 // was in Composite Element!??!?!
6877  
6878 (function(){
6879     var D = Roo.lib.Dom;
6880     var E = Roo.lib.Event;
6881     var A = Roo.lib.Anim;
6882
6883     // local style camelizing for speed
6884     var propCache = {};
6885     var camelRe = /(-[a-z])/gi;
6886     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6887     var view = document.defaultView;
6888
6889 /**
6890  * @class Roo.Element
6891  * Represents an Element in the DOM.<br><br>
6892  * Usage:<br>
6893 <pre><code>
6894 var el = Roo.get("my-div");
6895
6896 // or with getEl
6897 var el = getEl("my-div");
6898
6899 // or with a DOM element
6900 var el = Roo.get(myDivElement);
6901 </code></pre>
6902  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6903  * each call instead of constructing a new one.<br><br>
6904  * <b>Animations</b><br />
6905  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6906  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6907 <pre>
6908 Option    Default   Description
6909 --------- --------  ---------------------------------------------
6910 duration  .35       The duration of the animation in seconds
6911 easing    easeOut   The YUI easing method
6912 callback  none      A function to execute when the anim completes
6913 scope     this      The scope (this) of the callback function
6914 </pre>
6915 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6916 * manipulate the animation. Here's an example:
6917 <pre><code>
6918 var el = Roo.get("my-div");
6919
6920 // no animation
6921 el.setWidth(100);
6922
6923 // default animation
6924 el.setWidth(100, true);
6925
6926 // animation with some options set
6927 el.setWidth(100, {
6928     duration: 1,
6929     callback: this.foo,
6930     scope: this
6931 });
6932
6933 // using the "anim" property to get the Anim object
6934 var opt = {
6935     duration: 1,
6936     callback: this.foo,
6937     scope: this
6938 };
6939 el.setWidth(100, opt);
6940 ...
6941 if(opt.anim.isAnimated()){
6942     opt.anim.stop();
6943 }
6944 </code></pre>
6945 * <b> Composite (Collections of) Elements</b><br />
6946  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6947  * @constructor Create a new Element directly.
6948  * @param {String/HTMLElement} element
6949  * @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).
6950  */
6951     Roo.Element = function(element, forceNew){
6952         var dom = typeof element == "string" ?
6953                 document.getElementById(element) : element;
6954         if(!dom){ // invalid id/element
6955             return null;
6956         }
6957         var id = dom.id;
6958         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6959             return Roo.Element.cache[id];
6960         }
6961
6962         /**
6963          * The DOM element
6964          * @type HTMLElement
6965          */
6966         this.dom = dom;
6967
6968         /**
6969          * The DOM element ID
6970          * @type String
6971          */
6972         this.id = id || Roo.id(dom);
6973     };
6974
6975     var El = Roo.Element;
6976
6977     El.prototype = {
6978         /**
6979          * The element's default display mode  (defaults to "")
6980          * @type String
6981          */
6982         originalDisplay : "",
6983
6984         visibilityMode : 1,
6985         /**
6986          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6987          * @type String
6988          */
6989         defaultUnit : "px",
6990         /**
6991          * Sets the element's visibility mode. When setVisible() is called it
6992          * will use this to determine whether to set the visibility or the display property.
6993          * @param visMode Element.VISIBILITY or Element.DISPLAY
6994          * @return {Roo.Element} this
6995          */
6996         setVisibilityMode : function(visMode){
6997             this.visibilityMode = visMode;
6998             return this;
6999         },
7000         /**
7001          * Convenience method for setVisibilityMode(Element.DISPLAY)
7002          * @param {String} display (optional) What to set display to when visible
7003          * @return {Roo.Element} this
7004          */
7005         enableDisplayMode : function(display){
7006             this.setVisibilityMode(El.DISPLAY);
7007             if(typeof display != "undefined") this.originalDisplay = display;
7008             return this;
7009         },
7010
7011         /**
7012          * 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)
7013          * @param {String} selector The simple selector to test
7014          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7015                 search as a number or element (defaults to 10 || document.body)
7016          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7017          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7018          */
7019         findParent : function(simpleSelector, maxDepth, returnEl){
7020             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7021             maxDepth = maxDepth || 50;
7022             if(typeof maxDepth != "number"){
7023                 stopEl = Roo.getDom(maxDepth);
7024                 maxDepth = 10;
7025             }
7026             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7027                 if(dq.is(p, simpleSelector)){
7028                     return returnEl ? Roo.get(p) : p;
7029                 }
7030                 depth++;
7031                 p = p.parentNode;
7032             }
7033             return null;
7034         },
7035
7036
7037         /**
7038          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7039          * @param {String} selector The simple selector to test
7040          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7041                 search as a number or element (defaults to 10 || document.body)
7042          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7043          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7044          */
7045         findParentNode : function(simpleSelector, maxDepth, returnEl){
7046             var p = Roo.fly(this.dom.parentNode, '_internal');
7047             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7048         },
7049
7050         /**
7051          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7052          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7053          * @param {String} selector The simple selector to test
7054          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7055                 search as a number or element (defaults to 10 || document.body)
7056          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7057          */
7058         up : function(simpleSelector, maxDepth){
7059             return this.findParentNode(simpleSelector, maxDepth, true);
7060         },
7061
7062
7063
7064         /**
7065          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7066          * @param {String} selector The simple selector to test
7067          * @return {Boolean} True if this element matches the selector, else false
7068          */
7069         is : function(simpleSelector){
7070             return Roo.DomQuery.is(this.dom, simpleSelector);
7071         },
7072
7073         /**
7074          * Perform animation on this element.
7075          * @param {Object} args The YUI animation control args
7076          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7077          * @param {Function} onComplete (optional) Function to call when animation completes
7078          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7079          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7080          * @return {Roo.Element} this
7081          */
7082         animate : function(args, duration, onComplete, easing, animType){
7083             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7084             return this;
7085         },
7086
7087         /*
7088          * @private Internal animation call
7089          */
7090         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7091             animType = animType || 'run';
7092             opt = opt || {};
7093             var anim = Roo.lib.Anim[animType](
7094                 this.dom, args,
7095                 (opt.duration || defaultDur) || .35,
7096                 (opt.easing || defaultEase) || 'easeOut',
7097                 function(){
7098                     Roo.callback(cb, this);
7099                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7100                 },
7101                 this
7102             );
7103             opt.anim = anim;
7104             return anim;
7105         },
7106
7107         // private legacy anim prep
7108         preanim : function(a, i){
7109             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7110         },
7111
7112         /**
7113          * Removes worthless text nodes
7114          * @param {Boolean} forceReclean (optional) By default the element
7115          * keeps track if it has been cleaned already so
7116          * you can call this over and over. However, if you update the element and
7117          * need to force a reclean, you can pass true.
7118          */
7119         clean : function(forceReclean){
7120             if(this.isCleaned && forceReclean !== true){
7121                 return this;
7122             }
7123             var ns = /\S/;
7124             var d = this.dom, n = d.firstChild, ni = -1;
7125             while(n){
7126                 var nx = n.nextSibling;
7127                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7128                     d.removeChild(n);
7129                 }else{
7130                     n.nodeIndex = ++ni;
7131                 }
7132                 n = nx;
7133             }
7134             this.isCleaned = true;
7135             return this;
7136         },
7137
7138         // private
7139         calcOffsetsTo : function(el){
7140             el = Roo.get(el);
7141             var d = el.dom;
7142             var restorePos = false;
7143             if(el.getStyle('position') == 'static'){
7144                 el.position('relative');
7145                 restorePos = true;
7146             }
7147             var x = 0, y =0;
7148             var op = this.dom;
7149             while(op && op != d && op.tagName != 'HTML'){
7150                 x+= op.offsetLeft;
7151                 y+= op.offsetTop;
7152                 op = op.offsetParent;
7153             }
7154             if(restorePos){
7155                 el.position('static');
7156             }
7157             return [x, y];
7158         },
7159
7160         /**
7161          * Scrolls this element into view within the passed container.
7162          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7163          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7164          * @return {Roo.Element} this
7165          */
7166         scrollIntoView : function(container, hscroll){
7167             var c = Roo.getDom(container) || document.body;
7168             var el = this.dom;
7169
7170             var o = this.calcOffsetsTo(c),
7171                 l = o[0],
7172                 t = o[1],
7173                 b = t+el.offsetHeight,
7174                 r = l+el.offsetWidth;
7175
7176             var ch = c.clientHeight;
7177             var ct = parseInt(c.scrollTop, 10);
7178             var cl = parseInt(c.scrollLeft, 10);
7179             var cb = ct + ch;
7180             var cr = cl + c.clientWidth;
7181
7182             if(t < ct){
7183                 c.scrollTop = t;
7184             }else if(b > cb){
7185                 c.scrollTop = b-ch;
7186             }
7187
7188             if(hscroll !== false){
7189                 if(l < cl){
7190                     c.scrollLeft = l;
7191                 }else if(r > cr){
7192                     c.scrollLeft = r-c.clientWidth;
7193                 }
7194             }
7195             return this;
7196         },
7197
7198         // private
7199         scrollChildIntoView : function(child, hscroll){
7200             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7201         },
7202
7203         /**
7204          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7205          * the new height may not be available immediately.
7206          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7207          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7208          * @param {Function} onComplete (optional) Function to call when animation completes
7209          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7210          * @return {Roo.Element} this
7211          */
7212         autoHeight : function(animate, duration, onComplete, easing){
7213             var oldHeight = this.getHeight();
7214             this.clip();
7215             this.setHeight(1); // force clipping
7216             setTimeout(function(){
7217                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7218                 if(!animate){
7219                     this.setHeight(height);
7220                     this.unclip();
7221                     if(typeof onComplete == "function"){
7222                         onComplete();
7223                     }
7224                 }else{
7225                     this.setHeight(oldHeight); // restore original height
7226                     this.setHeight(height, animate, duration, function(){
7227                         this.unclip();
7228                         if(typeof onComplete == "function") onComplete();
7229                     }.createDelegate(this), easing);
7230                 }
7231             }.createDelegate(this), 0);
7232             return this;
7233         },
7234
7235         /**
7236          * Returns true if this element is an ancestor of the passed element
7237          * @param {HTMLElement/String} el The element to check
7238          * @return {Boolean} True if this element is an ancestor of el, else false
7239          */
7240         contains : function(el){
7241             if(!el){return false;}
7242             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7243         },
7244
7245         /**
7246          * Checks whether the element is currently visible using both visibility and display properties.
7247          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7248          * @return {Boolean} True if the element is currently visible, else false
7249          */
7250         isVisible : function(deep) {
7251             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7252             if(deep !== true || !vis){
7253                 return vis;
7254             }
7255             var p = this.dom.parentNode;
7256             while(p && p.tagName.toLowerCase() != "body"){
7257                 if(!Roo.fly(p, '_isVisible').isVisible()){
7258                     return false;
7259                 }
7260                 p = p.parentNode;
7261             }
7262             return true;
7263         },
7264
7265         /**
7266          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7267          * @param {String} selector The CSS selector
7268          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7269          * @return {CompositeElement/CompositeElementLite} The composite element
7270          */
7271         select : function(selector, unique){
7272             return El.select(selector, unique, this.dom);
7273         },
7274
7275         /**
7276          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7277          * @param {String} selector The CSS selector
7278          * @return {Array} An array of the matched nodes
7279          */
7280         query : function(selector, unique){
7281             return Roo.DomQuery.select(selector, this.dom);
7282         },
7283
7284         /**
7285          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7286          * @param {String} selector The CSS selector
7287          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7288          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7289          */
7290         child : function(selector, returnDom){
7291             var n = Roo.DomQuery.selectNode(selector, this.dom);
7292             return returnDom ? n : Roo.get(n);
7293         },
7294
7295         /**
7296          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7297          * @param {String} selector The CSS selector
7298          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7299          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7300          */
7301         down : function(selector, returnDom){
7302             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7303             return returnDom ? n : Roo.get(n);
7304         },
7305
7306         /**
7307          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7308          * @param {String} group The group the DD object is member of
7309          * @param {Object} config The DD config object
7310          * @param {Object} overrides An object containing methods to override/implement on the DD object
7311          * @return {Roo.dd.DD} The DD object
7312          */
7313         initDD : function(group, config, overrides){
7314             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7315             return Roo.apply(dd, overrides);
7316         },
7317
7318         /**
7319          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7320          * @param {String} group The group the DDProxy object is member of
7321          * @param {Object} config The DDProxy config object
7322          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7323          * @return {Roo.dd.DDProxy} The DDProxy object
7324          */
7325         initDDProxy : function(group, config, overrides){
7326             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7327             return Roo.apply(dd, overrides);
7328         },
7329
7330         /**
7331          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7332          * @param {String} group The group the DDTarget object is member of
7333          * @param {Object} config The DDTarget config object
7334          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7335          * @return {Roo.dd.DDTarget} The DDTarget object
7336          */
7337         initDDTarget : function(group, config, overrides){
7338             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7339             return Roo.apply(dd, overrides);
7340         },
7341
7342         /**
7343          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7344          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7345          * @param {Boolean} visible Whether the element is visible
7346          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7347          * @return {Roo.Element} this
7348          */
7349          setVisible : function(visible, animate){
7350             if(!animate || !A){
7351                 if(this.visibilityMode == El.DISPLAY){
7352                     this.setDisplayed(visible);
7353                 }else{
7354                     this.fixDisplay();
7355                     this.dom.style.visibility = visible ? "visible" : "hidden";
7356                 }
7357             }else{
7358                 // closure for composites
7359                 var dom = this.dom;
7360                 var visMode = this.visibilityMode;
7361                 if(visible){
7362                     this.setOpacity(.01);
7363                     this.setVisible(true);
7364                 }
7365                 this.anim({opacity: { to: (visible?1:0) }},
7366                       this.preanim(arguments, 1),
7367                       null, .35, 'easeIn', function(){
7368                          if(!visible){
7369                              if(visMode == El.DISPLAY){
7370                                  dom.style.display = "none";
7371                              }else{
7372                                  dom.style.visibility = "hidden";
7373                              }
7374                              Roo.get(dom).setOpacity(1);
7375                          }
7376                      });
7377             }
7378             return this;
7379         },
7380
7381         /**
7382          * Returns true if display is not "none"
7383          * @return {Boolean}
7384          */
7385         isDisplayed : function() {
7386             return this.getStyle("display") != "none";
7387         },
7388
7389         /**
7390          * Toggles the element's visibility or display, depending on visibility mode.
7391          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7392          * @return {Roo.Element} this
7393          */
7394         toggle : function(animate){
7395             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7396             return this;
7397         },
7398
7399         /**
7400          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7401          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7402          * @return {Roo.Element} this
7403          */
7404         setDisplayed : function(value) {
7405             if(typeof value == "boolean"){
7406                value = value ? this.originalDisplay : "none";
7407             }
7408             this.setStyle("display", value);
7409             return this;
7410         },
7411
7412         /**
7413          * Tries to focus the element. Any exceptions are caught and ignored.
7414          * @return {Roo.Element} this
7415          */
7416         focus : function() {
7417             try{
7418                 this.dom.focus();
7419             }catch(e){}
7420             return this;
7421         },
7422
7423         /**
7424          * Tries to blur the element. Any exceptions are caught and ignored.
7425          * @return {Roo.Element} this
7426          */
7427         blur : function() {
7428             try{
7429                 this.dom.blur();
7430             }catch(e){}
7431             return this;
7432         },
7433
7434         /**
7435          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7436          * @param {String/Array} className The CSS class to add, or an array of classes
7437          * @return {Roo.Element} this
7438          */
7439         addClass : function(className){
7440             if(className instanceof Array){
7441                 for(var i = 0, len = className.length; i < len; i++) {
7442                     this.addClass(className[i]);
7443                 }
7444             }else{
7445                 if(className && !this.hasClass(className)){
7446                     this.dom.className = this.dom.className + " " + className;
7447                 }
7448             }
7449             return this;
7450         },
7451
7452         /**
7453          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7454          * @param {String/Array} className The CSS class to add, or an array of classes
7455          * @return {Roo.Element} this
7456          */
7457         radioClass : function(className){
7458             var siblings = this.dom.parentNode.childNodes;
7459             for(var i = 0; i < siblings.length; i++) {
7460                 var s = siblings[i];
7461                 if(s.nodeType == 1){
7462                     Roo.get(s).removeClass(className);
7463                 }
7464             }
7465             this.addClass(className);
7466             return this;
7467         },
7468
7469         /**
7470          * Removes one or more CSS classes from the element.
7471          * @param {String/Array} className The CSS class to remove, or an array of classes
7472          * @return {Roo.Element} this
7473          */
7474         removeClass : function(className){
7475             if(!className || !this.dom.className){
7476                 return this;
7477             }
7478             if(className instanceof Array){
7479                 for(var i = 0, len = className.length; i < len; i++) {
7480                     this.removeClass(className[i]);
7481                 }
7482             }else{
7483                 if(this.hasClass(className)){
7484                     var re = this.classReCache[className];
7485                     if (!re) {
7486                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7487                        this.classReCache[className] = re;
7488                     }
7489                     this.dom.className =
7490                         this.dom.className.replace(re, " ");
7491                 }
7492             }
7493             return this;
7494         },
7495
7496         // private
7497         classReCache: {},
7498
7499         /**
7500          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7501          * @param {String} className The CSS class to toggle
7502          * @return {Roo.Element} this
7503          */
7504         toggleClass : function(className){
7505             if(this.hasClass(className)){
7506                 this.removeClass(className);
7507             }else{
7508                 this.addClass(className);
7509             }
7510             return this;
7511         },
7512
7513         /**
7514          * Checks if the specified CSS class exists on this element's DOM node.
7515          * @param {String} className The CSS class to check for
7516          * @return {Boolean} True if the class exists, else false
7517          */
7518         hasClass : function(className){
7519             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7520         },
7521
7522         /**
7523          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7524          * @param {String} oldClassName The CSS class to replace
7525          * @param {String} newClassName The replacement CSS class
7526          * @return {Roo.Element} this
7527          */
7528         replaceClass : function(oldClassName, newClassName){
7529             this.removeClass(oldClassName);
7530             this.addClass(newClassName);
7531             return this;
7532         },
7533
7534         /**
7535          * Returns an object with properties matching the styles requested.
7536          * For example, el.getStyles('color', 'font-size', 'width') might return
7537          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7538          * @param {String} style1 A style name
7539          * @param {String} style2 A style name
7540          * @param {String} etc.
7541          * @return {Object} The style object
7542          */
7543         getStyles : function(){
7544             var a = arguments, len = a.length, r = {};
7545             for(var i = 0; i < len; i++){
7546                 r[a[i]] = this.getStyle(a[i]);
7547             }
7548             return r;
7549         },
7550
7551         /**
7552          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7553          * @param {String} property The style property whose value is returned.
7554          * @return {String} The current value of the style property for this element.
7555          */
7556         getStyle : function(){
7557             return view && view.getComputedStyle ?
7558                 function(prop){
7559                     var el = this.dom, v, cs, camel;
7560                     if(prop == 'float'){
7561                         prop = "cssFloat";
7562                     }
7563                     if(el.style && (v = el.style[prop])){
7564                         return v;
7565                     }
7566                     if(cs = view.getComputedStyle(el, "")){
7567                         if(!(camel = propCache[prop])){
7568                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7569                         }
7570                         return cs[camel];
7571                     }
7572                     return null;
7573                 } :
7574                 function(prop){
7575                     var el = this.dom, v, cs, camel;
7576                     if(prop == 'opacity'){
7577                         if(typeof el.style.filter == 'string'){
7578                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7579                             if(m){
7580                                 var fv = parseFloat(m[1]);
7581                                 if(!isNaN(fv)){
7582                                     return fv ? fv / 100 : 0;
7583                                 }
7584                             }
7585                         }
7586                         return 1;
7587                     }else if(prop == 'float'){
7588                         prop = "styleFloat";
7589                     }
7590                     if(!(camel = propCache[prop])){
7591                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7592                     }
7593                     if(v = el.style[camel]){
7594                         return v;
7595                     }
7596                     if(cs = el.currentStyle){
7597                         return cs[camel];
7598                     }
7599                     return null;
7600                 };
7601         }(),
7602
7603         /**
7604          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7605          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7606          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7607          * @return {Roo.Element} this
7608          */
7609         setStyle : function(prop, value){
7610             if(typeof prop == "string"){
7611                 
7612                 if (prop == 'float') {
7613                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7614                     return this;
7615                 }
7616                 
7617                 var camel;
7618                 if(!(camel = propCache[prop])){
7619                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7620                 }
7621                 
7622                 if(camel == 'opacity') {
7623                     this.setOpacity(value);
7624                 }else{
7625                     this.dom.style[camel] = value;
7626                 }
7627             }else{
7628                 for(var style in prop){
7629                     if(typeof prop[style] != "function"){
7630                        this.setStyle(style, prop[style]);
7631                     }
7632                 }
7633             }
7634             return this;
7635         },
7636
7637         /**
7638          * More flexible version of {@link #setStyle} for setting style properties.
7639          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7640          * a function which returns such a specification.
7641          * @return {Roo.Element} this
7642          */
7643         applyStyles : function(style){
7644             Roo.DomHelper.applyStyles(this.dom, style);
7645             return this;
7646         },
7647
7648         /**
7649           * 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).
7650           * @return {Number} The X position of the element
7651           */
7652         getX : function(){
7653             return D.getX(this.dom);
7654         },
7655
7656         /**
7657           * 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).
7658           * @return {Number} The Y position of the element
7659           */
7660         getY : function(){
7661             return D.getY(this.dom);
7662         },
7663
7664         /**
7665           * 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).
7666           * @return {Array} The XY position of the element
7667           */
7668         getXY : function(){
7669             return D.getXY(this.dom);
7670         },
7671
7672         /**
7673          * 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).
7674          * @param {Number} The X position of the element
7675          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7676          * @return {Roo.Element} this
7677          */
7678         setX : function(x, animate){
7679             if(!animate || !A){
7680                 D.setX(this.dom, x);
7681             }else{
7682                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7683             }
7684             return this;
7685         },
7686
7687         /**
7688          * 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).
7689          * @param {Number} The Y position of the element
7690          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7691          * @return {Roo.Element} this
7692          */
7693         setY : function(y, animate){
7694             if(!animate || !A){
7695                 D.setY(this.dom, y);
7696             }else{
7697                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7698             }
7699             return this;
7700         },
7701
7702         /**
7703          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7704          * @param {String} left The left CSS property value
7705          * @return {Roo.Element} this
7706          */
7707         setLeft : function(left){
7708             this.setStyle("left", this.addUnits(left));
7709             return this;
7710         },
7711
7712         /**
7713          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7714          * @param {String} top The top CSS property value
7715          * @return {Roo.Element} this
7716          */
7717         setTop : function(top){
7718             this.setStyle("top", this.addUnits(top));
7719             return this;
7720         },
7721
7722         /**
7723          * Sets the element's CSS right style.
7724          * @param {String} right The right CSS property value
7725          * @return {Roo.Element} this
7726          */
7727         setRight : function(right){
7728             this.setStyle("right", this.addUnits(right));
7729             return this;
7730         },
7731
7732         /**
7733          * Sets the element's CSS bottom style.
7734          * @param {String} bottom The bottom CSS property value
7735          * @return {Roo.Element} this
7736          */
7737         setBottom : function(bottom){
7738             this.setStyle("bottom", this.addUnits(bottom));
7739             return this;
7740         },
7741
7742         /**
7743          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7744          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7745          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7746          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7747          * @return {Roo.Element} this
7748          */
7749         setXY : function(pos, animate){
7750             if(!animate || !A){
7751                 D.setXY(this.dom, pos);
7752             }else{
7753                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7754             }
7755             return this;
7756         },
7757
7758         /**
7759          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7760          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7761          * @param {Number} x X value for new position (coordinates are page-based)
7762          * @param {Number} y Y value for new position (coordinates are page-based)
7763          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7764          * @return {Roo.Element} this
7765          */
7766         setLocation : function(x, y, animate){
7767             this.setXY([x, y], this.preanim(arguments, 2));
7768             return this;
7769         },
7770
7771         /**
7772          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7773          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7774          * @param {Number} x X value for new position (coordinates are page-based)
7775          * @param {Number} y Y value for new position (coordinates are page-based)
7776          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7777          * @return {Roo.Element} this
7778          */
7779         moveTo : function(x, y, animate){
7780             this.setXY([x, y], this.preanim(arguments, 2));
7781             return this;
7782         },
7783
7784         /**
7785          * Returns the region of the given element.
7786          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7787          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7788          */
7789         getRegion : function(){
7790             return D.getRegion(this.dom);
7791         },
7792
7793         /**
7794          * Returns the offset height of the element
7795          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7796          * @return {Number} The element's height
7797          */
7798         getHeight : function(contentHeight){
7799             var h = this.dom.offsetHeight || 0;
7800             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7801         },
7802
7803         /**
7804          * Returns the offset width of the element
7805          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7806          * @return {Number} The element's width
7807          */
7808         getWidth : function(contentWidth){
7809             var w = this.dom.offsetWidth || 0;
7810             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7811         },
7812
7813         /**
7814          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7815          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7816          * if a height has not been set using CSS.
7817          * @return {Number}
7818          */
7819         getComputedHeight : function(){
7820             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7821             if(!h){
7822                 h = parseInt(this.getStyle('height'), 10) || 0;
7823                 if(!this.isBorderBox()){
7824                     h += this.getFrameWidth('tb');
7825                 }
7826             }
7827             return h;
7828         },
7829
7830         /**
7831          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7832          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7833          * if a width has not been set using CSS.
7834          * @return {Number}
7835          */
7836         getComputedWidth : function(){
7837             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7838             if(!w){
7839                 w = parseInt(this.getStyle('width'), 10) || 0;
7840                 if(!this.isBorderBox()){
7841                     w += this.getFrameWidth('lr');
7842                 }
7843             }
7844             return w;
7845         },
7846
7847         /**
7848          * Returns the size of the element.
7849          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7850          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7851          */
7852         getSize : function(contentSize){
7853             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7854         },
7855
7856         /**
7857          * Returns the width and height of the viewport.
7858          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7859          */
7860         getViewSize : function(){
7861             var d = this.dom, doc = document, aw = 0, ah = 0;
7862             if(d == doc || d == doc.body){
7863                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7864             }else{
7865                 return {
7866                     width : d.clientWidth,
7867                     height: d.clientHeight
7868                 };
7869             }
7870         },
7871
7872         /**
7873          * Returns the value of the "value" attribute
7874          * @param {Boolean} asNumber true to parse the value as a number
7875          * @return {String/Number}
7876          */
7877         getValue : function(asNumber){
7878             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7879         },
7880
7881         // private
7882         adjustWidth : function(width){
7883             if(typeof width == "number"){
7884                 if(this.autoBoxAdjust && !this.isBorderBox()){
7885                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7886                 }
7887                 if(width < 0){
7888                     width = 0;
7889                 }
7890             }
7891             return width;
7892         },
7893
7894         // private
7895         adjustHeight : function(height){
7896             if(typeof height == "number"){
7897                if(this.autoBoxAdjust && !this.isBorderBox()){
7898                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7899                }
7900                if(height < 0){
7901                    height = 0;
7902                }
7903             }
7904             return height;
7905         },
7906
7907         /**
7908          * Set the width of the element
7909          * @param {Number} width The new width
7910          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7911          * @return {Roo.Element} this
7912          */
7913         setWidth : function(width, animate){
7914             width = this.adjustWidth(width);
7915             if(!animate || !A){
7916                 this.dom.style.width = this.addUnits(width);
7917             }else{
7918                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7919             }
7920             return this;
7921         },
7922
7923         /**
7924          * Set the height of the element
7925          * @param {Number} height The new height
7926          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7927          * @return {Roo.Element} this
7928          */
7929          setHeight : function(height, animate){
7930             height = this.adjustHeight(height);
7931             if(!animate || !A){
7932                 this.dom.style.height = this.addUnits(height);
7933             }else{
7934                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7935             }
7936             return this;
7937         },
7938
7939         /**
7940          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7941          * @param {Number} width The new width
7942          * @param {Number} height The new height
7943          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7944          * @return {Roo.Element} this
7945          */
7946          setSize : function(width, height, animate){
7947             if(typeof width == "object"){ // in case of object from getSize()
7948                 height = width.height; width = width.width;
7949             }
7950             width = this.adjustWidth(width); height = this.adjustHeight(height);
7951             if(!animate || !A){
7952                 this.dom.style.width = this.addUnits(width);
7953                 this.dom.style.height = this.addUnits(height);
7954             }else{
7955                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7956             }
7957             return this;
7958         },
7959
7960         /**
7961          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7962          * @param {Number} x X value for new position (coordinates are page-based)
7963          * @param {Number} y Y value for new position (coordinates are page-based)
7964          * @param {Number} width The new width
7965          * @param {Number} height The new height
7966          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7967          * @return {Roo.Element} this
7968          */
7969         setBounds : function(x, y, width, height, animate){
7970             if(!animate || !A){
7971                 this.setSize(width, height);
7972                 this.setLocation(x, y);
7973             }else{
7974                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7975                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7976                               this.preanim(arguments, 4), 'motion');
7977             }
7978             return this;
7979         },
7980
7981         /**
7982          * 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.
7983          * @param {Roo.lib.Region} region The region to fill
7984          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7985          * @return {Roo.Element} this
7986          */
7987         setRegion : function(region, animate){
7988             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7989             return this;
7990         },
7991
7992         /**
7993          * Appends an event handler
7994          *
7995          * @param {String}   eventName     The type of event to append
7996          * @param {Function} fn        The method the event invokes
7997          * @param {Object} scope       (optional) The scope (this object) of the fn
7998          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
7999          */
8000         addListener : function(eventName, fn, scope, options){
8001             if (this.dom) {
8002                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8003             }
8004         },
8005
8006         /**
8007          * Removes an event handler from this element
8008          * @param {String} eventName the type of event to remove
8009          * @param {Function} fn the method the event invokes
8010          * @return {Roo.Element} this
8011          */
8012         removeListener : function(eventName, fn){
8013             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8014             return this;
8015         },
8016
8017         /**
8018          * Removes all previous added listeners from this element
8019          * @return {Roo.Element} this
8020          */
8021         removeAllListeners : function(){
8022             E.purgeElement(this.dom);
8023             return this;
8024         },
8025
8026         relayEvent : function(eventName, observable){
8027             this.on(eventName, function(e){
8028                 observable.fireEvent(eventName, e);
8029             });
8030         },
8031
8032         /**
8033          * Set the opacity of the element
8034          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8035          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8036          * @return {Roo.Element} this
8037          */
8038          setOpacity : function(opacity, animate){
8039             if(!animate || !A){
8040                 var s = this.dom.style;
8041                 if(Roo.isIE){
8042                     s.zoom = 1;
8043                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8044                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8045                 }else{
8046                     s.opacity = opacity;
8047                 }
8048             }else{
8049                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8050             }
8051             return this;
8052         },
8053
8054         /**
8055          * Gets the left X coordinate
8056          * @param {Boolean} local True to get the local css position instead of page coordinate
8057          * @return {Number}
8058          */
8059         getLeft : function(local){
8060             if(!local){
8061                 return this.getX();
8062             }else{
8063                 return parseInt(this.getStyle("left"), 10) || 0;
8064             }
8065         },
8066
8067         /**
8068          * Gets the right X coordinate of the element (element X position + element width)
8069          * @param {Boolean} local True to get the local css position instead of page coordinate
8070          * @return {Number}
8071          */
8072         getRight : function(local){
8073             if(!local){
8074                 return this.getX() + this.getWidth();
8075             }else{
8076                 return (this.getLeft(true) + this.getWidth()) || 0;
8077             }
8078         },
8079
8080         /**
8081          * Gets the top Y coordinate
8082          * @param {Boolean} local True to get the local css position instead of page coordinate
8083          * @return {Number}
8084          */
8085         getTop : function(local) {
8086             if(!local){
8087                 return this.getY();
8088             }else{
8089                 return parseInt(this.getStyle("top"), 10) || 0;
8090             }
8091         },
8092
8093         /**
8094          * Gets the bottom Y coordinate of the element (element Y position + element height)
8095          * @param {Boolean} local True to get the local css position instead of page coordinate
8096          * @return {Number}
8097          */
8098         getBottom : function(local){
8099             if(!local){
8100                 return this.getY() + this.getHeight();
8101             }else{
8102                 return (this.getTop(true) + this.getHeight()) || 0;
8103             }
8104         },
8105
8106         /**
8107         * Initializes positioning on this element. If a desired position is not passed, it will make the
8108         * the element positioned relative IF it is not already positioned.
8109         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8110         * @param {Number} zIndex (optional) The zIndex to apply
8111         * @param {Number} x (optional) Set the page X position
8112         * @param {Number} y (optional) Set the page Y position
8113         */
8114         position : function(pos, zIndex, x, y){
8115             if(!pos){
8116                if(this.getStyle('position') == 'static'){
8117                    this.setStyle('position', 'relative');
8118                }
8119             }else{
8120                 this.setStyle("position", pos);
8121             }
8122             if(zIndex){
8123                 this.setStyle("z-index", zIndex);
8124             }
8125             if(x !== undefined && y !== undefined){
8126                 this.setXY([x, y]);
8127             }else if(x !== undefined){
8128                 this.setX(x);
8129             }else if(y !== undefined){
8130                 this.setY(y);
8131             }
8132         },
8133
8134         /**
8135         * Clear positioning back to the default when the document was loaded
8136         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8137         * @return {Roo.Element} this
8138          */
8139         clearPositioning : function(value){
8140             value = value ||'';
8141             this.setStyle({
8142                 "left": value,
8143                 "right": value,
8144                 "top": value,
8145                 "bottom": value,
8146                 "z-index": "",
8147                 "position" : "static"
8148             });
8149             return this;
8150         },
8151
8152         /**
8153         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8154         * snapshot before performing an update and then restoring the element.
8155         * @return {Object}
8156         */
8157         getPositioning : function(){
8158             var l = this.getStyle("left");
8159             var t = this.getStyle("top");
8160             return {
8161                 "position" : this.getStyle("position"),
8162                 "left" : l,
8163                 "right" : l ? "" : this.getStyle("right"),
8164                 "top" : t,
8165                 "bottom" : t ? "" : this.getStyle("bottom"),
8166                 "z-index" : this.getStyle("z-index")
8167             };
8168         },
8169
8170         /**
8171          * Gets the width of the border(s) for the specified side(s)
8172          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8173          * passing lr would get the border (l)eft width + the border (r)ight width.
8174          * @return {Number} The width of the sides passed added together
8175          */
8176         getBorderWidth : function(side){
8177             return this.addStyles(side, El.borders);
8178         },
8179
8180         /**
8181          * Gets the width of the padding(s) for the specified side(s)
8182          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8183          * passing lr would get the padding (l)eft + the padding (r)ight.
8184          * @return {Number} The padding of the sides passed added together
8185          */
8186         getPadding : function(side){
8187             return this.addStyles(side, El.paddings);
8188         },
8189
8190         /**
8191         * Set positioning with an object returned by getPositioning().
8192         * @param {Object} posCfg
8193         * @return {Roo.Element} this
8194          */
8195         setPositioning : function(pc){
8196             this.applyStyles(pc);
8197             if(pc.right == "auto"){
8198                 this.dom.style.right = "";
8199             }
8200             if(pc.bottom == "auto"){
8201                 this.dom.style.bottom = "";
8202             }
8203             return this;
8204         },
8205
8206         // private
8207         fixDisplay : function(){
8208             if(this.getStyle("display") == "none"){
8209                 this.setStyle("visibility", "hidden");
8210                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8211                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8212                     this.setStyle("display", "block");
8213                 }
8214             }
8215         },
8216
8217         /**
8218          * Quick set left and top adding default units
8219          * @param {String} left The left CSS property value
8220          * @param {String} top The top CSS property value
8221          * @return {Roo.Element} this
8222          */
8223          setLeftTop : function(left, top){
8224             this.dom.style.left = this.addUnits(left);
8225             this.dom.style.top = this.addUnits(top);
8226             return this;
8227         },
8228
8229         /**
8230          * Move this element relative to its current position.
8231          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8232          * @param {Number} distance How far to move the element in pixels
8233          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8234          * @return {Roo.Element} this
8235          */
8236          move : function(direction, distance, animate){
8237             var xy = this.getXY();
8238             direction = direction.toLowerCase();
8239             switch(direction){
8240                 case "l":
8241                 case "left":
8242                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8243                     break;
8244                case "r":
8245                case "right":
8246                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8247                     break;
8248                case "t":
8249                case "top":
8250                case "up":
8251                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8252                     break;
8253                case "b":
8254                case "bottom":
8255                case "down":
8256                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8257                     break;
8258             }
8259             return this;
8260         },
8261
8262         /**
8263          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8264          * @return {Roo.Element} this
8265          */
8266         clip : function(){
8267             if(!this.isClipped){
8268                this.isClipped = true;
8269                this.originalClip = {
8270                    "o": this.getStyle("overflow"),
8271                    "x": this.getStyle("overflow-x"),
8272                    "y": this.getStyle("overflow-y")
8273                };
8274                this.setStyle("overflow", "hidden");
8275                this.setStyle("overflow-x", "hidden");
8276                this.setStyle("overflow-y", "hidden");
8277             }
8278             return this;
8279         },
8280
8281         /**
8282          *  Return clipping (overflow) to original clipping before clip() was called
8283          * @return {Roo.Element} this
8284          */
8285         unclip : function(){
8286             if(this.isClipped){
8287                 this.isClipped = false;
8288                 var o = this.originalClip;
8289                 if(o.o){this.setStyle("overflow", o.o);}
8290                 if(o.x){this.setStyle("overflow-x", o.x);}
8291                 if(o.y){this.setStyle("overflow-y", o.y);}
8292             }
8293             return this;
8294         },
8295
8296
8297         /**
8298          * Gets the x,y coordinates specified by the anchor position on the element.
8299          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8300          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8301          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8302          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8303          * @return {Array} [x, y] An array containing the element's x and y coordinates
8304          */
8305         getAnchorXY : function(anchor, local, s){
8306             //Passing a different size is useful for pre-calculating anchors,
8307             //especially for anchored animations that change the el size.
8308
8309             var w, h, vp = false;
8310             if(!s){
8311                 var d = this.dom;
8312                 if(d == document.body || d == document){
8313                     vp = true;
8314                     w = D.getViewWidth(); h = D.getViewHeight();
8315                 }else{
8316                     w = this.getWidth(); h = this.getHeight();
8317                 }
8318             }else{
8319                 w = s.width;  h = s.height;
8320             }
8321             var x = 0, y = 0, r = Math.round;
8322             switch((anchor || "tl").toLowerCase()){
8323                 case "c":
8324                     x = r(w*.5);
8325                     y = r(h*.5);
8326                 break;
8327                 case "t":
8328                     x = r(w*.5);
8329                     y = 0;
8330                 break;
8331                 case "l":
8332                     x = 0;
8333                     y = r(h*.5);
8334                 break;
8335                 case "r":
8336                     x = w;
8337                     y = r(h*.5);
8338                 break;
8339                 case "b":
8340                     x = r(w*.5);
8341                     y = h;
8342                 break;
8343                 case "tl":
8344                     x = 0;
8345                     y = 0;
8346                 break;
8347                 case "bl":
8348                     x = 0;
8349                     y = h;
8350                 break;
8351                 case "br":
8352                     x = w;
8353                     y = h;
8354                 break;
8355                 case "tr":
8356                     x = w;
8357                     y = 0;
8358                 break;
8359             }
8360             if(local === true){
8361                 return [x, y];
8362             }
8363             if(vp){
8364                 var sc = this.getScroll();
8365                 return [x + sc.left, y + sc.top];
8366             }
8367             //Add the element's offset xy
8368             var o = this.getXY();
8369             return [x+o[0], y+o[1]];
8370         },
8371
8372         /**
8373          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8374          * supported position values.
8375          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8376          * @param {String} position The position to align to.
8377          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8378          * @return {Array} [x, y]
8379          */
8380         getAlignToXY : function(el, p, o){
8381             el = Roo.get(el);
8382             var d = this.dom;
8383             if(!el.dom){
8384                 throw "Element.alignTo with an element that doesn't exist";
8385             }
8386             var c = false; //constrain to viewport
8387             var p1 = "", p2 = "";
8388             o = o || [0,0];
8389
8390             if(!p){
8391                 p = "tl-bl";
8392             }else if(p == "?"){
8393                 p = "tl-bl?";
8394             }else if(p.indexOf("-") == -1){
8395                 p = "tl-" + p;
8396             }
8397             p = p.toLowerCase();
8398             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8399             if(!m){
8400                throw "Element.alignTo with an invalid alignment " + p;
8401             }
8402             p1 = m[1]; p2 = m[2]; c = !!m[3];
8403
8404             //Subtract the aligned el's internal xy from the target's offset xy
8405             //plus custom offset to get the aligned el's new offset xy
8406             var a1 = this.getAnchorXY(p1, true);
8407             var a2 = el.getAnchorXY(p2, false);
8408             var x = a2[0] - a1[0] + o[0];
8409             var y = a2[1] - a1[1] + o[1];
8410             if(c){
8411                 //constrain the aligned el to viewport if necessary
8412                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8413                 // 5px of margin for ie
8414                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8415
8416                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8417                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8418                 //otherwise swap the aligned el to the opposite border of the target.
8419                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8420                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8421                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8422                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8423
8424                var doc = document;
8425                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8426                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8427
8428                if((x+w) > dw + scrollX){
8429                     x = swapX ? r.left-w : dw+scrollX-w;
8430                 }
8431                if(x < scrollX){
8432                    x = swapX ? r.right : scrollX;
8433                }
8434                if((y+h) > dh + scrollY){
8435                     y = swapY ? r.top-h : dh+scrollY-h;
8436                 }
8437                if (y < scrollY){
8438                    y = swapY ? r.bottom : scrollY;
8439                }
8440             }
8441             return [x,y];
8442         },
8443
8444         // private
8445         getConstrainToXY : function(){
8446             var os = {top:0, left:0, bottom:0, right: 0};
8447
8448             return function(el, local, offsets, proposedXY){
8449                 el = Roo.get(el);
8450                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8451
8452                 var vw, vh, vx = 0, vy = 0;
8453                 if(el.dom == document.body || el.dom == document){
8454                     vw = Roo.lib.Dom.getViewWidth();
8455                     vh = Roo.lib.Dom.getViewHeight();
8456                 }else{
8457                     vw = el.dom.clientWidth;
8458                     vh = el.dom.clientHeight;
8459                     if(!local){
8460                         var vxy = el.getXY();
8461                         vx = vxy[0];
8462                         vy = vxy[1];
8463                     }
8464                 }
8465
8466                 var s = el.getScroll();
8467
8468                 vx += offsets.left + s.left;
8469                 vy += offsets.top + s.top;
8470
8471                 vw -= offsets.right;
8472                 vh -= offsets.bottom;
8473
8474                 var vr = vx+vw;
8475                 var vb = vy+vh;
8476
8477                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8478                 var x = xy[0], y = xy[1];
8479                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8480
8481                 // only move it if it needs it
8482                 var moved = false;
8483
8484                 // first validate right/bottom
8485                 if((x + w) > vr){
8486                     x = vr - w;
8487                     moved = true;
8488                 }
8489                 if((y + h) > vb){
8490                     y = vb - h;
8491                     moved = true;
8492                 }
8493                 // then make sure top/left isn't negative
8494                 if(x < vx){
8495                     x = vx;
8496                     moved = true;
8497                 }
8498                 if(y < vy){
8499                     y = vy;
8500                     moved = true;
8501                 }
8502                 return moved ? [x, y] : false;
8503             };
8504         }(),
8505
8506         // private
8507         adjustForConstraints : function(xy, parent, offsets){
8508             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8509         },
8510
8511         /**
8512          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8513          * document it aligns it to the viewport.
8514          * The position parameter is optional, and can be specified in any one of the following formats:
8515          * <ul>
8516          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8517          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8518          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8519          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8520          *   <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
8521          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8522          * </ul>
8523          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8524          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8525          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8526          * that specified in order to enforce the viewport constraints.
8527          * Following are all of the supported anchor positions:
8528     <pre>
8529     Value  Description
8530     -----  -----------------------------
8531     tl     The top left corner (default)
8532     t      The center of the top edge
8533     tr     The top right corner
8534     l      The center of the left edge
8535     c      In the center of the element
8536     r      The center of the right edge
8537     bl     The bottom left corner
8538     b      The center of the bottom edge
8539     br     The bottom right corner
8540     </pre>
8541     Example Usage:
8542     <pre><code>
8543     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8544     el.alignTo("other-el");
8545
8546     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8547     el.alignTo("other-el", "tr?");
8548
8549     // align the bottom right corner of el with the center left edge of other-el
8550     el.alignTo("other-el", "br-l?");
8551
8552     // align the center of el with the bottom left corner of other-el and
8553     // adjust the x position by -6 pixels (and the y position by 0)
8554     el.alignTo("other-el", "c-bl", [-6, 0]);
8555     </code></pre>
8556          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8557          * @param {String} position The position to align to.
8558          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8559          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8560          * @return {Roo.Element} this
8561          */
8562         alignTo : function(element, position, offsets, animate){
8563             var xy = this.getAlignToXY(element, position, offsets);
8564             this.setXY(xy, this.preanim(arguments, 3));
8565             return this;
8566         },
8567
8568         /**
8569          * Anchors an element to another element and realigns it when the window is resized.
8570          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8571          * @param {String} position The position to align to.
8572          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8573          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8574          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8575          * is a number, it is used as the buffer delay (defaults to 50ms).
8576          * @param {Function} callback The function to call after the animation finishes
8577          * @return {Roo.Element} this
8578          */
8579         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8580             var action = function(){
8581                 this.alignTo(el, alignment, offsets, animate);
8582                 Roo.callback(callback, this);
8583             };
8584             Roo.EventManager.onWindowResize(action, this);
8585             var tm = typeof monitorScroll;
8586             if(tm != 'undefined'){
8587                 Roo.EventManager.on(window, 'scroll', action, this,
8588                     {buffer: tm == 'number' ? monitorScroll : 50});
8589             }
8590             action.call(this); // align immediately
8591             return this;
8592         },
8593         /**
8594          * Clears any opacity settings from this element. Required in some cases for IE.
8595          * @return {Roo.Element} this
8596          */
8597         clearOpacity : function(){
8598             if (window.ActiveXObject) {
8599                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8600                     this.dom.style.filter = "";
8601                 }
8602             } else {
8603                 this.dom.style.opacity = "";
8604                 this.dom.style["-moz-opacity"] = "";
8605                 this.dom.style["-khtml-opacity"] = "";
8606             }
8607             return this;
8608         },
8609
8610         /**
8611          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8612          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8613          * @return {Roo.Element} this
8614          */
8615         hide : function(animate){
8616             this.setVisible(false, this.preanim(arguments, 0));
8617             return this;
8618         },
8619
8620         /**
8621         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8622         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8623          * @return {Roo.Element} this
8624          */
8625         show : function(animate){
8626             this.setVisible(true, this.preanim(arguments, 0));
8627             return this;
8628         },
8629
8630         /**
8631          * @private Test if size has a unit, otherwise appends the default
8632          */
8633         addUnits : function(size){
8634             return Roo.Element.addUnits(size, this.defaultUnit);
8635         },
8636
8637         /**
8638          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8639          * @return {Roo.Element} this
8640          */
8641         beginMeasure : function(){
8642             var el = this.dom;
8643             if(el.offsetWidth || el.offsetHeight){
8644                 return this; // offsets work already
8645             }
8646             var changed = [];
8647             var p = this.dom, b = document.body; // start with this element
8648             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8649                 var pe = Roo.get(p);
8650                 if(pe.getStyle('display') == 'none'){
8651                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8652                     p.style.visibility = "hidden";
8653                     p.style.display = "block";
8654                 }
8655                 p = p.parentNode;
8656             }
8657             this._measureChanged = changed;
8658             return this;
8659
8660         },
8661
8662         /**
8663          * Restores displays to before beginMeasure was called
8664          * @return {Roo.Element} this
8665          */
8666         endMeasure : function(){
8667             var changed = this._measureChanged;
8668             if(changed){
8669                 for(var i = 0, len = changed.length; i < len; i++) {
8670                     var r = changed[i];
8671                     r.el.style.visibility = r.visibility;
8672                     r.el.style.display = "none";
8673                 }
8674                 this._measureChanged = null;
8675             }
8676             return this;
8677         },
8678
8679         /**
8680         * Update the innerHTML of this element, optionally searching for and processing scripts
8681         * @param {String} html The new HTML
8682         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8683         * @param {Function} callback For async script loading you can be noticed when the update completes
8684         * @return {Roo.Element} this
8685          */
8686         update : function(html, loadScripts, callback){
8687             if(typeof html == "undefined"){
8688                 html = "";
8689             }
8690             if(loadScripts !== true){
8691                 this.dom.innerHTML = html;
8692                 if(typeof callback == "function"){
8693                     callback();
8694                 }
8695                 return this;
8696             }
8697             var id = Roo.id();
8698             var dom = this.dom;
8699
8700             html += '<span id="' + id + '"></span>';
8701
8702             E.onAvailable(id, function(){
8703                 var hd = document.getElementsByTagName("head")[0];
8704                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8705                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8706                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8707
8708                 var match;
8709                 while(match = re.exec(html)){
8710                     var attrs = match[1];
8711                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8712                     if(srcMatch && srcMatch[2]){
8713                        var s = document.createElement("script");
8714                        s.src = srcMatch[2];
8715                        var typeMatch = attrs.match(typeRe);
8716                        if(typeMatch && typeMatch[2]){
8717                            s.type = typeMatch[2];
8718                        }
8719                        hd.appendChild(s);
8720                     }else if(match[2] && match[2].length > 0){
8721                         if(window.execScript) {
8722                            window.execScript(match[2]);
8723                         } else {
8724                             /**
8725                              * eval:var:id
8726                              * eval:var:dom
8727                              * eval:var:html
8728                              * 
8729                              */
8730                            window.eval(match[2]);
8731                         }
8732                     }
8733                 }
8734                 var el = document.getElementById(id);
8735                 if(el){el.parentNode.removeChild(el);}
8736                 if(typeof callback == "function"){
8737                     callback();
8738                 }
8739             });
8740             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8741             return this;
8742         },
8743
8744         /**
8745          * Direct access to the UpdateManager update() method (takes the same parameters).
8746          * @param {String/Function} url The url for this request or a function to call to get the url
8747          * @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}
8748          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8749          * @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.
8750          * @return {Roo.Element} this
8751          */
8752         load : function(){
8753             var um = this.getUpdateManager();
8754             um.update.apply(um, arguments);
8755             return this;
8756         },
8757
8758         /**
8759         * Gets this element's UpdateManager
8760         * @return {Roo.UpdateManager} The UpdateManager
8761         */
8762         getUpdateManager : function(){
8763             if(!this.updateManager){
8764                 this.updateManager = new Roo.UpdateManager(this);
8765             }
8766             return this.updateManager;
8767         },
8768
8769         /**
8770          * Disables text selection for this element (normalized across browsers)
8771          * @return {Roo.Element} this
8772          */
8773         unselectable : function(){
8774             this.dom.unselectable = "on";
8775             this.swallowEvent("selectstart", true);
8776             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8777             this.addClass("x-unselectable");
8778             return this;
8779         },
8780
8781         /**
8782         * Calculates the x, y to center this element on the screen
8783         * @return {Array} The x, y values [x, y]
8784         */
8785         getCenterXY : function(){
8786             return this.getAlignToXY(document, 'c-c');
8787         },
8788
8789         /**
8790         * Centers the Element in either the viewport, or another Element.
8791         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8792         */
8793         center : function(centerIn){
8794             this.alignTo(centerIn || document, 'c-c');
8795             return this;
8796         },
8797
8798         /**
8799          * Tests various css rules/browsers to determine if this element uses a border box
8800          * @return {Boolean}
8801          */
8802         isBorderBox : function(){
8803             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8804         },
8805
8806         /**
8807          * Return a box {x, y, width, height} that can be used to set another elements
8808          * size/location to match this element.
8809          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8810          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8811          * @return {Object} box An object in the format {x, y, width, height}
8812          */
8813         getBox : function(contentBox, local){
8814             var xy;
8815             if(!local){
8816                 xy = this.getXY();
8817             }else{
8818                 var left = parseInt(this.getStyle("left"), 10) || 0;
8819                 var top = parseInt(this.getStyle("top"), 10) || 0;
8820                 xy = [left, top];
8821             }
8822             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8823             if(!contentBox){
8824                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8825             }else{
8826                 var l = this.getBorderWidth("l")+this.getPadding("l");
8827                 var r = this.getBorderWidth("r")+this.getPadding("r");
8828                 var t = this.getBorderWidth("t")+this.getPadding("t");
8829                 var b = this.getBorderWidth("b")+this.getPadding("b");
8830                 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)};
8831             }
8832             bx.right = bx.x + bx.width;
8833             bx.bottom = bx.y + bx.height;
8834             return bx;
8835         },
8836
8837         /**
8838          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8839          for more information about the sides.
8840          * @param {String} sides
8841          * @return {Number}
8842          */
8843         getFrameWidth : function(sides, onlyContentBox){
8844             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8845         },
8846
8847         /**
8848          * 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.
8849          * @param {Object} box The box to fill {x, y, width, height}
8850          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8851          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8852          * @return {Roo.Element} this
8853          */
8854         setBox : function(box, adjust, animate){
8855             var w = box.width, h = box.height;
8856             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8857                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8858                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8859             }
8860             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8861             return this;
8862         },
8863
8864         /**
8865          * Forces the browser to repaint this element
8866          * @return {Roo.Element} this
8867          */
8868          repaint : function(){
8869             var dom = this.dom;
8870             this.addClass("x-repaint");
8871             setTimeout(function(){
8872                 Roo.get(dom).removeClass("x-repaint");
8873             }, 1);
8874             return this;
8875         },
8876
8877         /**
8878          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8879          * then it returns the calculated width of the sides (see getPadding)
8880          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8881          * @return {Object/Number}
8882          */
8883         getMargins : function(side){
8884             if(!side){
8885                 return {
8886                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8887                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8888                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8889                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8890                 };
8891             }else{
8892                 return this.addStyles(side, El.margins);
8893              }
8894         },
8895
8896         // private
8897         addStyles : function(sides, styles){
8898             var val = 0, v, w;
8899             for(var i = 0, len = sides.length; i < len; i++){
8900                 v = this.getStyle(styles[sides.charAt(i)]);
8901                 if(v){
8902                      w = parseInt(v, 10);
8903                      if(w){ val += w; }
8904                 }
8905             }
8906             return val;
8907         },
8908
8909         /**
8910          * Creates a proxy element of this element
8911          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8912          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8913          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8914          * @return {Roo.Element} The new proxy element
8915          */
8916         createProxy : function(config, renderTo, matchBox){
8917             if(renderTo){
8918                 renderTo = Roo.getDom(renderTo);
8919             }else{
8920                 renderTo = document.body;
8921             }
8922             config = typeof config == "object" ?
8923                 config : {tag : "div", cls: config};
8924             var proxy = Roo.DomHelper.append(renderTo, config, true);
8925             if(matchBox){
8926                proxy.setBox(this.getBox());
8927             }
8928             return proxy;
8929         },
8930
8931         /**
8932          * Puts a mask over this element to disable user interaction. Requires core.css.
8933          * This method can only be applied to elements which accept child nodes.
8934          * @param {String} msg (optional) A message to display in the mask
8935          * @param {String} msgCls (optional) A css class to apply to the msg element
8936          * @return {Element} The mask  element
8937          */
8938         mask : function(msg, msgCls)
8939         {
8940             if(this.getStyle("position") == "static"){
8941                 this.setStyle("position", "relative");
8942             }
8943             if(!this._mask){
8944                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8945             }
8946             this.addClass("x-masked");
8947             this._mask.setDisplayed(true);
8948             
8949             // we wander
8950             var z = 0;
8951             var dom = this.dom
8952             while (dom && dom.style) {
8953                 if (!isNaN(parseInt(dom.style.zIndex))) {
8954                     z = Math.max(z, parseInt(dom.style.zIndex));
8955                 }
8956                 dom = dom.parentNode;
8957             }
8958             // if we are masking the body - then it hides everything..
8959             if (this.dom == document.body) {
8960                 z = 1000000;
8961                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8962                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8963             }
8964            
8965             if(typeof msg == 'string'){
8966                 if(!this._maskMsg){
8967                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8968                 }
8969                 var mm = this._maskMsg;
8970                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8971                 mm.dom.firstChild.innerHTML = msg;
8972                 mm.setDisplayed(true);
8973                 mm.center(this);
8974                 mm.setStyle('z-index', z + 102);
8975             }
8976             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8977                 this._mask.setHeight(this.getHeight());
8978             }
8979             this._mask.setStyle('z-index', z + 100);
8980             
8981             return this._mask;
8982         },
8983
8984         /**
8985          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8986          * it is cached for reuse.
8987          */
8988         unmask : function(removeEl){
8989             if(this._mask){
8990                 if(removeEl === true){
8991                     this._mask.remove();
8992                     delete this._mask;
8993                     if(this._maskMsg){
8994                         this._maskMsg.remove();
8995                         delete this._maskMsg;
8996                     }
8997                 }else{
8998                     this._mask.setDisplayed(false);
8999                     if(this._maskMsg){
9000                         this._maskMsg.setDisplayed(false);
9001                     }
9002                 }
9003             }
9004             this.removeClass("x-masked");
9005         },
9006
9007         /**
9008          * Returns true if this element is masked
9009          * @return {Boolean}
9010          */
9011         isMasked : function(){
9012             return this._mask && this._mask.isVisible();
9013         },
9014
9015         /**
9016          * Creates an iframe shim for this element to keep selects and other windowed objects from
9017          * showing through.
9018          * @return {Roo.Element} The new shim element
9019          */
9020         createShim : function(){
9021             var el = document.createElement('iframe');
9022             el.frameBorder = 'no';
9023             el.className = 'roo-shim';
9024             if(Roo.isIE && Roo.isSecure){
9025                 el.src = Roo.SSL_SECURE_URL;
9026             }
9027             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9028             shim.autoBoxAdjust = false;
9029             return shim;
9030         },
9031
9032         /**
9033          * Removes this element from the DOM and deletes it from the cache
9034          */
9035         remove : function(){
9036             if(this.dom.parentNode){
9037                 this.dom.parentNode.removeChild(this.dom);
9038             }
9039             delete El.cache[this.dom.id];
9040         },
9041
9042         /**
9043          * Sets up event handlers to add and remove a css class when the mouse is over this element
9044          * @param {String} className
9045          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9046          * mouseout events for children elements
9047          * @return {Roo.Element} this
9048          */
9049         addClassOnOver : function(className, preventFlicker){
9050             this.on("mouseover", function(){
9051                 Roo.fly(this, '_internal').addClass(className);
9052             }, this.dom);
9053             var removeFn = function(e){
9054                 if(preventFlicker !== true || !e.within(this, true)){
9055                     Roo.fly(this, '_internal').removeClass(className);
9056                 }
9057             };
9058             this.on("mouseout", removeFn, this.dom);
9059             return this;
9060         },
9061
9062         /**
9063          * Sets up event handlers to add and remove a css class when this element has the focus
9064          * @param {String} className
9065          * @return {Roo.Element} this
9066          */
9067         addClassOnFocus : function(className){
9068             this.on("focus", function(){
9069                 Roo.fly(this, '_internal').addClass(className);
9070             }, this.dom);
9071             this.on("blur", function(){
9072                 Roo.fly(this, '_internal').removeClass(className);
9073             }, this.dom);
9074             return this;
9075         },
9076         /**
9077          * 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)
9078          * @param {String} className
9079          * @return {Roo.Element} this
9080          */
9081         addClassOnClick : function(className){
9082             var dom = this.dom;
9083             this.on("mousedown", function(){
9084                 Roo.fly(dom, '_internal').addClass(className);
9085                 var d = Roo.get(document);
9086                 var fn = function(){
9087                     Roo.fly(dom, '_internal').removeClass(className);
9088                     d.removeListener("mouseup", fn);
9089                 };
9090                 d.on("mouseup", fn);
9091             });
9092             return this;
9093         },
9094
9095         /**
9096          * Stops the specified event from bubbling and optionally prevents the default action
9097          * @param {String} eventName
9098          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9099          * @return {Roo.Element} this
9100          */
9101         swallowEvent : function(eventName, preventDefault){
9102             var fn = function(e){
9103                 e.stopPropagation();
9104                 if(preventDefault){
9105                     e.preventDefault();
9106                 }
9107             };
9108             if(eventName instanceof Array){
9109                 for(var i = 0, len = eventName.length; i < len; i++){
9110                      this.on(eventName[i], fn);
9111                 }
9112                 return this;
9113             }
9114             this.on(eventName, fn);
9115             return this;
9116         },
9117
9118         /**
9119          * @private
9120          */
9121       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9122
9123         /**
9124          * Sizes this element to its parent element's dimensions performing
9125          * neccessary box adjustments.
9126          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9127          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9128          * @return {Roo.Element} this
9129          */
9130         fitToParent : function(monitorResize, targetParent) {
9131           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9132           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9133           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9134             return;
9135           }
9136           var p = Roo.get(targetParent || this.dom.parentNode);
9137           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9138           if (monitorResize === true) {
9139             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9140             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9141           }
9142           return this;
9143         },
9144
9145         /**
9146          * Gets the next sibling, skipping text nodes
9147          * @return {HTMLElement} The next sibling or null
9148          */
9149         getNextSibling : function(){
9150             var n = this.dom.nextSibling;
9151             while(n && n.nodeType != 1){
9152                 n = n.nextSibling;
9153             }
9154             return n;
9155         },
9156
9157         /**
9158          * Gets the previous sibling, skipping text nodes
9159          * @return {HTMLElement} The previous sibling or null
9160          */
9161         getPrevSibling : function(){
9162             var n = this.dom.previousSibling;
9163             while(n && n.nodeType != 1){
9164                 n = n.previousSibling;
9165             }
9166             return n;
9167         },
9168
9169
9170         /**
9171          * Appends the passed element(s) to this element
9172          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9173          * @return {Roo.Element} this
9174          */
9175         appendChild: function(el){
9176             el = Roo.get(el);
9177             el.appendTo(this);
9178             return this;
9179         },
9180
9181         /**
9182          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9183          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9184          * automatically generated with the specified attributes.
9185          * @param {HTMLElement} insertBefore (optional) a child element of this element
9186          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9187          * @return {Roo.Element} The new child element
9188          */
9189         createChild: function(config, insertBefore, returnDom){
9190             config = config || {tag:'div'};
9191             if(insertBefore){
9192                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9193             }
9194             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9195         },
9196
9197         /**
9198          * Appends this element to the passed element
9199          * @param {String/HTMLElement/Element} el The new parent element
9200          * @return {Roo.Element} this
9201          */
9202         appendTo: function(el){
9203             el = Roo.getDom(el);
9204             el.appendChild(this.dom);
9205             return this;
9206         },
9207
9208         /**
9209          * Inserts this element before the passed element in the DOM
9210          * @param {String/HTMLElement/Element} el The element to insert before
9211          * @return {Roo.Element} this
9212          */
9213         insertBefore: function(el){
9214             el = Roo.getDom(el);
9215             el.parentNode.insertBefore(this.dom, el);
9216             return this;
9217         },
9218
9219         /**
9220          * Inserts this element after the passed element in the DOM
9221          * @param {String/HTMLElement/Element} el The element to insert after
9222          * @return {Roo.Element} this
9223          */
9224         insertAfter: function(el){
9225             el = Roo.getDom(el);
9226             el.parentNode.insertBefore(this.dom, el.nextSibling);
9227             return this;
9228         },
9229
9230         /**
9231          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9232          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9233          * @return {Roo.Element} The new child
9234          */
9235         insertFirst: function(el, returnDom){
9236             el = el || {};
9237             if(typeof el == 'object' && !el.nodeType){ // dh config
9238                 return this.createChild(el, this.dom.firstChild, returnDom);
9239             }else{
9240                 el = Roo.getDom(el);
9241                 this.dom.insertBefore(el, this.dom.firstChild);
9242                 return !returnDom ? Roo.get(el) : el;
9243             }
9244         },
9245
9246         /**
9247          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9248          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9249          * @param {String} where (optional) 'before' or 'after' defaults to before
9250          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9251          * @return {Roo.Element} the inserted Element
9252          */
9253         insertSibling: function(el, where, returnDom){
9254             where = where ? where.toLowerCase() : 'before';
9255             el = el || {};
9256             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9257
9258             if(typeof el == 'object' && !el.nodeType){ // dh config
9259                 if(where == 'after' && !this.dom.nextSibling){
9260                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9261                 }else{
9262                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9263                 }
9264
9265             }else{
9266                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9267                             where == 'before' ? this.dom : this.dom.nextSibling);
9268                 if(!returnDom){
9269                     rt = Roo.get(rt);
9270                 }
9271             }
9272             return rt;
9273         },
9274
9275         /**
9276          * Creates and wraps this element with another element
9277          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9278          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9279          * @return {HTMLElement/Element} The newly created wrapper element
9280          */
9281         wrap: function(config, returnDom){
9282             if(!config){
9283                 config = {tag: "div"};
9284             }
9285             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9286             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9287             return newEl;
9288         },
9289
9290         /**
9291          * Replaces the passed element with this element
9292          * @param {String/HTMLElement/Element} el The element to replace
9293          * @return {Roo.Element} this
9294          */
9295         replace: function(el){
9296             el = Roo.get(el);
9297             this.insertBefore(el);
9298             el.remove();
9299             return this;
9300         },
9301
9302         /**
9303          * Inserts an html fragment into this element
9304          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9305          * @param {String} html The HTML fragment
9306          * @param {Boolean} returnEl True to return an Roo.Element
9307          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9308          */
9309         insertHtml : function(where, html, returnEl){
9310             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9311             return returnEl ? Roo.get(el) : el;
9312         },
9313
9314         /**
9315          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9316          * @param {Object} o The object with the attributes
9317          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9318          * @return {Roo.Element} this
9319          */
9320         set : function(o, useSet){
9321             var el = this.dom;
9322             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9323             for(var attr in o){
9324                 if(attr == "style" || typeof o[attr] == "function") continue;
9325                 if(attr=="cls"){
9326                     el.className = o["cls"];
9327                 }else{
9328                     if(useSet) el.setAttribute(attr, o[attr]);
9329                     else el[attr] = o[attr];
9330                 }
9331             }
9332             if(o.style){
9333                 Roo.DomHelper.applyStyles(el, o.style);
9334             }
9335             return this;
9336         },
9337
9338         /**
9339          * Convenience method for constructing a KeyMap
9340          * @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:
9341          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9342          * @param {Function} fn The function to call
9343          * @param {Object} scope (optional) The scope of the function
9344          * @return {Roo.KeyMap} The KeyMap created
9345          */
9346         addKeyListener : function(key, fn, scope){
9347             var config;
9348             if(typeof key != "object" || key instanceof Array){
9349                 config = {
9350                     key: key,
9351                     fn: fn,
9352                     scope: scope
9353                 };
9354             }else{
9355                 config = {
9356                     key : key.key,
9357                     shift : key.shift,
9358                     ctrl : key.ctrl,
9359                     alt : key.alt,
9360                     fn: fn,
9361                     scope: scope
9362                 };
9363             }
9364             return new Roo.KeyMap(this, config);
9365         },
9366
9367         /**
9368          * Creates a KeyMap for this element
9369          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9370          * @return {Roo.KeyMap} The KeyMap created
9371          */
9372         addKeyMap : function(config){
9373             return new Roo.KeyMap(this, config);
9374         },
9375
9376         /**
9377          * Returns true if this element is scrollable.
9378          * @return {Boolean}
9379          */
9380          isScrollable : function(){
9381             var dom = this.dom;
9382             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9383         },
9384
9385         /**
9386          * 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().
9387          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9388          * @param {Number} value The new scroll value
9389          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9390          * @return {Element} this
9391          */
9392
9393         scrollTo : function(side, value, animate){
9394             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9395             if(!animate || !A){
9396                 this.dom[prop] = value;
9397             }else{
9398                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9399                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9400             }
9401             return this;
9402         },
9403
9404         /**
9405          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9406          * within this element's scrollable range.
9407          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9408          * @param {Number} distance How far to scroll the element in pixels
9409          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9410          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9411          * was scrolled as far as it could go.
9412          */
9413          scroll : function(direction, distance, animate){
9414              if(!this.isScrollable()){
9415                  return;
9416              }
9417              var el = this.dom;
9418              var l = el.scrollLeft, t = el.scrollTop;
9419              var w = el.scrollWidth, h = el.scrollHeight;
9420              var cw = el.clientWidth, ch = el.clientHeight;
9421              direction = direction.toLowerCase();
9422              var scrolled = false;
9423              var a = this.preanim(arguments, 2);
9424              switch(direction){
9425                  case "l":
9426                  case "left":
9427                      if(w - l > cw){
9428                          var v = Math.min(l + distance, w-cw);
9429                          this.scrollTo("left", v, a);
9430                          scrolled = true;
9431                      }
9432                      break;
9433                 case "r":
9434                 case "right":
9435                      if(l > 0){
9436                          var v = Math.max(l - distance, 0);
9437                          this.scrollTo("left", v, a);
9438                          scrolled = true;
9439                      }
9440                      break;
9441                 case "t":
9442                 case "top":
9443                 case "up":
9444                      if(t > 0){
9445                          var v = Math.max(t - distance, 0);
9446                          this.scrollTo("top", v, a);
9447                          scrolled = true;
9448                      }
9449                      break;
9450                 case "b":
9451                 case "bottom":
9452                 case "down":
9453                      if(h - t > ch){
9454                          var v = Math.min(t + distance, h-ch);
9455                          this.scrollTo("top", v, a);
9456                          scrolled = true;
9457                      }
9458                      break;
9459              }
9460              return scrolled;
9461         },
9462
9463         /**
9464          * Translates the passed page coordinates into left/top css values for this element
9465          * @param {Number/Array} x The page x or an array containing [x, y]
9466          * @param {Number} y The page y
9467          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9468          */
9469         translatePoints : function(x, y){
9470             if(typeof x == 'object' || x instanceof Array){
9471                 y = x[1]; x = x[0];
9472             }
9473             var p = this.getStyle('position');
9474             var o = this.getXY();
9475
9476             var l = parseInt(this.getStyle('left'), 10);
9477             var t = parseInt(this.getStyle('top'), 10);
9478
9479             if(isNaN(l)){
9480                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9481             }
9482             if(isNaN(t)){
9483                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9484             }
9485
9486             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9487         },
9488
9489         /**
9490          * Returns the current scroll position of the element.
9491          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9492          */
9493         getScroll : function(){
9494             var d = this.dom, doc = document;
9495             if(d == doc || d == doc.body){
9496                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9497                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9498                 return {left: l, top: t};
9499             }else{
9500                 return {left: d.scrollLeft, top: d.scrollTop};
9501             }
9502         },
9503
9504         /**
9505          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9506          * are convert to standard 6 digit hex color.
9507          * @param {String} attr The css attribute
9508          * @param {String} defaultValue The default value to use when a valid color isn't found
9509          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9510          * YUI color anims.
9511          */
9512         getColor : function(attr, defaultValue, prefix){
9513             var v = this.getStyle(attr);
9514             if(!v || v == "transparent" || v == "inherit") {
9515                 return defaultValue;
9516             }
9517             var color = typeof prefix == "undefined" ? "#" : prefix;
9518             if(v.substr(0, 4) == "rgb("){
9519                 var rvs = v.slice(4, v.length -1).split(",");
9520                 for(var i = 0; i < 3; i++){
9521                     var h = parseInt(rvs[i]).toString(16);
9522                     if(h < 16){
9523                         h = "0" + h;
9524                     }
9525                     color += h;
9526                 }
9527             } else {
9528                 if(v.substr(0, 1) == "#"){
9529                     if(v.length == 4) {
9530                         for(var i = 1; i < 4; i++){
9531                             var c = v.charAt(i);
9532                             color +=  c + c;
9533                         }
9534                     }else if(v.length == 7){
9535                         color += v.substr(1);
9536                     }
9537                 }
9538             }
9539             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9540         },
9541
9542         /**
9543          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9544          * gradient background, rounded corners and a 4-way shadow.
9545          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9546          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9547          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9548          * @return {Roo.Element} this
9549          */
9550         boxWrap : function(cls){
9551             cls = cls || 'x-box';
9552             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9553             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9554             return el;
9555         },
9556
9557         /**
9558          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9559          * @param {String} namespace The namespace in which to look for the attribute
9560          * @param {String} name The attribute name
9561          * @return {String} The attribute value
9562          */
9563         getAttributeNS : Roo.isIE ? function(ns, name){
9564             var d = this.dom;
9565             var type = typeof d[ns+":"+name];
9566             if(type != 'undefined' && type != 'unknown'){
9567                 return d[ns+":"+name];
9568             }
9569             return d[name];
9570         } : function(ns, name){
9571             var d = this.dom;
9572             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9573         },
9574         
9575         
9576         /**
9577          * Sets or Returns the value the dom attribute value
9578          * @param {String} name The attribute name
9579          * @param {String} value (optional) The value to set the attribute to
9580          * @return {String} The attribute value
9581          */
9582         attr : function(name){
9583             if (arguments.length > 1) {
9584                 this.dom.setAttribute(name, arguments[1]);
9585                 return arguments[1];
9586             }
9587             if (!this.dom.hasAttribute(name)) {
9588                 return undefined;
9589             }
9590             return this.dom.getAttribute(name);
9591         }
9592         
9593         
9594         
9595     };
9596
9597     var ep = El.prototype;
9598
9599     /**
9600      * Appends an event handler (Shorthand for addListener)
9601      * @param {String}   eventName     The type of event to append
9602      * @param {Function} fn        The method the event invokes
9603      * @param {Object} scope       (optional) The scope (this object) of the fn
9604      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9605      * @method
9606      */
9607     ep.on = ep.addListener;
9608         // backwards compat
9609     ep.mon = ep.addListener;
9610
9611     /**
9612      * Removes an event handler from this element (shorthand for removeListener)
9613      * @param {String} eventName the type of event to remove
9614      * @param {Function} fn the method the event invokes
9615      * @return {Roo.Element} this
9616      * @method
9617      */
9618     ep.un = ep.removeListener;
9619
9620     /**
9621      * true to automatically adjust width and height settings for box-model issues (default to true)
9622      */
9623     ep.autoBoxAdjust = true;
9624
9625     // private
9626     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9627
9628     // private
9629     El.addUnits = function(v, defaultUnit){
9630         if(v === "" || v == "auto"){
9631             return v;
9632         }
9633         if(v === undefined){
9634             return '';
9635         }
9636         if(typeof v == "number" || !El.unitPattern.test(v)){
9637             return v + (defaultUnit || 'px');
9638         }
9639         return v;
9640     };
9641
9642     // special markup used throughout Roo when box wrapping elements
9643     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>';
9644     /**
9645      * Visibility mode constant - Use visibility to hide element
9646      * @static
9647      * @type Number
9648      */
9649     El.VISIBILITY = 1;
9650     /**
9651      * Visibility mode constant - Use display to hide element
9652      * @static
9653      * @type Number
9654      */
9655     El.DISPLAY = 2;
9656
9657     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9658     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9659     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9660
9661
9662
9663     /**
9664      * @private
9665      */
9666     El.cache = {};
9667
9668     var docEl;
9669
9670     /**
9671      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9672      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9673      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9674      * @return {Element} The Element object
9675      * @static
9676      */
9677     El.get = function(el){
9678         var ex, elm, id;
9679         if(!el){ return null; }
9680         if(typeof el == "string"){ // element id
9681             if(!(elm = document.getElementById(el))){
9682                 return null;
9683             }
9684             if(ex = El.cache[el]){
9685                 ex.dom = elm;
9686             }else{
9687                 ex = El.cache[el] = new El(elm);
9688             }
9689             return ex;
9690         }else if(el.tagName){ // dom element
9691             if(!(id = el.id)){
9692                 id = Roo.id(el);
9693             }
9694             if(ex = El.cache[id]){
9695                 ex.dom = el;
9696             }else{
9697                 ex = El.cache[id] = new El(el);
9698             }
9699             return ex;
9700         }else if(el instanceof El){
9701             if(el != docEl){
9702                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9703                                                               // catch case where it hasn't been appended
9704                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9705             }
9706             return el;
9707         }else if(el.isComposite){
9708             return el;
9709         }else if(el instanceof Array){
9710             return El.select(el);
9711         }else if(el == document){
9712             // create a bogus element object representing the document object
9713             if(!docEl){
9714                 var f = function(){};
9715                 f.prototype = El.prototype;
9716                 docEl = new f();
9717                 docEl.dom = document;
9718             }
9719             return docEl;
9720         }
9721         return null;
9722     };
9723
9724     // private
9725     El.uncache = function(el){
9726         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9727             if(a[i]){
9728                 delete El.cache[a[i].id || a[i]];
9729             }
9730         }
9731     };
9732
9733     // private
9734     // Garbage collection - uncache elements/purge listeners on orphaned elements
9735     // so we don't hold a reference and cause the browser to retain them
9736     El.garbageCollect = function(){
9737         if(!Roo.enableGarbageCollector){
9738             clearInterval(El.collectorThread);
9739             return;
9740         }
9741         for(var eid in El.cache){
9742             var el = El.cache[eid], d = el.dom;
9743             // -------------------------------------------------------
9744             // Determining what is garbage:
9745             // -------------------------------------------------------
9746             // !d
9747             // dom node is null, definitely garbage
9748             // -------------------------------------------------------
9749             // !d.parentNode
9750             // no parentNode == direct orphan, definitely garbage
9751             // -------------------------------------------------------
9752             // !d.offsetParent && !document.getElementById(eid)
9753             // display none elements have no offsetParent so we will
9754             // also try to look it up by it's id. However, check
9755             // offsetParent first so we don't do unneeded lookups.
9756             // This enables collection of elements that are not orphans
9757             // directly, but somewhere up the line they have an orphan
9758             // parent.
9759             // -------------------------------------------------------
9760             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9761                 delete El.cache[eid];
9762                 if(d && Roo.enableListenerCollection){
9763                     E.purgeElement(d);
9764                 }
9765             }
9766         }
9767     }
9768     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9769
9770
9771     // dom is optional
9772     El.Flyweight = function(dom){
9773         this.dom = dom;
9774     };
9775     El.Flyweight.prototype = El.prototype;
9776
9777     El._flyweights = {};
9778     /**
9779      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9780      * the dom node can be overwritten by other code.
9781      * @param {String/HTMLElement} el The dom node or id
9782      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9783      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9784      * @static
9785      * @return {Element} The shared Element object
9786      */
9787     El.fly = function(el, named){
9788         named = named || '_global';
9789         el = Roo.getDom(el);
9790         if(!el){
9791             return null;
9792         }
9793         if(!El._flyweights[named]){
9794             El._flyweights[named] = new El.Flyweight();
9795         }
9796         El._flyweights[named].dom = el;
9797         return El._flyweights[named];
9798     };
9799
9800     /**
9801      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9802      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9803      * Shorthand of {@link Roo.Element#get}
9804      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9805      * @return {Element} The Element object
9806      * @member Roo
9807      * @method get
9808      */
9809     Roo.get = El.get;
9810     /**
9811      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9812      * the dom node can be overwritten by other code.
9813      * Shorthand of {@link Roo.Element#fly}
9814      * @param {String/HTMLElement} el The dom node or id
9815      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9816      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9817      * @static
9818      * @return {Element} The shared Element object
9819      * @member Roo
9820      * @method fly
9821      */
9822     Roo.fly = El.fly;
9823
9824     // speedy lookup for elements never to box adjust
9825     var noBoxAdjust = Roo.isStrict ? {
9826         select:1
9827     } : {
9828         input:1, select:1, textarea:1
9829     };
9830     if(Roo.isIE || Roo.isGecko){
9831         noBoxAdjust['button'] = 1;
9832     }
9833
9834
9835     Roo.EventManager.on(window, 'unload', function(){
9836         delete El.cache;
9837         delete El._flyweights;
9838     });
9839 })();
9840
9841
9842
9843
9844 if(Roo.DomQuery){
9845     Roo.Element.selectorFunction = Roo.DomQuery.select;
9846 }
9847
9848 Roo.Element.select = function(selector, unique, root){
9849     var els;
9850     if(typeof selector == "string"){
9851         els = Roo.Element.selectorFunction(selector, root);
9852     }else if(selector.length !== undefined){
9853         els = selector;
9854     }else{
9855         throw "Invalid selector";
9856     }
9857     if(unique === true){
9858         return new Roo.CompositeElement(els);
9859     }else{
9860         return new Roo.CompositeElementLite(els);
9861     }
9862 };
9863 /**
9864  * Selects elements based on the passed CSS selector to enable working on them as 1.
9865  * @param {String/Array} selector The CSS selector or an array of elements
9866  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9867  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9868  * @return {CompositeElementLite/CompositeElement}
9869  * @member Roo
9870  * @method select
9871  */
9872 Roo.select = Roo.Element.select;
9873
9874
9875
9876
9877
9878
9879
9880
9881
9882
9883
9884
9885
9886
9887 /*
9888  * Based on:
9889  * Ext JS Library 1.1.1
9890  * Copyright(c) 2006-2007, Ext JS, LLC.
9891  *
9892  * Originally Released Under LGPL - original licence link has changed is not relivant.
9893  *
9894  * Fork - LGPL
9895  * <script type="text/javascript">
9896  */
9897
9898
9899
9900 //Notifies Element that fx methods are available
9901 Roo.enableFx = true;
9902
9903 /**
9904  * @class Roo.Fx
9905  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9906  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9907  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9908  * Element effects to work.</p><br/>
9909  *
9910  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9911  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9912  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9913  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9914  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9915  * expected results and should be done with care.</p><br/>
9916  *
9917  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9918  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9919 <pre>
9920 Value  Description
9921 -----  -----------------------------
9922 tl     The top left corner
9923 t      The center of the top edge
9924 tr     The top right corner
9925 l      The center of the left edge
9926 r      The center of the right edge
9927 bl     The bottom left corner
9928 b      The center of the bottom edge
9929 br     The bottom right corner
9930 </pre>
9931  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9932  * below are common options that can be passed to any Fx method.</b>
9933  * @cfg {Function} callback A function called when the effect is finished
9934  * @cfg {Object} scope The scope of the effect function
9935  * @cfg {String} easing A valid Easing value for the effect
9936  * @cfg {String} afterCls A css class to apply after the effect
9937  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9938  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9939  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9940  * effects that end with the element being visually hidden, ignored otherwise)
9941  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9942  * a function which returns such a specification that will be applied to the Element after the effect finishes
9943  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9944  * @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
9945  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9946  */
9947 Roo.Fx = {
9948         /**
9949          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9950          * origin for the slide effect.  This function automatically handles wrapping the element with
9951          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9952          * Usage:
9953          *<pre><code>
9954 // default: slide the element in from the top
9955 el.slideIn();
9956
9957 // custom: slide the element in from the right with a 2-second duration
9958 el.slideIn('r', { duration: 2 });
9959
9960 // common config options shown with default values
9961 el.slideIn('t', {
9962     easing: 'easeOut',
9963     duration: .5
9964 });
9965 </code></pre>
9966          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9967          * @param {Object} options (optional) Object literal with any of the Fx config options
9968          * @return {Roo.Element} The Element
9969          */
9970     slideIn : function(anchor, o){
9971         var el = this.getFxEl();
9972         o = o || {};
9973
9974         el.queueFx(o, function(){
9975
9976             anchor = anchor || "t";
9977
9978             // fix display to visibility
9979             this.fixDisplay();
9980
9981             // restore values after effect
9982             var r = this.getFxRestore();
9983             var b = this.getBox();
9984             // fixed size for slide
9985             this.setSize(b);
9986
9987             // wrap if needed
9988             var wrap = this.fxWrap(r.pos, o, "hidden");
9989
9990             var st = this.dom.style;
9991             st.visibility = "visible";
9992             st.position = "absolute";
9993
9994             // clear out temp styles after slide and unwrap
9995             var after = function(){
9996                 el.fxUnwrap(wrap, r.pos, o);
9997                 st.width = r.width;
9998                 st.height = r.height;
9999                 el.afterFx(o);
10000             };
10001             // time to calc the positions
10002             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10003
10004             switch(anchor.toLowerCase()){
10005                 case "t":
10006                     wrap.setSize(b.width, 0);
10007                     st.left = st.bottom = "0";
10008                     a = {height: bh};
10009                 break;
10010                 case "l":
10011                     wrap.setSize(0, b.height);
10012                     st.right = st.top = "0";
10013                     a = {width: bw};
10014                 break;
10015                 case "r":
10016                     wrap.setSize(0, b.height);
10017                     wrap.setX(b.right);
10018                     st.left = st.top = "0";
10019                     a = {width: bw, points: pt};
10020                 break;
10021                 case "b":
10022                     wrap.setSize(b.width, 0);
10023                     wrap.setY(b.bottom);
10024                     st.left = st.top = "0";
10025                     a = {height: bh, points: pt};
10026                 break;
10027                 case "tl":
10028                     wrap.setSize(0, 0);
10029                     st.right = st.bottom = "0";
10030                     a = {width: bw, height: bh};
10031                 break;
10032                 case "bl":
10033                     wrap.setSize(0, 0);
10034                     wrap.setY(b.y+b.height);
10035                     st.right = st.top = "0";
10036                     a = {width: bw, height: bh, points: pt};
10037                 break;
10038                 case "br":
10039                     wrap.setSize(0, 0);
10040                     wrap.setXY([b.right, b.bottom]);
10041                     st.left = st.top = "0";
10042                     a = {width: bw, height: bh, points: pt};
10043                 break;
10044                 case "tr":
10045                     wrap.setSize(0, 0);
10046                     wrap.setX(b.x+b.width);
10047                     st.left = st.bottom = "0";
10048                     a = {width: bw, height: bh, points: pt};
10049                 break;
10050             }
10051             this.dom.style.visibility = "visible";
10052             wrap.show();
10053
10054             arguments.callee.anim = wrap.fxanim(a,
10055                 o,
10056                 'motion',
10057                 .5,
10058                 'easeOut', after);
10059         });
10060         return this;
10061     },
10062     
10063         /**
10064          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10065          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10066          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10067          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10068          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10069          * Usage:
10070          *<pre><code>
10071 // default: slide the element out to the top
10072 el.slideOut();
10073
10074 // custom: slide the element out to the right with a 2-second duration
10075 el.slideOut('r', { duration: 2 });
10076
10077 // common config options shown with default values
10078 el.slideOut('t', {
10079     easing: 'easeOut',
10080     duration: .5,
10081     remove: false,
10082     useDisplay: false
10083 });
10084 </code></pre>
10085          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10086          * @param {Object} options (optional) Object literal with any of the Fx config options
10087          * @return {Roo.Element} The Element
10088          */
10089     slideOut : function(anchor, o){
10090         var el = this.getFxEl();
10091         o = o || {};
10092
10093         el.queueFx(o, function(){
10094
10095             anchor = anchor || "t";
10096
10097             // restore values after effect
10098             var r = this.getFxRestore();
10099             
10100             var b = this.getBox();
10101             // fixed size for slide
10102             this.setSize(b);
10103
10104             // wrap if needed
10105             var wrap = this.fxWrap(r.pos, o, "visible");
10106
10107             var st = this.dom.style;
10108             st.visibility = "visible";
10109             st.position = "absolute";
10110
10111             wrap.setSize(b);
10112
10113             var after = function(){
10114                 if(o.useDisplay){
10115                     el.setDisplayed(false);
10116                 }else{
10117                     el.hide();
10118                 }
10119
10120                 el.fxUnwrap(wrap, r.pos, o);
10121
10122                 st.width = r.width;
10123                 st.height = r.height;
10124
10125                 el.afterFx(o);
10126             };
10127
10128             var a, zero = {to: 0};
10129             switch(anchor.toLowerCase()){
10130                 case "t":
10131                     st.left = st.bottom = "0";
10132                     a = {height: zero};
10133                 break;
10134                 case "l":
10135                     st.right = st.top = "0";
10136                     a = {width: zero};
10137                 break;
10138                 case "r":
10139                     st.left = st.top = "0";
10140                     a = {width: zero, points: {to:[b.right, b.y]}};
10141                 break;
10142                 case "b":
10143                     st.left = st.top = "0";
10144                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10145                 break;
10146                 case "tl":
10147                     st.right = st.bottom = "0";
10148                     a = {width: zero, height: zero};
10149                 break;
10150                 case "bl":
10151                     st.right = st.top = "0";
10152                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10153                 break;
10154                 case "br":
10155                     st.left = st.top = "0";
10156                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10157                 break;
10158                 case "tr":
10159                     st.left = st.bottom = "0";
10160                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10161                 break;
10162             }
10163
10164             arguments.callee.anim = wrap.fxanim(a,
10165                 o,
10166                 'motion',
10167                 .5,
10168                 "easeOut", after);
10169         });
10170         return this;
10171     },
10172
10173         /**
10174          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10175          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10176          * The element must be removed from the DOM using the 'remove' config option if desired.
10177          * Usage:
10178          *<pre><code>
10179 // default
10180 el.puff();
10181
10182 // common config options shown with default values
10183 el.puff({
10184     easing: 'easeOut',
10185     duration: .5,
10186     remove: false,
10187     useDisplay: false
10188 });
10189 </code></pre>
10190          * @param {Object} options (optional) Object literal with any of the Fx config options
10191          * @return {Roo.Element} The Element
10192          */
10193     puff : function(o){
10194         var el = this.getFxEl();
10195         o = o || {};
10196
10197         el.queueFx(o, function(){
10198             this.clearOpacity();
10199             this.show();
10200
10201             // restore values after effect
10202             var r = this.getFxRestore();
10203             var st = this.dom.style;
10204
10205             var after = function(){
10206                 if(o.useDisplay){
10207                     el.setDisplayed(false);
10208                 }else{
10209                     el.hide();
10210                 }
10211
10212                 el.clearOpacity();
10213
10214                 el.setPositioning(r.pos);
10215                 st.width = r.width;
10216                 st.height = r.height;
10217                 st.fontSize = '';
10218                 el.afterFx(o);
10219             };
10220
10221             var width = this.getWidth();
10222             var height = this.getHeight();
10223
10224             arguments.callee.anim = this.fxanim({
10225                     width : {to: this.adjustWidth(width * 2)},
10226                     height : {to: this.adjustHeight(height * 2)},
10227                     points : {by: [-(width * .5), -(height * .5)]},
10228                     opacity : {to: 0},
10229                     fontSize: {to:200, unit: "%"}
10230                 },
10231                 o,
10232                 'motion',
10233                 .5,
10234                 "easeOut", after);
10235         });
10236         return this;
10237     },
10238
10239         /**
10240          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10241          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10242          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10243          * Usage:
10244          *<pre><code>
10245 // default
10246 el.switchOff();
10247
10248 // all config options shown with default values
10249 el.switchOff({
10250     easing: 'easeIn',
10251     duration: .3,
10252     remove: false,
10253     useDisplay: false
10254 });
10255 </code></pre>
10256          * @param {Object} options (optional) Object literal with any of the Fx config options
10257          * @return {Roo.Element} The Element
10258          */
10259     switchOff : function(o){
10260         var el = this.getFxEl();
10261         o = o || {};
10262
10263         el.queueFx(o, function(){
10264             this.clearOpacity();
10265             this.clip();
10266
10267             // restore values after effect
10268             var r = this.getFxRestore();
10269             var st = this.dom.style;
10270
10271             var after = function(){
10272                 if(o.useDisplay){
10273                     el.setDisplayed(false);
10274                 }else{
10275                     el.hide();
10276                 }
10277
10278                 el.clearOpacity();
10279                 el.setPositioning(r.pos);
10280                 st.width = r.width;
10281                 st.height = r.height;
10282
10283                 el.afterFx(o);
10284             };
10285
10286             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10287                 this.clearOpacity();
10288                 (function(){
10289                     this.fxanim({
10290                         height:{to:1},
10291                         points:{by:[0, this.getHeight() * .5]}
10292                     }, o, 'motion', 0.3, 'easeIn', after);
10293                 }).defer(100, this);
10294             });
10295         });
10296         return this;
10297     },
10298
10299     /**
10300      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10301      * changed using the "attr" config option) and then fading back to the original color. If no original
10302      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10303      * Usage:
10304 <pre><code>
10305 // default: highlight background to yellow
10306 el.highlight();
10307
10308 // custom: highlight foreground text to blue for 2 seconds
10309 el.highlight("0000ff", { attr: 'color', duration: 2 });
10310
10311 // common config options shown with default values
10312 el.highlight("ffff9c", {
10313     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10314     endColor: (current color) or "ffffff",
10315     easing: 'easeIn',
10316     duration: 1
10317 });
10318 </code></pre>
10319      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10320      * @param {Object} options (optional) Object literal with any of the Fx config options
10321      * @return {Roo.Element} The Element
10322      */ 
10323     highlight : function(color, o){
10324         var el = this.getFxEl();
10325         o = o || {};
10326
10327         el.queueFx(o, function(){
10328             color = color || "ffff9c";
10329             attr = o.attr || "backgroundColor";
10330
10331             this.clearOpacity();
10332             this.show();
10333
10334             var origColor = this.getColor(attr);
10335             var restoreColor = this.dom.style[attr];
10336             endColor = (o.endColor || origColor) || "ffffff";
10337
10338             var after = function(){
10339                 el.dom.style[attr] = restoreColor;
10340                 el.afterFx(o);
10341             };
10342
10343             var a = {};
10344             a[attr] = {from: color, to: endColor};
10345             arguments.callee.anim = this.fxanim(a,
10346                 o,
10347                 'color',
10348                 1,
10349                 'easeIn', after);
10350         });
10351         return this;
10352     },
10353
10354    /**
10355     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10356     * Usage:
10357 <pre><code>
10358 // default: a single light blue ripple
10359 el.frame();
10360
10361 // custom: 3 red ripples lasting 3 seconds total
10362 el.frame("ff0000", 3, { duration: 3 });
10363
10364 // common config options shown with default values
10365 el.frame("C3DAF9", 1, {
10366     duration: 1 //duration of entire animation (not each individual ripple)
10367     // Note: Easing is not configurable and will be ignored if included
10368 });
10369 </code></pre>
10370     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10371     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10372     * @param {Object} options (optional) Object literal with any of the Fx config options
10373     * @return {Roo.Element} The Element
10374     */
10375     frame : function(color, count, o){
10376         var el = this.getFxEl();
10377         o = o || {};
10378
10379         el.queueFx(o, function(){
10380             color = color || "#C3DAF9";
10381             if(color.length == 6){
10382                 color = "#" + color;
10383             }
10384             count = count || 1;
10385             duration = o.duration || 1;
10386             this.show();
10387
10388             var b = this.getBox();
10389             var animFn = function(){
10390                 var proxy = this.createProxy({
10391
10392                      style:{
10393                         visbility:"hidden",
10394                         position:"absolute",
10395                         "z-index":"35000", // yee haw
10396                         border:"0px solid " + color
10397                      }
10398                   });
10399                 var scale = Roo.isBorderBox ? 2 : 1;
10400                 proxy.animate({
10401                     top:{from:b.y, to:b.y - 20},
10402                     left:{from:b.x, to:b.x - 20},
10403                     borderWidth:{from:0, to:10},
10404                     opacity:{from:1, to:0},
10405                     height:{from:b.height, to:(b.height + (20*scale))},
10406                     width:{from:b.width, to:(b.width + (20*scale))}
10407                 }, duration, function(){
10408                     proxy.remove();
10409                 });
10410                 if(--count > 0){
10411                      animFn.defer((duration/2)*1000, this);
10412                 }else{
10413                     el.afterFx(o);
10414                 }
10415             };
10416             animFn.call(this);
10417         });
10418         return this;
10419     },
10420
10421    /**
10422     * Creates a pause before any subsequent queued effects begin.  If there are
10423     * no effects queued after the pause it will have no effect.
10424     * Usage:
10425 <pre><code>
10426 el.pause(1);
10427 </code></pre>
10428     * @param {Number} seconds The length of time to pause (in seconds)
10429     * @return {Roo.Element} The Element
10430     */
10431     pause : function(seconds){
10432         var el = this.getFxEl();
10433         var o = {};
10434
10435         el.queueFx(o, function(){
10436             setTimeout(function(){
10437                 el.afterFx(o);
10438             }, seconds * 1000);
10439         });
10440         return this;
10441     },
10442
10443    /**
10444     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10445     * using the "endOpacity" config option.
10446     * Usage:
10447 <pre><code>
10448 // default: fade in from opacity 0 to 100%
10449 el.fadeIn();
10450
10451 // custom: fade in from opacity 0 to 75% over 2 seconds
10452 el.fadeIn({ endOpacity: .75, duration: 2});
10453
10454 // common config options shown with default values
10455 el.fadeIn({
10456     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10457     easing: 'easeOut',
10458     duration: .5
10459 });
10460 </code></pre>
10461     * @param {Object} options (optional) Object literal with any of the Fx config options
10462     * @return {Roo.Element} The Element
10463     */
10464     fadeIn : function(o){
10465         var el = this.getFxEl();
10466         o = o || {};
10467         el.queueFx(o, function(){
10468             this.setOpacity(0);
10469             this.fixDisplay();
10470             this.dom.style.visibility = 'visible';
10471             var to = o.endOpacity || 1;
10472             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10473                 o, null, .5, "easeOut", function(){
10474                 if(to == 1){
10475                     this.clearOpacity();
10476                 }
10477                 el.afterFx(o);
10478             });
10479         });
10480         return this;
10481     },
10482
10483    /**
10484     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10485     * using the "endOpacity" config option.
10486     * Usage:
10487 <pre><code>
10488 // default: fade out from the element's current opacity to 0
10489 el.fadeOut();
10490
10491 // custom: fade out from the element's current opacity to 25% over 2 seconds
10492 el.fadeOut({ endOpacity: .25, duration: 2});
10493
10494 // common config options shown with default values
10495 el.fadeOut({
10496     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10497     easing: 'easeOut',
10498     duration: .5
10499     remove: false,
10500     useDisplay: false
10501 });
10502 </code></pre>
10503     * @param {Object} options (optional) Object literal with any of the Fx config options
10504     * @return {Roo.Element} The Element
10505     */
10506     fadeOut : function(o){
10507         var el = this.getFxEl();
10508         o = o || {};
10509         el.queueFx(o, function(){
10510             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10511                 o, null, .5, "easeOut", function(){
10512                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10513                      this.dom.style.display = "none";
10514                 }else{
10515                      this.dom.style.visibility = "hidden";
10516                 }
10517                 this.clearOpacity();
10518                 el.afterFx(o);
10519             });
10520         });
10521         return this;
10522     },
10523
10524    /**
10525     * Animates the transition of an element's dimensions from a starting height/width
10526     * to an ending height/width.
10527     * Usage:
10528 <pre><code>
10529 // change height and width to 100x100 pixels
10530 el.scale(100, 100);
10531
10532 // common config options shown with default values.  The height and width will default to
10533 // the element's existing values if passed as null.
10534 el.scale(
10535     [element's width],
10536     [element's height], {
10537     easing: 'easeOut',
10538     duration: .35
10539 });
10540 </code></pre>
10541     * @param {Number} width  The new width (pass undefined to keep the original width)
10542     * @param {Number} height  The new height (pass undefined to keep the original height)
10543     * @param {Object} options (optional) Object literal with any of the Fx config options
10544     * @return {Roo.Element} The Element
10545     */
10546     scale : function(w, h, o){
10547         this.shift(Roo.apply({}, o, {
10548             width: w,
10549             height: h
10550         }));
10551         return this;
10552     },
10553
10554    /**
10555     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10556     * Any of these properties not specified in the config object will not be changed.  This effect 
10557     * requires that at least one new dimension, position or opacity setting must be passed in on
10558     * the config object in order for the function to have any effect.
10559     * Usage:
10560 <pre><code>
10561 // slide the element horizontally to x position 200 while changing the height and opacity
10562 el.shift({ x: 200, height: 50, opacity: .8 });
10563
10564 // common config options shown with default values.
10565 el.shift({
10566     width: [element's width],
10567     height: [element's height],
10568     x: [element's x position],
10569     y: [element's y position],
10570     opacity: [element's opacity],
10571     easing: 'easeOut',
10572     duration: .35
10573 });
10574 </code></pre>
10575     * @param {Object} options  Object literal with any of the Fx config options
10576     * @return {Roo.Element} The Element
10577     */
10578     shift : function(o){
10579         var el = this.getFxEl();
10580         o = o || {};
10581         el.queueFx(o, function(){
10582             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10583             if(w !== undefined){
10584                 a.width = {to: this.adjustWidth(w)};
10585             }
10586             if(h !== undefined){
10587                 a.height = {to: this.adjustHeight(h)};
10588             }
10589             if(x !== undefined || y !== undefined){
10590                 a.points = {to: [
10591                     x !== undefined ? x : this.getX(),
10592                     y !== undefined ? y : this.getY()
10593                 ]};
10594             }
10595             if(op !== undefined){
10596                 a.opacity = {to: op};
10597             }
10598             if(o.xy !== undefined){
10599                 a.points = {to: o.xy};
10600             }
10601             arguments.callee.anim = this.fxanim(a,
10602                 o, 'motion', .35, "easeOut", function(){
10603                 el.afterFx(o);
10604             });
10605         });
10606         return this;
10607     },
10608
10609         /**
10610          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10611          * ending point of the effect.
10612          * Usage:
10613          *<pre><code>
10614 // default: slide the element downward while fading out
10615 el.ghost();
10616
10617 // custom: slide the element out to the right with a 2-second duration
10618 el.ghost('r', { duration: 2 });
10619
10620 // common config options shown with default values
10621 el.ghost('b', {
10622     easing: 'easeOut',
10623     duration: .5
10624     remove: false,
10625     useDisplay: false
10626 });
10627 </code></pre>
10628          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10629          * @param {Object} options (optional) Object literal with any of the Fx config options
10630          * @return {Roo.Element} The Element
10631          */
10632     ghost : function(anchor, o){
10633         var el = this.getFxEl();
10634         o = o || {};
10635
10636         el.queueFx(o, function(){
10637             anchor = anchor || "b";
10638
10639             // restore values after effect
10640             var r = this.getFxRestore();
10641             var w = this.getWidth(),
10642                 h = this.getHeight();
10643
10644             var st = this.dom.style;
10645
10646             var after = function(){
10647                 if(o.useDisplay){
10648                     el.setDisplayed(false);
10649                 }else{
10650                     el.hide();
10651                 }
10652
10653                 el.clearOpacity();
10654                 el.setPositioning(r.pos);
10655                 st.width = r.width;
10656                 st.height = r.height;
10657
10658                 el.afterFx(o);
10659             };
10660
10661             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10662             switch(anchor.toLowerCase()){
10663                 case "t":
10664                     pt.by = [0, -h];
10665                 break;
10666                 case "l":
10667                     pt.by = [-w, 0];
10668                 break;
10669                 case "r":
10670                     pt.by = [w, 0];
10671                 break;
10672                 case "b":
10673                     pt.by = [0, h];
10674                 break;
10675                 case "tl":
10676                     pt.by = [-w, -h];
10677                 break;
10678                 case "bl":
10679                     pt.by = [-w, h];
10680                 break;
10681                 case "br":
10682                     pt.by = [w, h];
10683                 break;
10684                 case "tr":
10685                     pt.by = [w, -h];
10686                 break;
10687             }
10688
10689             arguments.callee.anim = this.fxanim(a,
10690                 o,
10691                 'motion',
10692                 .5,
10693                 "easeOut", after);
10694         });
10695         return this;
10696     },
10697
10698         /**
10699          * Ensures that all effects queued after syncFx is called on the element are
10700          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10701          * @return {Roo.Element} The Element
10702          */
10703     syncFx : function(){
10704         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10705             block : false,
10706             concurrent : true,
10707             stopFx : false
10708         });
10709         return this;
10710     },
10711
10712         /**
10713          * Ensures that all effects queued after sequenceFx is called on the element are
10714          * run in sequence.  This is the opposite of {@link #syncFx}.
10715          * @return {Roo.Element} The Element
10716          */
10717     sequenceFx : function(){
10718         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10719             block : false,
10720             concurrent : false,
10721             stopFx : false
10722         });
10723         return this;
10724     },
10725
10726         /* @private */
10727     nextFx : function(){
10728         var ef = this.fxQueue[0];
10729         if(ef){
10730             ef.call(this);
10731         }
10732     },
10733
10734         /**
10735          * Returns true if the element has any effects actively running or queued, else returns false.
10736          * @return {Boolean} True if element has active effects, else false
10737          */
10738     hasActiveFx : function(){
10739         return this.fxQueue && this.fxQueue[0];
10740     },
10741
10742         /**
10743          * Stops any running effects and clears the element's internal effects queue if it contains
10744          * any additional effects that haven't started yet.
10745          * @return {Roo.Element} The Element
10746          */
10747     stopFx : function(){
10748         if(this.hasActiveFx()){
10749             var cur = this.fxQueue[0];
10750             if(cur && cur.anim && cur.anim.isAnimated()){
10751                 this.fxQueue = [cur]; // clear out others
10752                 cur.anim.stop(true);
10753             }
10754         }
10755         return this;
10756     },
10757
10758         /* @private */
10759     beforeFx : function(o){
10760         if(this.hasActiveFx() && !o.concurrent){
10761            if(o.stopFx){
10762                this.stopFx();
10763                return true;
10764            }
10765            return false;
10766         }
10767         return true;
10768     },
10769
10770         /**
10771          * Returns true if the element is currently blocking so that no other effect can be queued
10772          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10773          * used to ensure that an effect initiated by a user action runs to completion prior to the
10774          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10775          * @return {Boolean} True if blocking, else false
10776          */
10777     hasFxBlock : function(){
10778         var q = this.fxQueue;
10779         return q && q[0] && q[0].block;
10780     },
10781
10782         /* @private */
10783     queueFx : function(o, fn){
10784         if(!this.fxQueue){
10785             this.fxQueue = [];
10786         }
10787         if(!this.hasFxBlock()){
10788             Roo.applyIf(o, this.fxDefaults);
10789             if(!o.concurrent){
10790                 var run = this.beforeFx(o);
10791                 fn.block = o.block;
10792                 this.fxQueue.push(fn);
10793                 if(run){
10794                     this.nextFx();
10795                 }
10796             }else{
10797                 fn.call(this);
10798             }
10799         }
10800         return this;
10801     },
10802
10803         /* @private */
10804     fxWrap : function(pos, o, vis){
10805         var wrap;
10806         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10807             var wrapXY;
10808             if(o.fixPosition){
10809                 wrapXY = this.getXY();
10810             }
10811             var div = document.createElement("div");
10812             div.style.visibility = vis;
10813             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10814             wrap.setPositioning(pos);
10815             if(wrap.getStyle("position") == "static"){
10816                 wrap.position("relative");
10817             }
10818             this.clearPositioning('auto');
10819             wrap.clip();
10820             wrap.dom.appendChild(this.dom);
10821             if(wrapXY){
10822                 wrap.setXY(wrapXY);
10823             }
10824         }
10825         return wrap;
10826     },
10827
10828         /* @private */
10829     fxUnwrap : function(wrap, pos, o){
10830         this.clearPositioning();
10831         this.setPositioning(pos);
10832         if(!o.wrap){
10833             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10834             wrap.remove();
10835         }
10836     },
10837
10838         /* @private */
10839     getFxRestore : function(){
10840         var st = this.dom.style;
10841         return {pos: this.getPositioning(), width: st.width, height : st.height};
10842     },
10843
10844         /* @private */
10845     afterFx : function(o){
10846         if(o.afterStyle){
10847             this.applyStyles(o.afterStyle);
10848         }
10849         if(o.afterCls){
10850             this.addClass(o.afterCls);
10851         }
10852         if(o.remove === true){
10853             this.remove();
10854         }
10855         Roo.callback(o.callback, o.scope, [this]);
10856         if(!o.concurrent){
10857             this.fxQueue.shift();
10858             this.nextFx();
10859         }
10860     },
10861
10862         /* @private */
10863     getFxEl : function(){ // support for composite element fx
10864         return Roo.get(this.dom);
10865     },
10866
10867         /* @private */
10868     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10869         animType = animType || 'run';
10870         opt = opt || {};
10871         var anim = Roo.lib.Anim[animType](
10872             this.dom, args,
10873             (opt.duration || defaultDur) || .35,
10874             (opt.easing || defaultEase) || 'easeOut',
10875             function(){
10876                 Roo.callback(cb, this);
10877             },
10878             this
10879         );
10880         opt.anim = anim;
10881         return anim;
10882     }
10883 };
10884
10885 // backwords compat
10886 Roo.Fx.resize = Roo.Fx.scale;
10887
10888 //When included, Roo.Fx is automatically applied to Element so that all basic
10889 //effects are available directly via the Element API
10890 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10891  * Based on:
10892  * Ext JS Library 1.1.1
10893  * Copyright(c) 2006-2007, Ext JS, LLC.
10894  *
10895  * Originally Released Under LGPL - original licence link has changed is not relivant.
10896  *
10897  * Fork - LGPL
10898  * <script type="text/javascript">
10899  */
10900
10901
10902 /**
10903  * @class Roo.CompositeElement
10904  * Standard composite class. Creates a Roo.Element for every element in the collection.
10905  * <br><br>
10906  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10907  * actions will be performed on all the elements in this collection.</b>
10908  * <br><br>
10909  * All methods return <i>this</i> and can be chained.
10910  <pre><code>
10911  var els = Roo.select("#some-el div.some-class", true);
10912  // or select directly from an existing element
10913  var el = Roo.get('some-el');
10914  el.select('div.some-class', true);
10915
10916  els.setWidth(100); // all elements become 100 width
10917  els.hide(true); // all elements fade out and hide
10918  // or
10919  els.setWidth(100).hide(true);
10920  </code></pre>
10921  */
10922 Roo.CompositeElement = function(els){
10923     this.elements = [];
10924     this.addElements(els);
10925 };
10926 Roo.CompositeElement.prototype = {
10927     isComposite: true,
10928     addElements : function(els){
10929         if(!els) return this;
10930         if(typeof els == "string"){
10931             els = Roo.Element.selectorFunction(els);
10932         }
10933         var yels = this.elements;
10934         var index = yels.length-1;
10935         for(var i = 0, len = els.length; i < len; i++) {
10936                 yels[++index] = Roo.get(els[i]);
10937         }
10938         return this;
10939     },
10940
10941     /**
10942     * Clears this composite and adds the elements returned by the passed selector.
10943     * @param {String/Array} els A string CSS selector, an array of elements or an element
10944     * @return {CompositeElement} this
10945     */
10946     fill : function(els){
10947         this.elements = [];
10948         this.add(els);
10949         return this;
10950     },
10951
10952     /**
10953     * Filters this composite to only elements that match the passed selector.
10954     * @param {String} selector A string CSS selector
10955     * @return {CompositeElement} this
10956     */
10957     filter : function(selector){
10958         var els = [];
10959         this.each(function(el){
10960             if(el.is(selector)){
10961                 els[els.length] = el.dom;
10962             }
10963         });
10964         this.fill(els);
10965         return this;
10966     },
10967
10968     invoke : function(fn, args){
10969         var els = this.elements;
10970         for(var i = 0, len = els.length; i < len; i++) {
10971                 Roo.Element.prototype[fn].apply(els[i], args);
10972         }
10973         return this;
10974     },
10975     /**
10976     * Adds elements to this composite.
10977     * @param {String/Array} els A string CSS selector, an array of elements or an element
10978     * @return {CompositeElement} this
10979     */
10980     add : function(els){
10981         if(typeof els == "string"){
10982             this.addElements(Roo.Element.selectorFunction(els));
10983         }else if(els.length !== undefined){
10984             this.addElements(els);
10985         }else{
10986             this.addElements([els]);
10987         }
10988         return this;
10989     },
10990     /**
10991     * Calls the passed function passing (el, this, index) for each element in this composite.
10992     * @param {Function} fn The function to call
10993     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10994     * @return {CompositeElement} this
10995     */
10996     each : function(fn, scope){
10997         var els = this.elements;
10998         for(var i = 0, len = els.length; i < len; i++){
10999             if(fn.call(scope || els[i], els[i], this, i) === false) {
11000                 break;
11001             }
11002         }
11003         return this;
11004     },
11005
11006     /**
11007      * Returns the Element object at the specified index
11008      * @param {Number} index
11009      * @return {Roo.Element}
11010      */
11011     item : function(index){
11012         return this.elements[index] || null;
11013     },
11014
11015     /**
11016      * Returns the first Element
11017      * @return {Roo.Element}
11018      */
11019     first : function(){
11020         return this.item(0);
11021     },
11022
11023     /**
11024      * Returns the last Element
11025      * @return {Roo.Element}
11026      */
11027     last : function(){
11028         return this.item(this.elements.length-1);
11029     },
11030
11031     /**
11032      * Returns the number of elements in this composite
11033      * @return Number
11034      */
11035     getCount : function(){
11036         return this.elements.length;
11037     },
11038
11039     /**
11040      * Returns true if this composite contains the passed element
11041      * @return Boolean
11042      */
11043     contains : function(el){
11044         return this.indexOf(el) !== -1;
11045     },
11046
11047     /**
11048      * Returns true if this composite contains the passed element
11049      * @return Boolean
11050      */
11051     indexOf : function(el){
11052         return this.elements.indexOf(Roo.get(el));
11053     },
11054
11055
11056     /**
11057     * Removes the specified element(s).
11058     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11059     * or an array of any of those.
11060     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11061     * @return {CompositeElement} this
11062     */
11063     removeElement : function(el, removeDom){
11064         if(el instanceof Array){
11065             for(var i = 0, len = el.length; i < len; i++){
11066                 this.removeElement(el[i]);
11067             }
11068             return this;
11069         }
11070         var index = typeof el == 'number' ? el : this.indexOf(el);
11071         if(index !== -1){
11072             if(removeDom){
11073                 var d = this.elements[index];
11074                 if(d.dom){
11075                     d.remove();
11076                 }else{
11077                     d.parentNode.removeChild(d);
11078                 }
11079             }
11080             this.elements.splice(index, 1);
11081         }
11082         return this;
11083     },
11084
11085     /**
11086     * Replaces the specified element with the passed element.
11087     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11088     * to replace.
11089     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11090     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11091     * @return {CompositeElement} this
11092     */
11093     replaceElement : function(el, replacement, domReplace){
11094         var index = typeof el == 'number' ? el : this.indexOf(el);
11095         if(index !== -1){
11096             if(domReplace){
11097                 this.elements[index].replaceWith(replacement);
11098             }else{
11099                 this.elements.splice(index, 1, Roo.get(replacement))
11100             }
11101         }
11102         return this;
11103     },
11104
11105     /**
11106      * Removes all elements.
11107      */
11108     clear : function(){
11109         this.elements = [];
11110     }
11111 };
11112 (function(){
11113     Roo.CompositeElement.createCall = function(proto, fnName){
11114         if(!proto[fnName]){
11115             proto[fnName] = function(){
11116                 return this.invoke(fnName, arguments);
11117             };
11118         }
11119     };
11120     for(var fnName in Roo.Element.prototype){
11121         if(typeof Roo.Element.prototype[fnName] == "function"){
11122             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11123         }
11124     };
11125 })();
11126 /*
11127  * Based on:
11128  * Ext JS Library 1.1.1
11129  * Copyright(c) 2006-2007, Ext JS, LLC.
11130  *
11131  * Originally Released Under LGPL - original licence link has changed is not relivant.
11132  *
11133  * Fork - LGPL
11134  * <script type="text/javascript">
11135  */
11136
11137 /**
11138  * @class Roo.CompositeElementLite
11139  * @extends Roo.CompositeElement
11140  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11141  <pre><code>
11142  var els = Roo.select("#some-el div.some-class");
11143  // or select directly from an existing element
11144  var el = Roo.get('some-el');
11145  el.select('div.some-class');
11146
11147  els.setWidth(100); // all elements become 100 width
11148  els.hide(true); // all elements fade out and hide
11149  // or
11150  els.setWidth(100).hide(true);
11151  </code></pre><br><br>
11152  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11153  * actions will be performed on all the elements in this collection.</b>
11154  */
11155 Roo.CompositeElementLite = function(els){
11156     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11157     this.el = new Roo.Element.Flyweight();
11158 };
11159 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11160     addElements : function(els){
11161         if(els){
11162             if(els instanceof Array){
11163                 this.elements = this.elements.concat(els);
11164             }else{
11165                 var yels = this.elements;
11166                 var index = yels.length-1;
11167                 for(var i = 0, len = els.length; i < len; i++) {
11168                     yels[++index] = els[i];
11169                 }
11170             }
11171         }
11172         return this;
11173     },
11174     invoke : function(fn, args){
11175         var els = this.elements;
11176         var el = this.el;
11177         for(var i = 0, len = els.length; i < len; i++) {
11178             el.dom = els[i];
11179                 Roo.Element.prototype[fn].apply(el, args);
11180         }
11181         return this;
11182     },
11183     /**
11184      * Returns a flyweight Element of the dom element object at the specified index
11185      * @param {Number} index
11186      * @return {Roo.Element}
11187      */
11188     item : function(index){
11189         if(!this.elements[index]){
11190             return null;
11191         }
11192         this.el.dom = this.elements[index];
11193         return this.el;
11194     },
11195
11196     // fixes scope with flyweight
11197     addListener : function(eventName, handler, scope, opt){
11198         var els = this.elements;
11199         for(var i = 0, len = els.length; i < len; i++) {
11200             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11201         }
11202         return this;
11203     },
11204
11205     /**
11206     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11207     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11208     * a reference to the dom node, use el.dom.</b>
11209     * @param {Function} fn The function to call
11210     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11211     * @return {CompositeElement} this
11212     */
11213     each : function(fn, scope){
11214         var els = this.elements;
11215         var el = this.el;
11216         for(var i = 0, len = els.length; i < len; i++){
11217             el.dom = els[i];
11218                 if(fn.call(scope || el, el, this, i) === false){
11219                 break;
11220             }
11221         }
11222         return this;
11223     },
11224
11225     indexOf : function(el){
11226         return this.elements.indexOf(Roo.getDom(el));
11227     },
11228
11229     replaceElement : function(el, replacement, domReplace){
11230         var index = typeof el == 'number' ? el : this.indexOf(el);
11231         if(index !== -1){
11232             replacement = Roo.getDom(replacement);
11233             if(domReplace){
11234                 var d = this.elements[index];
11235                 d.parentNode.insertBefore(replacement, d);
11236                 d.parentNode.removeChild(d);
11237             }
11238             this.elements.splice(index, 1, replacement);
11239         }
11240         return this;
11241     }
11242 });
11243 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11244
11245 /*
11246  * Based on:
11247  * Ext JS Library 1.1.1
11248  * Copyright(c) 2006-2007, Ext JS, LLC.
11249  *
11250  * Originally Released Under LGPL - original licence link has changed is not relivant.
11251  *
11252  * Fork - LGPL
11253  * <script type="text/javascript">
11254  */
11255
11256  
11257
11258 /**
11259  * @class Roo.data.Connection
11260  * @extends Roo.util.Observable
11261  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11262  * either to a configured URL, or to a URL specified at request time.<br><br>
11263  * <p>
11264  * Requests made by this class are asynchronous, and will return immediately. No data from
11265  * the server will be available to the statement immediately following the {@link #request} call.
11266  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11267  * <p>
11268  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11269  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11270  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11271  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11272  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11273  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11274  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11275  * standard DOM methods.
11276  * @constructor
11277  * @param {Object} config a configuration object.
11278  */
11279 Roo.data.Connection = function(config){
11280     Roo.apply(this, config);
11281     this.addEvents({
11282         /**
11283          * @event beforerequest
11284          * Fires before a network request is made to retrieve a data object.
11285          * @param {Connection} conn This Connection object.
11286          * @param {Object} options The options config object passed to the {@link #request} method.
11287          */
11288         "beforerequest" : true,
11289         /**
11290          * @event requestcomplete
11291          * Fires if the request was successfully completed.
11292          * @param {Connection} conn This Connection object.
11293          * @param {Object} response The XHR object containing the response data.
11294          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11295          * @param {Object} options The options config object passed to the {@link #request} method.
11296          */
11297         "requestcomplete" : true,
11298         /**
11299          * @event requestexception
11300          * Fires if an error HTTP status was returned from the server.
11301          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11302          * @param {Connection} conn This Connection object.
11303          * @param {Object} response The XHR object containing the response data.
11304          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11305          * @param {Object} options The options config object passed to the {@link #request} method.
11306          */
11307         "requestexception" : true
11308     });
11309     Roo.data.Connection.superclass.constructor.call(this);
11310 };
11311
11312 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11313     /**
11314      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11315      */
11316     /**
11317      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11318      * extra parameters to each request made by this object. (defaults to undefined)
11319      */
11320     /**
11321      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11322      *  to each request made by this object. (defaults to undefined)
11323      */
11324     /**
11325      * @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)
11326      */
11327     /**
11328      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11329      */
11330     timeout : 30000,
11331     /**
11332      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11333      * @type Boolean
11334      */
11335     autoAbort:false,
11336
11337     /**
11338      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11339      * @type Boolean
11340      */
11341     disableCaching: true,
11342
11343     /**
11344      * Sends an HTTP request to a remote server.
11345      * @param {Object} options An object which may contain the following properties:<ul>
11346      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11347      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11348      * request, a url encoded string or a function to call to get either.</li>
11349      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11350      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11351      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11352      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11353      * <li>options {Object} The parameter to the request call.</li>
11354      * <li>success {Boolean} True if the request succeeded.</li>
11355      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11356      * </ul></li>
11357      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11358      * The callback is passed the following parameters:<ul>
11359      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11360      * <li>options {Object} The parameter to the request call.</li>
11361      * </ul></li>
11362      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11363      * The callback is passed the following parameters:<ul>
11364      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11365      * <li>options {Object} The parameter to the request call.</li>
11366      * </ul></li>
11367      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11368      * for the callback function. Defaults to the browser window.</li>
11369      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11370      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11371      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11372      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11373      * params for the post data. Any params will be appended to the URL.</li>
11374      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11375      * </ul>
11376      * @return {Number} transactionId
11377      */
11378     request : function(o){
11379         if(this.fireEvent("beforerequest", this, o) !== false){
11380             var p = o.params;
11381
11382             if(typeof p == "function"){
11383                 p = p.call(o.scope||window, o);
11384             }
11385             if(typeof p == "object"){
11386                 p = Roo.urlEncode(o.params);
11387             }
11388             if(this.extraParams){
11389                 var extras = Roo.urlEncode(this.extraParams);
11390                 p = p ? (p + '&' + extras) : extras;
11391             }
11392
11393             var url = o.url || this.url;
11394             if(typeof url == 'function'){
11395                 url = url.call(o.scope||window, o);
11396             }
11397
11398             if(o.form){
11399                 var form = Roo.getDom(o.form);
11400                 url = url || form.action;
11401
11402                 var enctype = form.getAttribute("enctype");
11403                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11404                     return this.doFormUpload(o, p, url);
11405                 }
11406                 var f = Roo.lib.Ajax.serializeForm(form);
11407                 p = p ? (p + '&' + f) : f;
11408             }
11409
11410             var hs = o.headers;
11411             if(this.defaultHeaders){
11412                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11413                 if(!o.headers){
11414                     o.headers = hs;
11415                 }
11416             }
11417
11418             var cb = {
11419                 success: this.handleResponse,
11420                 failure: this.handleFailure,
11421                 scope: this,
11422                 argument: {options: o},
11423                 timeout : o.timeout || this.timeout
11424             };
11425
11426             var method = o.method||this.method||(p ? "POST" : "GET");
11427
11428             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11429                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11430             }
11431
11432             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11433                 if(o.autoAbort){
11434                     this.abort();
11435                 }
11436             }else if(this.autoAbort !== false){
11437                 this.abort();
11438             }
11439
11440             if((method == 'GET' && p) || o.xmlData){
11441                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11442                 p = '';
11443             }
11444             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11445             return this.transId;
11446         }else{
11447             Roo.callback(o.callback, o.scope, [o, null, null]);
11448             return null;
11449         }
11450     },
11451
11452     /**
11453      * Determine whether this object has a request outstanding.
11454      * @param {Number} transactionId (Optional) defaults to the last transaction
11455      * @return {Boolean} True if there is an outstanding request.
11456      */
11457     isLoading : function(transId){
11458         if(transId){
11459             return Roo.lib.Ajax.isCallInProgress(transId);
11460         }else{
11461             return this.transId ? true : false;
11462         }
11463     },
11464
11465     /**
11466      * Aborts any outstanding request.
11467      * @param {Number} transactionId (Optional) defaults to the last transaction
11468      */
11469     abort : function(transId){
11470         if(transId || this.isLoading()){
11471             Roo.lib.Ajax.abort(transId || this.transId);
11472         }
11473     },
11474
11475     // private
11476     handleResponse : function(response){
11477         this.transId = false;
11478         var options = response.argument.options;
11479         response.argument = options ? options.argument : null;
11480         this.fireEvent("requestcomplete", this, response, options);
11481         Roo.callback(options.success, options.scope, [response, options]);
11482         Roo.callback(options.callback, options.scope, [options, true, response]);
11483     },
11484
11485     // private
11486     handleFailure : function(response, e){
11487         this.transId = false;
11488         var options = response.argument.options;
11489         response.argument = options ? options.argument : null;
11490         this.fireEvent("requestexception", this, response, options, e);
11491         Roo.callback(options.failure, options.scope, [response, options]);
11492         Roo.callback(options.callback, options.scope, [options, false, response]);
11493     },
11494
11495     // private
11496     doFormUpload : function(o, ps, url){
11497         var id = Roo.id();
11498         var frame = document.createElement('iframe');
11499         frame.id = id;
11500         frame.name = id;
11501         frame.className = 'x-hidden';
11502         if(Roo.isIE){
11503             frame.src = Roo.SSL_SECURE_URL;
11504         }
11505         document.body.appendChild(frame);
11506
11507         if(Roo.isIE){
11508            document.frames[id].name = id;
11509         }
11510
11511         var form = Roo.getDom(o.form);
11512         form.target = id;
11513         form.method = 'POST';
11514         form.enctype = form.encoding = 'multipart/form-data';
11515         if(url){
11516             form.action = url;
11517         }
11518
11519         var hiddens, hd;
11520         if(ps){ // add dynamic params
11521             hiddens = [];
11522             ps = Roo.urlDecode(ps, false);
11523             for(var k in ps){
11524                 if(ps.hasOwnProperty(k)){
11525                     hd = document.createElement('input');
11526                     hd.type = 'hidden';
11527                     hd.name = k;
11528                     hd.value = ps[k];
11529                     form.appendChild(hd);
11530                     hiddens.push(hd);
11531                 }
11532             }
11533         }
11534
11535         function cb(){
11536             var r = {  // bogus response object
11537                 responseText : '',
11538                 responseXML : null
11539             };
11540
11541             r.argument = o ? o.argument : null;
11542
11543             try { //
11544                 var doc;
11545                 if(Roo.isIE){
11546                     doc = frame.contentWindow.document;
11547                 }else {
11548                     doc = (frame.contentDocument || window.frames[id].document);
11549                 }
11550                 if(doc && doc.body){
11551                     r.responseText = doc.body.innerHTML;
11552                 }
11553                 if(doc && doc.XMLDocument){
11554                     r.responseXML = doc.XMLDocument;
11555                 }else {
11556                     r.responseXML = doc;
11557                 }
11558             }
11559             catch(e) {
11560                 // ignore
11561             }
11562
11563             Roo.EventManager.removeListener(frame, 'load', cb, this);
11564
11565             this.fireEvent("requestcomplete", this, r, o);
11566             Roo.callback(o.success, o.scope, [r, o]);
11567             Roo.callback(o.callback, o.scope, [o, true, r]);
11568
11569             setTimeout(function(){document.body.removeChild(frame);}, 100);
11570         }
11571
11572         Roo.EventManager.on(frame, 'load', cb, this);
11573         form.submit();
11574
11575         if(hiddens){ // remove dynamic params
11576             for(var i = 0, len = hiddens.length; i < len; i++){
11577                 form.removeChild(hiddens[i]);
11578             }
11579         }
11580     }
11581 });
11582 /*
11583  * Based on:
11584  * Ext JS Library 1.1.1
11585  * Copyright(c) 2006-2007, Ext JS, LLC.
11586  *
11587  * Originally Released Under LGPL - original licence link has changed is not relivant.
11588  *
11589  * Fork - LGPL
11590  * <script type="text/javascript">
11591  */
11592  
11593 /**
11594  * Global Ajax request class.
11595  * 
11596  * @class Roo.Ajax
11597  * @extends Roo.data.Connection
11598  * @static
11599  * 
11600  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11601  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11602  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11603  * @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)
11604  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11605  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11606  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11607  */
11608 Roo.Ajax = new Roo.data.Connection({
11609     // fix up the docs
11610     /**
11611      * @scope Roo.Ajax
11612      * @type {Boolear} 
11613      */
11614     autoAbort : false,
11615
11616     /**
11617      * Serialize the passed form into a url encoded string
11618      * @scope Roo.Ajax
11619      * @param {String/HTMLElement} form
11620      * @return {String}
11621      */
11622     serializeForm : function(form){
11623         return Roo.lib.Ajax.serializeForm(form);
11624     }
11625 });/*
11626  * Based on:
11627  * Ext JS Library 1.1.1
11628  * Copyright(c) 2006-2007, Ext JS, LLC.
11629  *
11630  * Originally Released Under LGPL - original licence link has changed is not relivant.
11631  *
11632  * Fork - LGPL
11633  * <script type="text/javascript">
11634  */
11635
11636  
11637 /**
11638  * @class Roo.UpdateManager
11639  * @extends Roo.util.Observable
11640  * Provides AJAX-style update for Element object.<br><br>
11641  * Usage:<br>
11642  * <pre><code>
11643  * // Get it from a Roo.Element object
11644  * var el = Roo.get("foo");
11645  * var mgr = el.getUpdateManager();
11646  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11647  * ...
11648  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11649  * <br>
11650  * // or directly (returns the same UpdateManager instance)
11651  * var mgr = new Roo.UpdateManager("myElementId");
11652  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11653  * mgr.on("update", myFcnNeedsToKnow);
11654  * <br>
11655    // short handed call directly from the element object
11656    Roo.get("foo").load({
11657         url: "bar.php",
11658         scripts:true,
11659         params: "for=bar",
11660         text: "Loading Foo..."
11661    });
11662  * </code></pre>
11663  * @constructor
11664  * Create new UpdateManager directly.
11665  * @param {String/HTMLElement/Roo.Element} el The element to update
11666  * @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).
11667  */
11668 Roo.UpdateManager = function(el, forceNew){
11669     el = Roo.get(el);
11670     if(!forceNew && el.updateManager){
11671         return el.updateManager;
11672     }
11673     /**
11674      * The Element object
11675      * @type Roo.Element
11676      */
11677     this.el = el;
11678     /**
11679      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11680      * @type String
11681      */
11682     this.defaultUrl = null;
11683
11684     this.addEvents({
11685         /**
11686          * @event beforeupdate
11687          * Fired before an update is made, return false from your handler and the update is cancelled.
11688          * @param {Roo.Element} el
11689          * @param {String/Object/Function} url
11690          * @param {String/Object} params
11691          */
11692         "beforeupdate": true,
11693         /**
11694          * @event update
11695          * Fired after successful update is made.
11696          * @param {Roo.Element} el
11697          * @param {Object} oResponseObject The response Object
11698          */
11699         "update": true,
11700         /**
11701          * @event failure
11702          * Fired on update failure.
11703          * @param {Roo.Element} el
11704          * @param {Object} oResponseObject The response Object
11705          */
11706         "failure": true
11707     });
11708     var d = Roo.UpdateManager.defaults;
11709     /**
11710      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11711      * @type String
11712      */
11713     this.sslBlankUrl = d.sslBlankUrl;
11714     /**
11715      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11716      * @type Boolean
11717      */
11718     this.disableCaching = d.disableCaching;
11719     /**
11720      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11721      * @type String
11722      */
11723     this.indicatorText = d.indicatorText;
11724     /**
11725      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11726      * @type String
11727      */
11728     this.showLoadIndicator = d.showLoadIndicator;
11729     /**
11730      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11731      * @type Number
11732      */
11733     this.timeout = d.timeout;
11734
11735     /**
11736      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11737      * @type Boolean
11738      */
11739     this.loadScripts = d.loadScripts;
11740
11741     /**
11742      * Transaction object of current executing transaction
11743      */
11744     this.transaction = null;
11745
11746     /**
11747      * @private
11748      */
11749     this.autoRefreshProcId = null;
11750     /**
11751      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11752      * @type Function
11753      */
11754     this.refreshDelegate = this.refresh.createDelegate(this);
11755     /**
11756      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11757      * @type Function
11758      */
11759     this.updateDelegate = this.update.createDelegate(this);
11760     /**
11761      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11762      * @type Function
11763      */
11764     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11765     /**
11766      * @private
11767      */
11768     this.successDelegate = this.processSuccess.createDelegate(this);
11769     /**
11770      * @private
11771      */
11772     this.failureDelegate = this.processFailure.createDelegate(this);
11773
11774     if(!this.renderer){
11775      /**
11776       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11777       */
11778     this.renderer = new Roo.UpdateManager.BasicRenderer();
11779     }
11780     
11781     Roo.UpdateManager.superclass.constructor.call(this);
11782 };
11783
11784 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11785     /**
11786      * Get the Element this UpdateManager is bound to
11787      * @return {Roo.Element} The element
11788      */
11789     getEl : function(){
11790         return this.el;
11791     },
11792     /**
11793      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11794      * @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:
11795 <pre><code>
11796 um.update({<br/>
11797     url: "your-url.php",<br/>
11798     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11799     callback: yourFunction,<br/>
11800     scope: yourObject, //(optional scope)  <br/>
11801     discardUrl: false, <br/>
11802     nocache: false,<br/>
11803     text: "Loading...",<br/>
11804     timeout: 30,<br/>
11805     scripts: false<br/>
11806 });
11807 </code></pre>
11808      * The only required property is url. The optional properties nocache, text and scripts
11809      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11810      * @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}
11811      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11812      * @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.
11813      */
11814     update : function(url, params, callback, discardUrl){
11815         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11816             var method = this.method,
11817                 cfg;
11818             if(typeof url == "object"){ // must be config object
11819                 cfg = url;
11820                 url = cfg.url;
11821                 params = params || cfg.params;
11822                 callback = callback || cfg.callback;
11823                 discardUrl = discardUrl || cfg.discardUrl;
11824                 if(callback && cfg.scope){
11825                     callback = callback.createDelegate(cfg.scope);
11826                 }
11827                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11828                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11829                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11830                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11831                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11832             }
11833             this.showLoading();
11834             if(!discardUrl){
11835                 this.defaultUrl = url;
11836             }
11837             if(typeof url == "function"){
11838                 url = url.call(this);
11839             }
11840
11841             method = method || (params ? "POST" : "GET");
11842             if(method == "GET"){
11843                 url = this.prepareUrl(url);
11844             }
11845
11846             var o = Roo.apply(cfg ||{}, {
11847                 url : url,
11848                 params: params,
11849                 success: this.successDelegate,
11850                 failure: this.failureDelegate,
11851                 callback: undefined,
11852                 timeout: (this.timeout*1000),
11853                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11854             });
11855             Roo.log("updated manager called with timeout of " + o.timeout);
11856             this.transaction = Roo.Ajax.request(o);
11857         }
11858     },
11859
11860     /**
11861      * 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.
11862      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11863      * @param {String/HTMLElement} form The form Id or form element
11864      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11865      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11866      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11867      */
11868     formUpdate : function(form, url, reset, callback){
11869         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11870             if(typeof url == "function"){
11871                 url = url.call(this);
11872             }
11873             form = Roo.getDom(form);
11874             this.transaction = Roo.Ajax.request({
11875                 form: form,
11876                 url:url,
11877                 success: this.successDelegate,
11878                 failure: this.failureDelegate,
11879                 timeout: (this.timeout*1000),
11880                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11881             });
11882             this.showLoading.defer(1, this);
11883         }
11884     },
11885
11886     /**
11887      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11888      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11889      */
11890     refresh : function(callback){
11891         if(this.defaultUrl == null){
11892             return;
11893         }
11894         this.update(this.defaultUrl, null, callback, true);
11895     },
11896
11897     /**
11898      * Set this element to auto refresh.
11899      * @param {Number} interval How often to update (in seconds).
11900      * @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)
11901      * @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}
11902      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11903      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11904      */
11905     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11906         if(refreshNow){
11907             this.update(url || this.defaultUrl, params, callback, true);
11908         }
11909         if(this.autoRefreshProcId){
11910             clearInterval(this.autoRefreshProcId);
11911         }
11912         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11913     },
11914
11915     /**
11916      * Stop auto refresh on this element.
11917      */
11918      stopAutoRefresh : function(){
11919         if(this.autoRefreshProcId){
11920             clearInterval(this.autoRefreshProcId);
11921             delete this.autoRefreshProcId;
11922         }
11923     },
11924
11925     isAutoRefreshing : function(){
11926        return this.autoRefreshProcId ? true : false;
11927     },
11928     /**
11929      * Called to update the element to "Loading" state. Override to perform custom action.
11930      */
11931     showLoading : function(){
11932         if(this.showLoadIndicator){
11933             this.el.update(this.indicatorText);
11934         }
11935     },
11936
11937     /**
11938      * Adds unique parameter to query string if disableCaching = true
11939      * @private
11940      */
11941     prepareUrl : function(url){
11942         if(this.disableCaching){
11943             var append = "_dc=" + (new Date().getTime());
11944             if(url.indexOf("?") !== -1){
11945                 url += "&" + append;
11946             }else{
11947                 url += "?" + append;
11948             }
11949         }
11950         return url;
11951     },
11952
11953     /**
11954      * @private
11955      */
11956     processSuccess : function(response){
11957         this.transaction = null;
11958         if(response.argument.form && response.argument.reset){
11959             try{ // put in try/catch since some older FF releases had problems with this
11960                 response.argument.form.reset();
11961             }catch(e){}
11962         }
11963         if(this.loadScripts){
11964             this.renderer.render(this.el, response, this,
11965                 this.updateComplete.createDelegate(this, [response]));
11966         }else{
11967             this.renderer.render(this.el, response, this);
11968             this.updateComplete(response);
11969         }
11970     },
11971
11972     updateComplete : function(response){
11973         this.fireEvent("update", this.el, response);
11974         if(typeof response.argument.callback == "function"){
11975             response.argument.callback(this.el, true, response);
11976         }
11977     },
11978
11979     /**
11980      * @private
11981      */
11982     processFailure : function(response){
11983         this.transaction = null;
11984         this.fireEvent("failure", this.el, response);
11985         if(typeof response.argument.callback == "function"){
11986             response.argument.callback(this.el, false, response);
11987         }
11988     },
11989
11990     /**
11991      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11992      * @param {Object} renderer The object implementing the render() method
11993      */
11994     setRenderer : function(renderer){
11995         this.renderer = renderer;
11996     },
11997
11998     getRenderer : function(){
11999        return this.renderer;
12000     },
12001
12002     /**
12003      * Set the defaultUrl used for updates
12004      * @param {String/Function} defaultUrl The url or a function to call to get the url
12005      */
12006     setDefaultUrl : function(defaultUrl){
12007         this.defaultUrl = defaultUrl;
12008     },
12009
12010     /**
12011      * Aborts the executing transaction
12012      */
12013     abort : function(){
12014         if(this.transaction){
12015             Roo.Ajax.abort(this.transaction);
12016         }
12017     },
12018
12019     /**
12020      * Returns true if an update is in progress
12021      * @return {Boolean}
12022      */
12023     isUpdating : function(){
12024         if(this.transaction){
12025             return Roo.Ajax.isLoading(this.transaction);
12026         }
12027         return false;
12028     }
12029 });
12030
12031 /**
12032  * @class Roo.UpdateManager.defaults
12033  * @static (not really - but it helps the doc tool)
12034  * The defaults collection enables customizing the default properties of UpdateManager
12035  */
12036    Roo.UpdateManager.defaults = {
12037        /**
12038          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12039          * @type Number
12040          */
12041          timeout : 30,
12042
12043          /**
12044          * True to process scripts by default (Defaults to false).
12045          * @type Boolean
12046          */
12047         loadScripts : false,
12048
12049         /**
12050         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12051         * @type String
12052         */
12053         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12054         /**
12055          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12056          * @type Boolean
12057          */
12058         disableCaching : false,
12059         /**
12060          * Whether to show indicatorText when loading (Defaults to true).
12061          * @type Boolean
12062          */
12063         showLoadIndicator : true,
12064         /**
12065          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12066          * @type String
12067          */
12068         indicatorText : '<div class="loading-indicator">Loading...</div>'
12069    };
12070
12071 /**
12072  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12073  *Usage:
12074  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12075  * @param {String/HTMLElement/Roo.Element} el The element to update
12076  * @param {String} url The url
12077  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12078  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12079  * @static
12080  * @deprecated
12081  * @member Roo.UpdateManager
12082  */
12083 Roo.UpdateManager.updateElement = function(el, url, params, options){
12084     var um = Roo.get(el, true).getUpdateManager();
12085     Roo.apply(um, options);
12086     um.update(url, params, options ? options.callback : null);
12087 };
12088 // alias for backwards compat
12089 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12090 /**
12091  * @class Roo.UpdateManager.BasicRenderer
12092  * Default Content renderer. Updates the elements innerHTML with the responseText.
12093  */
12094 Roo.UpdateManager.BasicRenderer = function(){};
12095
12096 Roo.UpdateManager.BasicRenderer.prototype = {
12097     /**
12098      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12099      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12100      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12101      * @param {Roo.Element} el The element being rendered
12102      * @param {Object} response The YUI Connect response object
12103      * @param {UpdateManager} updateManager The calling update manager
12104      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12105      */
12106      render : function(el, response, updateManager, callback){
12107         el.update(response.responseText, updateManager.loadScripts, callback);
12108     }
12109 };
12110 /*
12111  * Based on:
12112  * Roo JS
12113  * (c)) Alan Knowles
12114  * Licence : LGPL
12115  */
12116
12117
12118 /**
12119  * @class Roo.DomTemplate
12120  * @extends Roo.Template
12121  * An effort at a dom based template engine..
12122  *
12123  * Similar to XTemplate, except it uses dom parsing to create the template..
12124  *
12125  * Supported features:
12126  *
12127  *  Tags:
12128
12129 <pre><code>
12130       {a_variable} - output encoded.
12131       {a_variable.format:("Y-m-d")} - call a method on the variable
12132       {a_variable:raw} - unencoded output
12133       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12134       {a_variable:this.method_on_template(...)} - call a method on the template object.
12135  
12136 </code></pre>
12137  *  The tpl tag:
12138 <pre><code>
12139         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12140         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12141         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12142         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12143   
12144 </code></pre>
12145  *      
12146  */
12147 Roo.DomTemplate = function()
12148 {
12149      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12150      if (this.html) {
12151         this.compile();
12152      }
12153 };
12154
12155
12156 Roo.extend(Roo.DomTemplate, Roo.Template, {
12157     /**
12158      * id counter for sub templates.
12159      */
12160     id : 0,
12161     /**
12162      * flag to indicate if dom parser is inside a pre,
12163      * it will strip whitespace if not.
12164      */
12165     inPre : false,
12166     
12167     /**
12168      * The various sub templates
12169      */
12170     tpls : false,
12171     
12172     
12173     
12174     /**
12175      *
12176      * basic tag replacing syntax
12177      * WORD:WORD()
12178      *
12179      * // you can fake an object call by doing this
12180      *  x.t:(test,tesT) 
12181      * 
12182      */
12183     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12184     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12185     
12186     iterChild : function (node, method) {
12187         
12188         var oldPre = this.inPre;
12189         if (node.tagName == 'PRE') {
12190             this.inPre = true;
12191         }
12192         for( var i = 0; i < node.childNodes.length; i++) {
12193             method.call(this, node.childNodes[i]);
12194         }
12195         this.inPre = oldPre;
12196     },
12197     
12198     
12199     
12200     /**
12201      * compile the template
12202      *
12203      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12204      *
12205      */
12206     compile: function()
12207     {
12208         var s = this.html;
12209         
12210         // covert the html into DOM...
12211         var doc = false;
12212         var div =false;
12213         try {
12214             doc = document.implementation.createHTMLDocument("");
12215             doc.documentElement.innerHTML =   this.html  ;
12216             div = doc.documentElement;
12217         } catch (e) {
12218             // old IE... - nasty -- it causes all sorts of issues.. with
12219             // images getting pulled from server..
12220             div = document.createElement('div');
12221             div.innerHTML = this.html;
12222         }
12223         //doc.documentElement.innerHTML = htmlBody
12224          
12225         
12226         
12227         this.tpls = [];
12228         var _t = this;
12229         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12230         
12231         var tpls = this.tpls;
12232         
12233         // create a top level template from the snippet..
12234         
12235         //Roo.log(div.innerHTML);
12236         
12237         var tpl = {
12238             uid : 'master',
12239             id : this.id++,
12240             attr : false,
12241             value : false,
12242             body : div.innerHTML,
12243             
12244             forCall : false,
12245             execCall : false,
12246             dom : div,
12247             isTop : true
12248             
12249         };
12250         tpls.unshift(tpl);
12251         
12252         
12253         // compile them...
12254         this.tpls = [];
12255         Roo.each(tpls, function(tp){
12256             this.compileTpl(tp);
12257             this.tpls[tp.id] = tp;
12258         }, this);
12259         
12260         this.master = tpls[0];
12261         return this;
12262         
12263         
12264     },
12265     
12266     compileNode : function(node, istop) {
12267         // test for
12268         //Roo.log(node);
12269         
12270         
12271         // skip anything not a tag..
12272         if (node.nodeType != 1) {
12273             if (node.nodeType == 3 && !this.inPre) {
12274                 // reduce white space..
12275                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12276                 
12277             }
12278             return;
12279         }
12280         
12281         var tpl = {
12282             uid : false,
12283             id : false,
12284             attr : false,
12285             value : false,
12286             body : '',
12287             
12288             forCall : false,
12289             execCall : false,
12290             dom : false,
12291             isTop : istop
12292             
12293             
12294         };
12295         
12296         
12297         switch(true) {
12298             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12299             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12300             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12301             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12302             // no default..
12303         }
12304         
12305         
12306         if (!tpl.attr) {
12307             // just itterate children..
12308             this.iterChild(node,this.compileNode);
12309             return;
12310         }
12311         tpl.uid = this.id++;
12312         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12313         node.removeAttribute('roo-'+ tpl.attr);
12314         if (tpl.attr != 'name') {
12315             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12316             node.parentNode.replaceChild(placeholder,  node);
12317         } else {
12318             
12319             var placeholder =  document.createElement('span');
12320             placeholder.className = 'roo-tpl-' + tpl.value;
12321             node.parentNode.replaceChild(placeholder,  node);
12322         }
12323         
12324         // parent now sees '{domtplXXXX}
12325         this.iterChild(node,this.compileNode);
12326         
12327         // we should now have node body...
12328         var div = document.createElement('div');
12329         div.appendChild(node);
12330         tpl.dom = node;
12331         // this has the unfortunate side effect of converting tagged attributes
12332         // eg. href="{...}" into %7C...%7D
12333         // this has been fixed by searching for those combo's although it's a bit hacky..
12334         
12335         
12336         tpl.body = div.innerHTML;
12337         
12338         
12339          
12340         tpl.id = tpl.uid;
12341         switch(tpl.attr) {
12342             case 'for' :
12343                 switch (tpl.value) {
12344                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12345                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12346                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12347                 }
12348                 break;
12349             
12350             case 'exec':
12351                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12352                 break;
12353             
12354             case 'if':     
12355                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12356                 break;
12357             
12358             case 'name':
12359                 tpl.id  = tpl.value; // replace non characters???
12360                 break;
12361             
12362         }
12363         
12364         
12365         this.tpls.push(tpl);
12366         
12367         
12368         
12369     },
12370     
12371     
12372     
12373     
12374     /**
12375      * Compile a segment of the template into a 'sub-template'
12376      *
12377      * 
12378      * 
12379      *
12380      */
12381     compileTpl : function(tpl)
12382     {
12383         var fm = Roo.util.Format;
12384         var useF = this.disableFormats !== true;
12385         
12386         var sep = Roo.isGecko ? "+\n" : ",\n";
12387         
12388         var undef = function(str) {
12389             Roo.debug && Roo.log("Property not found :"  + str);
12390             return '';
12391         };
12392           
12393         //Roo.log(tpl.body);
12394         
12395         
12396         
12397         var fn = function(m, lbrace, name, format, args)
12398         {
12399             //Roo.log("ARGS");
12400             //Roo.log(arguments);
12401             args = args ? args.replace(/\\'/g,"'") : args;
12402             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12403             if (typeof(format) == 'undefined') {
12404                 format =  'htmlEncode'; 
12405             }
12406             if (format == 'raw' ) {
12407                 format = false;
12408             }
12409             
12410             if(name.substr(0, 6) == 'domtpl'){
12411                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12412             }
12413             
12414             // build an array of options to determine if value is undefined..
12415             
12416             // basically get 'xxxx.yyyy' then do
12417             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12418             //    (function () { Roo.log("Property not found"); return ''; })() :
12419             //    ......
12420             
12421             var udef_ar = [];
12422             var lookfor = '';
12423             Roo.each(name.split('.'), function(st) {
12424                 lookfor += (lookfor.length ? '.': '') + st;
12425                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12426             });
12427             
12428             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12429             
12430             
12431             if(format && useF){
12432                 
12433                 args = args ? ',' + args : "";
12434                  
12435                 if(format.substr(0, 5) != "this."){
12436                     format = "fm." + format + '(';
12437                 }else{
12438                     format = 'this.call("'+ format.substr(5) + '", ';
12439                     args = ", values";
12440                 }
12441                 
12442                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12443             }
12444              
12445             if (args && args.length) {
12446                 // called with xxyx.yuu:(test,test)
12447                 // change to ()
12448                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12449             }
12450             // raw.. - :raw modifier..
12451             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12452             
12453         };
12454         var body;
12455         // branched to use + in gecko and [].join() in others
12456         if(Roo.isGecko){
12457             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12458                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12459                     "';};};";
12460         }else{
12461             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12462             body.push(tpl.body.replace(/(\r\n|\n)/g,
12463                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12464             body.push("'].join('');};};");
12465             body = body.join('');
12466         }
12467         
12468         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12469        
12470         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12471         eval(body);
12472         
12473         return this;
12474     },
12475      
12476     /**
12477      * same as applyTemplate, except it's done to one of the subTemplates
12478      * when using named templates, you can do:
12479      *
12480      * var str = pl.applySubTemplate('your-name', values);
12481      *
12482      * 
12483      * @param {Number} id of the template
12484      * @param {Object} values to apply to template
12485      * @param {Object} parent (normaly the instance of this object)
12486      */
12487     applySubTemplate : function(id, values, parent)
12488     {
12489         
12490         
12491         var t = this.tpls[id];
12492         
12493         
12494         try { 
12495             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12496                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12497                 return '';
12498             }
12499         } catch(e) {
12500             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12501             Roo.log(values);
12502           
12503             return '';
12504         }
12505         try { 
12506             
12507             if(t.execCall && t.execCall.call(this, values, parent)){
12508                 return '';
12509             }
12510         } catch(e) {
12511             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12512             Roo.log(values);
12513             return '';
12514         }
12515         
12516         try {
12517             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12518             parent = t.target ? values : parent;
12519             if(t.forCall && vs instanceof Array){
12520                 var buf = [];
12521                 for(var i = 0, len = vs.length; i < len; i++){
12522                     try {
12523                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12524                     } catch (e) {
12525                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12526                         Roo.log(e.body);
12527                         //Roo.log(t.compiled);
12528                         Roo.log(vs[i]);
12529                     }   
12530                 }
12531                 return buf.join('');
12532             }
12533         } catch (e) {
12534             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12535             Roo.log(values);
12536             return '';
12537         }
12538         try {
12539             return t.compiled.call(this, vs, parent);
12540         } catch (e) {
12541             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12542             Roo.log(e.body);
12543             //Roo.log(t.compiled);
12544             Roo.log(values);
12545             return '';
12546         }
12547     },
12548
12549    
12550
12551     applyTemplate : function(values){
12552         return this.master.compiled.call(this, values, {});
12553         //var s = this.subs;
12554     },
12555
12556     apply : function(){
12557         return this.applyTemplate.apply(this, arguments);
12558     }
12559
12560  });
12561
12562 Roo.DomTemplate.from = function(el){
12563     el = Roo.getDom(el);
12564     return new Roo.Domtemplate(el.value || el.innerHTML);
12565 };/*
12566  * Based on:
12567  * Ext JS Library 1.1.1
12568  * Copyright(c) 2006-2007, Ext JS, LLC.
12569  *
12570  * Originally Released Under LGPL - original licence link has changed is not relivant.
12571  *
12572  * Fork - LGPL
12573  * <script type="text/javascript">
12574  */
12575
12576 /**
12577  * @class Roo.util.DelayedTask
12578  * Provides a convenient method of performing setTimeout where a new
12579  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12580  * You can use this class to buffer
12581  * the keypress events for a certain number of milliseconds, and perform only if they stop
12582  * for that amount of time.
12583  * @constructor The parameters to this constructor serve as defaults and are not required.
12584  * @param {Function} fn (optional) The default function to timeout
12585  * @param {Object} scope (optional) The default scope of that timeout
12586  * @param {Array} args (optional) The default Array of arguments
12587  */
12588 Roo.util.DelayedTask = function(fn, scope, args){
12589     var id = null, d, t;
12590
12591     var call = function(){
12592         var now = new Date().getTime();
12593         if(now - t >= d){
12594             clearInterval(id);
12595             id = null;
12596             fn.apply(scope, args || []);
12597         }
12598     };
12599     /**
12600      * Cancels any pending timeout and queues a new one
12601      * @param {Number} delay The milliseconds to delay
12602      * @param {Function} newFn (optional) Overrides function passed to constructor
12603      * @param {Object} newScope (optional) Overrides scope passed to constructor
12604      * @param {Array} newArgs (optional) Overrides args passed to constructor
12605      */
12606     this.delay = function(delay, newFn, newScope, newArgs){
12607         if(id && delay != d){
12608             this.cancel();
12609         }
12610         d = delay;
12611         t = new Date().getTime();
12612         fn = newFn || fn;
12613         scope = newScope || scope;
12614         args = newArgs || args;
12615         if(!id){
12616             id = setInterval(call, d);
12617         }
12618     };
12619
12620     /**
12621      * Cancel the last queued timeout
12622      */
12623     this.cancel = function(){
12624         if(id){
12625             clearInterval(id);
12626             id = null;
12627         }
12628     };
12629 };/*
12630  * Based on:
12631  * Ext JS Library 1.1.1
12632  * Copyright(c) 2006-2007, Ext JS, LLC.
12633  *
12634  * Originally Released Under LGPL - original licence link has changed is not relivant.
12635  *
12636  * Fork - LGPL
12637  * <script type="text/javascript">
12638  */
12639  
12640  
12641 Roo.util.TaskRunner = function(interval){
12642     interval = interval || 10;
12643     var tasks = [], removeQueue = [];
12644     var id = 0;
12645     var running = false;
12646
12647     var stopThread = function(){
12648         running = false;
12649         clearInterval(id);
12650         id = 0;
12651     };
12652
12653     var startThread = function(){
12654         if(!running){
12655             running = true;
12656             id = setInterval(runTasks, interval);
12657         }
12658     };
12659
12660     var removeTask = function(task){
12661         removeQueue.push(task);
12662         if(task.onStop){
12663             task.onStop();
12664         }
12665     };
12666
12667     var runTasks = function(){
12668         if(removeQueue.length > 0){
12669             for(var i = 0, len = removeQueue.length; i < len; i++){
12670                 tasks.remove(removeQueue[i]);
12671             }
12672             removeQueue = [];
12673             if(tasks.length < 1){
12674                 stopThread();
12675                 return;
12676             }
12677         }
12678         var now = new Date().getTime();
12679         for(var i = 0, len = tasks.length; i < len; ++i){
12680             var t = tasks[i];
12681             var itime = now - t.taskRunTime;
12682             if(t.interval <= itime){
12683                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12684                 t.taskRunTime = now;
12685                 if(rt === false || t.taskRunCount === t.repeat){
12686                     removeTask(t);
12687                     return;
12688                 }
12689             }
12690             if(t.duration && t.duration <= (now - t.taskStartTime)){
12691                 removeTask(t);
12692             }
12693         }
12694     };
12695
12696     /**
12697      * Queues a new task.
12698      * @param {Object} task
12699      */
12700     this.start = function(task){
12701         tasks.push(task);
12702         task.taskStartTime = new Date().getTime();
12703         task.taskRunTime = 0;
12704         task.taskRunCount = 0;
12705         startThread();
12706         return task;
12707     };
12708
12709     this.stop = function(task){
12710         removeTask(task);
12711         return task;
12712     };
12713
12714     this.stopAll = function(){
12715         stopThread();
12716         for(var i = 0, len = tasks.length; i < len; i++){
12717             if(tasks[i].onStop){
12718                 tasks[i].onStop();
12719             }
12720         }
12721         tasks = [];
12722         removeQueue = [];
12723     };
12724 };
12725
12726 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12727  * Based on:
12728  * Ext JS Library 1.1.1
12729  * Copyright(c) 2006-2007, Ext JS, LLC.
12730  *
12731  * Originally Released Under LGPL - original licence link has changed is not relivant.
12732  *
12733  * Fork - LGPL
12734  * <script type="text/javascript">
12735  */
12736
12737  
12738 /**
12739  * @class Roo.util.MixedCollection
12740  * @extends Roo.util.Observable
12741  * A Collection class that maintains both numeric indexes and keys and exposes events.
12742  * @constructor
12743  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12744  * collection (defaults to false)
12745  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12746  * and return the key value for that item.  This is used when available to look up the key on items that
12747  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12748  * equivalent to providing an implementation for the {@link #getKey} method.
12749  */
12750 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12751     this.items = [];
12752     this.map = {};
12753     this.keys = [];
12754     this.length = 0;
12755     this.addEvents({
12756         /**
12757          * @event clear
12758          * Fires when the collection is cleared.
12759          */
12760         "clear" : true,
12761         /**
12762          * @event add
12763          * Fires when an item is added to the collection.
12764          * @param {Number} index The index at which the item was added.
12765          * @param {Object} o The item added.
12766          * @param {String} key The key associated with the added item.
12767          */
12768         "add" : true,
12769         /**
12770          * @event replace
12771          * Fires when an item is replaced in the collection.
12772          * @param {String} key he key associated with the new added.
12773          * @param {Object} old The item being replaced.
12774          * @param {Object} new The new item.
12775          */
12776         "replace" : true,
12777         /**
12778          * @event remove
12779          * Fires when an item is removed from the collection.
12780          * @param {Object} o The item being removed.
12781          * @param {String} key (optional) The key associated with the removed item.
12782          */
12783         "remove" : true,
12784         "sort" : true
12785     });
12786     this.allowFunctions = allowFunctions === true;
12787     if(keyFn){
12788         this.getKey = keyFn;
12789     }
12790     Roo.util.MixedCollection.superclass.constructor.call(this);
12791 };
12792
12793 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12794     allowFunctions : false,
12795     
12796 /**
12797  * Adds an item to the collection.
12798  * @param {String} key The key to associate with the item
12799  * @param {Object} o The item to add.
12800  * @return {Object} The item added.
12801  */
12802     add : function(key, o){
12803         if(arguments.length == 1){
12804             o = arguments[0];
12805             key = this.getKey(o);
12806         }
12807         if(typeof key == "undefined" || key === null){
12808             this.length++;
12809             this.items.push(o);
12810             this.keys.push(null);
12811         }else{
12812             var old = this.map[key];
12813             if(old){
12814                 return this.replace(key, o);
12815             }
12816             this.length++;
12817             this.items.push(o);
12818             this.map[key] = o;
12819             this.keys.push(key);
12820         }
12821         this.fireEvent("add", this.length-1, o, key);
12822         return o;
12823     },
12824        
12825 /**
12826   * MixedCollection has a generic way to fetch keys if you implement getKey.
12827 <pre><code>
12828 // normal way
12829 var mc = new Roo.util.MixedCollection();
12830 mc.add(someEl.dom.id, someEl);
12831 mc.add(otherEl.dom.id, otherEl);
12832 //and so on
12833
12834 // using getKey
12835 var mc = new Roo.util.MixedCollection();
12836 mc.getKey = function(el){
12837    return el.dom.id;
12838 };
12839 mc.add(someEl);
12840 mc.add(otherEl);
12841
12842 // or via the constructor
12843 var mc = new Roo.util.MixedCollection(false, function(el){
12844    return el.dom.id;
12845 });
12846 mc.add(someEl);
12847 mc.add(otherEl);
12848 </code></pre>
12849  * @param o {Object} The item for which to find the key.
12850  * @return {Object} The key for the passed item.
12851  */
12852     getKey : function(o){
12853          return o.id; 
12854     },
12855    
12856 /**
12857  * Replaces an item in the collection.
12858  * @param {String} key The key associated with the item to replace, or the item to replace.
12859  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12860  * @return {Object}  The new item.
12861  */
12862     replace : function(key, o){
12863         if(arguments.length == 1){
12864             o = arguments[0];
12865             key = this.getKey(o);
12866         }
12867         var old = this.item(key);
12868         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12869              return this.add(key, o);
12870         }
12871         var index = this.indexOfKey(key);
12872         this.items[index] = o;
12873         this.map[key] = o;
12874         this.fireEvent("replace", key, old, o);
12875         return o;
12876     },
12877    
12878 /**
12879  * Adds all elements of an Array or an Object to the collection.
12880  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12881  * an Array of values, each of which are added to the collection.
12882  */
12883     addAll : function(objs){
12884         if(arguments.length > 1 || objs instanceof Array){
12885             var args = arguments.length > 1 ? arguments : objs;
12886             for(var i = 0, len = args.length; i < len; i++){
12887                 this.add(args[i]);
12888             }
12889         }else{
12890             for(var key in objs){
12891                 if(this.allowFunctions || typeof objs[key] != "function"){
12892                     this.add(key, objs[key]);
12893                 }
12894             }
12895         }
12896     },
12897    
12898 /**
12899  * Executes the specified function once for every item in the collection, passing each
12900  * item as the first and only parameter. returning false from the function will stop the iteration.
12901  * @param {Function} fn The function to execute for each item.
12902  * @param {Object} scope (optional) The scope in which to execute the function.
12903  */
12904     each : function(fn, scope){
12905         var items = [].concat(this.items); // each safe for removal
12906         for(var i = 0, len = items.length; i < len; i++){
12907             if(fn.call(scope || items[i], items[i], i, len) === false){
12908                 break;
12909             }
12910         }
12911     },
12912    
12913 /**
12914  * Executes the specified function once for every key in the collection, passing each
12915  * key, and its associated item as the first two parameters.
12916  * @param {Function} fn The function to execute for each item.
12917  * @param {Object} scope (optional) The scope in which to execute the function.
12918  */
12919     eachKey : function(fn, scope){
12920         for(var i = 0, len = this.keys.length; i < len; i++){
12921             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12922         }
12923     },
12924    
12925 /**
12926  * Returns the first item in the collection which elicits a true return value from the
12927  * passed selection function.
12928  * @param {Function} fn The selection function to execute for each item.
12929  * @param {Object} scope (optional) The scope in which to execute the function.
12930  * @return {Object} The first item in the collection which returned true from the selection function.
12931  */
12932     find : function(fn, scope){
12933         for(var i = 0, len = this.items.length; i < len; i++){
12934             if(fn.call(scope || window, this.items[i], this.keys[i])){
12935                 return this.items[i];
12936             }
12937         }
12938         return null;
12939     },
12940    
12941 /**
12942  * Inserts an item at the specified index in the collection.
12943  * @param {Number} index The index to insert the item at.
12944  * @param {String} key The key to associate with the new item, or the item itself.
12945  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12946  * @return {Object} The item inserted.
12947  */
12948     insert : function(index, key, o){
12949         if(arguments.length == 2){
12950             o = arguments[1];
12951             key = this.getKey(o);
12952         }
12953         if(index >= this.length){
12954             return this.add(key, o);
12955         }
12956         this.length++;
12957         this.items.splice(index, 0, o);
12958         if(typeof key != "undefined" && key != null){
12959             this.map[key] = o;
12960         }
12961         this.keys.splice(index, 0, key);
12962         this.fireEvent("add", index, o, key);
12963         return o;
12964     },
12965    
12966 /**
12967  * Removed an item from the collection.
12968  * @param {Object} o The item to remove.
12969  * @return {Object} The item removed.
12970  */
12971     remove : function(o){
12972         return this.removeAt(this.indexOf(o));
12973     },
12974    
12975 /**
12976  * Remove an item from a specified index in the collection.
12977  * @param {Number} index The index within the collection of the item to remove.
12978  */
12979     removeAt : function(index){
12980         if(index < this.length && index >= 0){
12981             this.length--;
12982             var o = this.items[index];
12983             this.items.splice(index, 1);
12984             var key = this.keys[index];
12985             if(typeof key != "undefined"){
12986                 delete this.map[key];
12987             }
12988             this.keys.splice(index, 1);
12989             this.fireEvent("remove", o, key);
12990         }
12991     },
12992    
12993 /**
12994  * Removed an item associated with the passed key fom the collection.
12995  * @param {String} key The key of the item to remove.
12996  */
12997     removeKey : function(key){
12998         return this.removeAt(this.indexOfKey(key));
12999     },
13000    
13001 /**
13002  * Returns the number of items in the collection.
13003  * @return {Number} the number of items in the collection.
13004  */
13005     getCount : function(){
13006         return this.length; 
13007     },
13008    
13009 /**
13010  * Returns index within the collection of the passed Object.
13011  * @param {Object} o The item to find the index of.
13012  * @return {Number} index of the item.
13013  */
13014     indexOf : function(o){
13015         if(!this.items.indexOf){
13016             for(var i = 0, len = this.items.length; i < len; i++){
13017                 if(this.items[i] == o) return i;
13018             }
13019             return -1;
13020         }else{
13021             return this.items.indexOf(o);
13022         }
13023     },
13024    
13025 /**
13026  * Returns index within the collection of the passed key.
13027  * @param {String} key The key to find the index of.
13028  * @return {Number} index of the key.
13029  */
13030     indexOfKey : function(key){
13031         if(!this.keys.indexOf){
13032             for(var i = 0, len = this.keys.length; i < len; i++){
13033                 if(this.keys[i] == key) return i;
13034             }
13035             return -1;
13036         }else{
13037             return this.keys.indexOf(key);
13038         }
13039     },
13040    
13041 /**
13042  * Returns the item associated with the passed key OR index. Key has priority over index.
13043  * @param {String/Number} key The key or index of the item.
13044  * @return {Object} The item associated with the passed key.
13045  */
13046     item : function(key){
13047         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13048         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13049     },
13050     
13051 /**
13052  * Returns the item at the specified index.
13053  * @param {Number} index The index of the item.
13054  * @return {Object}
13055  */
13056     itemAt : function(index){
13057         return this.items[index];
13058     },
13059     
13060 /**
13061  * Returns the item associated with the passed key.
13062  * @param {String/Number} key The key of the item.
13063  * @return {Object} The item associated with the passed key.
13064  */
13065     key : function(key){
13066         return this.map[key];
13067     },
13068    
13069 /**
13070  * Returns true if the collection contains the passed Object as an item.
13071  * @param {Object} o  The Object to look for in the collection.
13072  * @return {Boolean} True if the collection contains the Object as an item.
13073  */
13074     contains : function(o){
13075         return this.indexOf(o) != -1;
13076     },
13077    
13078 /**
13079  * Returns true if the collection contains the passed Object as a key.
13080  * @param {String} key The key to look for in the collection.
13081  * @return {Boolean} True if the collection contains the Object as a key.
13082  */
13083     containsKey : function(key){
13084         return typeof this.map[key] != "undefined";
13085     },
13086    
13087 /**
13088  * Removes all items from the collection.
13089  */
13090     clear : function(){
13091         this.length = 0;
13092         this.items = [];
13093         this.keys = [];
13094         this.map = {};
13095         this.fireEvent("clear");
13096     },
13097    
13098 /**
13099  * Returns the first item in the collection.
13100  * @return {Object} the first item in the collection..
13101  */
13102     first : function(){
13103         return this.items[0]; 
13104     },
13105    
13106 /**
13107  * Returns the last item in the collection.
13108  * @return {Object} the last item in the collection..
13109  */
13110     last : function(){
13111         return this.items[this.length-1];   
13112     },
13113     
13114     _sort : function(property, dir, fn){
13115         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13116         fn = fn || function(a, b){
13117             return a-b;
13118         };
13119         var c = [], k = this.keys, items = this.items;
13120         for(var i = 0, len = items.length; i < len; i++){
13121             c[c.length] = {key: k[i], value: items[i], index: i};
13122         }
13123         c.sort(function(a, b){
13124             var v = fn(a[property], b[property]) * dsc;
13125             if(v == 0){
13126                 v = (a.index < b.index ? -1 : 1);
13127             }
13128             return v;
13129         });
13130         for(var i = 0, len = c.length; i < len; i++){
13131             items[i] = c[i].value;
13132             k[i] = c[i].key;
13133         }
13134         this.fireEvent("sort", this);
13135     },
13136     
13137     /**
13138      * Sorts this collection with the passed comparison function
13139      * @param {String} direction (optional) "ASC" or "DESC"
13140      * @param {Function} fn (optional) comparison function
13141      */
13142     sort : function(dir, fn){
13143         this._sort("value", dir, fn);
13144     },
13145     
13146     /**
13147      * Sorts this collection by keys
13148      * @param {String} direction (optional) "ASC" or "DESC"
13149      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13150      */
13151     keySort : function(dir, fn){
13152         this._sort("key", dir, fn || function(a, b){
13153             return String(a).toUpperCase()-String(b).toUpperCase();
13154         });
13155     },
13156     
13157     /**
13158      * Returns a range of items in this collection
13159      * @param {Number} startIndex (optional) defaults to 0
13160      * @param {Number} endIndex (optional) default to the last item
13161      * @return {Array} An array of items
13162      */
13163     getRange : function(start, end){
13164         var items = this.items;
13165         if(items.length < 1){
13166             return [];
13167         }
13168         start = start || 0;
13169         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13170         var r = [];
13171         if(start <= end){
13172             for(var i = start; i <= end; i++) {
13173                     r[r.length] = items[i];
13174             }
13175         }else{
13176             for(var i = start; i >= end; i--) {
13177                     r[r.length] = items[i];
13178             }
13179         }
13180         return r;
13181     },
13182         
13183     /**
13184      * Filter the <i>objects</i> in this collection by a specific property. 
13185      * Returns a new collection that has been filtered.
13186      * @param {String} property A property on your objects
13187      * @param {String/RegExp} value Either string that the property values 
13188      * should start with or a RegExp to test against the property
13189      * @return {MixedCollection} The new filtered collection
13190      */
13191     filter : function(property, value){
13192         if(!value.exec){ // not a regex
13193             value = String(value);
13194             if(value.length == 0){
13195                 return this.clone();
13196             }
13197             value = new RegExp("^" + Roo.escapeRe(value), "i");
13198         }
13199         return this.filterBy(function(o){
13200             return o && value.test(o[property]);
13201         });
13202         },
13203     
13204     /**
13205      * Filter by a function. * Returns a new collection that has been filtered.
13206      * The passed function will be called with each 
13207      * object in the collection. If the function returns true, the value is included 
13208      * otherwise it is filtered.
13209      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13210      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13211      * @return {MixedCollection} The new filtered collection
13212      */
13213     filterBy : function(fn, scope){
13214         var r = new Roo.util.MixedCollection();
13215         r.getKey = this.getKey;
13216         var k = this.keys, it = this.items;
13217         for(var i = 0, len = it.length; i < len; i++){
13218             if(fn.call(scope||this, it[i], k[i])){
13219                                 r.add(k[i], it[i]);
13220                         }
13221         }
13222         return r;
13223     },
13224     
13225     /**
13226      * Creates a duplicate of this collection
13227      * @return {MixedCollection}
13228      */
13229     clone : function(){
13230         var r = new Roo.util.MixedCollection();
13231         var k = this.keys, it = this.items;
13232         for(var i = 0, len = it.length; i < len; i++){
13233             r.add(k[i], it[i]);
13234         }
13235         r.getKey = this.getKey;
13236         return r;
13237     }
13238 });
13239 /**
13240  * Returns the item associated with the passed key or index.
13241  * @method
13242  * @param {String/Number} key The key or index of the item.
13243  * @return {Object} The item associated with the passed key.
13244  */
13245 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13246  * Based on:
13247  * Ext JS Library 1.1.1
13248  * Copyright(c) 2006-2007, Ext JS, LLC.
13249  *
13250  * Originally Released Under LGPL - original licence link has changed is not relivant.
13251  *
13252  * Fork - LGPL
13253  * <script type="text/javascript">
13254  */
13255 /**
13256  * @class Roo.util.JSON
13257  * Modified version of Douglas Crockford"s json.js that doesn"t
13258  * mess with the Object prototype 
13259  * http://www.json.org/js.html
13260  * @singleton
13261  */
13262 Roo.util.JSON = new (function(){
13263     var useHasOwn = {}.hasOwnProperty ? true : false;
13264     
13265     // crashes Safari in some instances
13266     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13267     
13268     var pad = function(n) {
13269         return n < 10 ? "0" + n : n;
13270     };
13271     
13272     var m = {
13273         "\b": '\\b',
13274         "\t": '\\t',
13275         "\n": '\\n',
13276         "\f": '\\f',
13277         "\r": '\\r',
13278         '"' : '\\"',
13279         "\\": '\\\\'
13280     };
13281
13282     var encodeString = function(s){
13283         if (/["\\\x00-\x1f]/.test(s)) {
13284             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13285                 var c = m[b];
13286                 if(c){
13287                     return c;
13288                 }
13289                 c = b.charCodeAt();
13290                 return "\\u00" +
13291                     Math.floor(c / 16).toString(16) +
13292                     (c % 16).toString(16);
13293             }) + '"';
13294         }
13295         return '"' + s + '"';
13296     };
13297     
13298     var encodeArray = function(o){
13299         var a = ["["], b, i, l = o.length, v;
13300             for (i = 0; i < l; i += 1) {
13301                 v = o[i];
13302                 switch (typeof v) {
13303                     case "undefined":
13304                     case "function":
13305                     case "unknown":
13306                         break;
13307                     default:
13308                         if (b) {
13309                             a.push(',');
13310                         }
13311                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13312                         b = true;
13313                 }
13314             }
13315             a.push("]");
13316             return a.join("");
13317     };
13318     
13319     var encodeDate = function(o){
13320         return '"' + o.getFullYear() + "-" +
13321                 pad(o.getMonth() + 1) + "-" +
13322                 pad(o.getDate()) + "T" +
13323                 pad(o.getHours()) + ":" +
13324                 pad(o.getMinutes()) + ":" +
13325                 pad(o.getSeconds()) + '"';
13326     };
13327     
13328     /**
13329      * Encodes an Object, Array or other value
13330      * @param {Mixed} o The variable to encode
13331      * @return {String} The JSON string
13332      */
13333     this.encode = function(o)
13334     {
13335         // should this be extended to fully wrap stringify..
13336         
13337         if(typeof o == "undefined" || o === null){
13338             return "null";
13339         }else if(o instanceof Array){
13340             return encodeArray(o);
13341         }else if(o instanceof Date){
13342             return encodeDate(o);
13343         }else if(typeof o == "string"){
13344             return encodeString(o);
13345         }else if(typeof o == "number"){
13346             return isFinite(o) ? String(o) : "null";
13347         }else if(typeof o == "boolean"){
13348             return String(o);
13349         }else {
13350             var a = ["{"], b, i, v;
13351             for (i in o) {
13352                 if(!useHasOwn || o.hasOwnProperty(i)) {
13353                     v = o[i];
13354                     switch (typeof v) {
13355                     case "undefined":
13356                     case "function":
13357                     case "unknown":
13358                         break;
13359                     default:
13360                         if(b){
13361                             a.push(',');
13362                         }
13363                         a.push(this.encode(i), ":",
13364                                 v === null ? "null" : this.encode(v));
13365                         b = true;
13366                     }
13367                 }
13368             }
13369             a.push("}");
13370             return a.join("");
13371         }
13372     };
13373     
13374     /**
13375      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13376      * @param {String} json The JSON string
13377      * @return {Object} The resulting object
13378      */
13379     this.decode = function(json){
13380         
13381         return  /** eval:var:json */ eval("(" + json + ')');
13382     };
13383 })();
13384 /** 
13385  * Shorthand for {@link Roo.util.JSON#encode}
13386  * @member Roo encode 
13387  * @method */
13388 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13389 /** 
13390  * Shorthand for {@link Roo.util.JSON#decode}
13391  * @member Roo decode 
13392  * @method */
13393 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13394 /*
13395  * Based on:
13396  * Ext JS Library 1.1.1
13397  * Copyright(c) 2006-2007, Ext JS, LLC.
13398  *
13399  * Originally Released Under LGPL - original licence link has changed is not relivant.
13400  *
13401  * Fork - LGPL
13402  * <script type="text/javascript">
13403  */
13404  
13405 /**
13406  * @class Roo.util.Format
13407  * Reusable data formatting functions
13408  * @singleton
13409  */
13410 Roo.util.Format = function(){
13411     var trimRe = /^\s+|\s+$/g;
13412     return {
13413         /**
13414          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13415          * @param {String} value The string to truncate
13416          * @param {Number} length The maximum length to allow before truncating
13417          * @return {String} The converted text
13418          */
13419         ellipsis : function(value, len){
13420             if(value && value.length > len){
13421                 return value.substr(0, len-3)+"...";
13422             }
13423             return value;
13424         },
13425
13426         /**
13427          * Checks a reference and converts it to empty string if it is undefined
13428          * @param {Mixed} value Reference to check
13429          * @return {Mixed} Empty string if converted, otherwise the original value
13430          */
13431         undef : function(value){
13432             return typeof value != "undefined" ? value : "";
13433         },
13434
13435         /**
13436          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13437          * @param {String} value The string to encode
13438          * @return {String} The encoded text
13439          */
13440         htmlEncode : function(value){
13441             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13442         },
13443
13444         /**
13445          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13446          * @param {String} value The string to decode
13447          * @return {String} The decoded text
13448          */
13449         htmlDecode : function(value){
13450             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13451         },
13452
13453         /**
13454          * Trims any whitespace from either side of a string
13455          * @param {String} value The text to trim
13456          * @return {String} The trimmed text
13457          */
13458         trim : function(value){
13459             return String(value).replace(trimRe, "");
13460         },
13461
13462         /**
13463          * Returns a substring from within an original string
13464          * @param {String} value The original text
13465          * @param {Number} start The start index of the substring
13466          * @param {Number} length The length of the substring
13467          * @return {String} The substring
13468          */
13469         substr : function(value, start, length){
13470             return String(value).substr(start, length);
13471         },
13472
13473         /**
13474          * Converts a string to all lower case letters
13475          * @param {String} value The text to convert
13476          * @return {String} The converted text
13477          */
13478         lowercase : function(value){
13479             return String(value).toLowerCase();
13480         },
13481
13482         /**
13483          * Converts a string to all upper case letters
13484          * @param {String} value The text to convert
13485          * @return {String} The converted text
13486          */
13487         uppercase : function(value){
13488             return String(value).toUpperCase();
13489         },
13490
13491         /**
13492          * Converts the first character only of a string to upper case
13493          * @param {String} value The text to convert
13494          * @return {String} The converted text
13495          */
13496         capitalize : function(value){
13497             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13498         },
13499
13500         // private
13501         call : function(value, fn){
13502             if(arguments.length > 2){
13503                 var args = Array.prototype.slice.call(arguments, 2);
13504                 args.unshift(value);
13505                  
13506                 return /** eval:var:value */  eval(fn).apply(window, args);
13507             }else{
13508                 /** eval:var:value */
13509                 return /** eval:var:value */ eval(fn).call(window, value);
13510             }
13511         },
13512
13513        
13514         /**
13515          * safer version of Math.toFixed..??/
13516          * @param {Number/String} value The numeric value to format
13517          * @param {Number/String} value Decimal places 
13518          * @return {String} The formatted currency string
13519          */
13520         toFixed : function(v, n)
13521         {
13522             // why not use to fixed - precision is buggered???
13523             if (!n) {
13524                 return Math.round(v-0);
13525             }
13526             var fact = Math.pow(10,n+1);
13527             v = (Math.round((v-0)*fact))/fact;
13528             var z = (''+fact).substring(2);
13529             if (v == Math.floor(v)) {
13530                 return Math.floor(v) + '.' + z;
13531             }
13532             
13533             // now just padd decimals..
13534             var ps = String(v).split('.');
13535             var fd = (ps[1] + z);
13536             var r = fd.substring(0,n); 
13537             var rm = fd.substring(n); 
13538             if (rm < 5) {
13539                 return ps[0] + '.' + r;
13540             }
13541             r*=1; // turn it into a number;
13542             r++;
13543             if (String(r).length != n) {
13544                 ps[0]*=1;
13545                 ps[0]++;
13546                 r = String(r).substring(1); // chop the end off.
13547             }
13548             
13549             return ps[0] + '.' + r;
13550              
13551         },
13552         
13553         /**
13554          * Format a number as US currency
13555          * @param {Number/String} value The numeric value to format
13556          * @return {String} The formatted currency string
13557          */
13558         usMoney : function(v){
13559             return '$' + Roo.util.Format.number(v);
13560         },
13561         
13562         /**
13563          * Format a number
13564          * eventually this should probably emulate php's number_format
13565          * @param {Number/String} value The numeric value to format
13566          * @param {Number} decimals number of decimal places
13567          * @return {String} The formatted currency string
13568          */
13569         number : function(v,decimals)
13570         {
13571             // multiply and round.
13572             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13573             var mul = Math.pow(10, decimals);
13574             var zero = String(mul).substring(1);
13575             v = (Math.round((v-0)*mul))/mul;
13576             
13577             // if it's '0' number.. then
13578             
13579             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13580             v = String(v);
13581             var ps = v.split('.');
13582             var whole = ps[0];
13583             
13584             
13585             var r = /(\d+)(\d{3})/;
13586             // add comma's
13587             while (r.test(whole)) {
13588                 whole = whole.replace(r, '$1' + ',' + '$2');
13589             }
13590             
13591             
13592             var sub = ps[1] ?
13593                     // has decimals..
13594                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13595                     // does not have decimals
13596                     (decimals ? ('.' + zero) : '');
13597             
13598             
13599             return whole + sub ;
13600         },
13601         
13602         /**
13603          * Parse a value into a formatted date using the specified format pattern.
13604          * @param {Mixed} value The value to format
13605          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13606          * @return {String} The formatted date string
13607          */
13608         date : function(v, format){
13609             if(!v){
13610                 return "";
13611             }
13612             if(!(v instanceof Date)){
13613                 v = new Date(Date.parse(v));
13614             }
13615             return v.dateFormat(format || Roo.util.Format.defaults.date);
13616         },
13617
13618         /**
13619          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13620          * @param {String} format Any valid date format string
13621          * @return {Function} The date formatting function
13622          */
13623         dateRenderer : function(format){
13624             return function(v){
13625                 return Roo.util.Format.date(v, format);  
13626             };
13627         },
13628
13629         // private
13630         stripTagsRE : /<\/?[^>]+>/gi,
13631         
13632         /**
13633          * Strips all HTML tags
13634          * @param {Mixed} value The text from which to strip tags
13635          * @return {String} The stripped text
13636          */
13637         stripTags : function(v){
13638             return !v ? v : String(v).replace(this.stripTagsRE, "");
13639         }
13640     };
13641 }();
13642 Roo.util.Format.defaults = {
13643     date : 'd/M/Y'
13644 };/*
13645  * Based on:
13646  * Ext JS Library 1.1.1
13647  * Copyright(c) 2006-2007, Ext JS, LLC.
13648  *
13649  * Originally Released Under LGPL - original licence link has changed is not relivant.
13650  *
13651  * Fork - LGPL
13652  * <script type="text/javascript">
13653  */
13654
13655
13656  
13657
13658 /**
13659  * @class Roo.MasterTemplate
13660  * @extends Roo.Template
13661  * Provides a template that can have child templates. The syntax is:
13662 <pre><code>
13663 var t = new Roo.MasterTemplate(
13664         '&lt;select name="{name}"&gt;',
13665                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13666         '&lt;/select&gt;'
13667 );
13668 t.add('options', {value: 'foo', text: 'bar'});
13669 // or you can add multiple child elements in one shot
13670 t.addAll('options', [
13671     {value: 'foo', text: 'bar'},
13672     {value: 'foo2', text: 'bar2'},
13673     {value: 'foo3', text: 'bar3'}
13674 ]);
13675 // then append, applying the master template values
13676 t.append('my-form', {name: 'my-select'});
13677 </code></pre>
13678 * A name attribute for the child template is not required if you have only one child
13679 * template or you want to refer to them by index.
13680  */
13681 Roo.MasterTemplate = function(){
13682     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13683     this.originalHtml = this.html;
13684     var st = {};
13685     var m, re = this.subTemplateRe;
13686     re.lastIndex = 0;
13687     var subIndex = 0;
13688     while(m = re.exec(this.html)){
13689         var name = m[1], content = m[2];
13690         st[subIndex] = {
13691             name: name,
13692             index: subIndex,
13693             buffer: [],
13694             tpl : new Roo.Template(content)
13695         };
13696         if(name){
13697             st[name] = st[subIndex];
13698         }
13699         st[subIndex].tpl.compile();
13700         st[subIndex].tpl.call = this.call.createDelegate(this);
13701         subIndex++;
13702     }
13703     this.subCount = subIndex;
13704     this.subs = st;
13705 };
13706 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13707     /**
13708     * The regular expression used to match sub templates
13709     * @type RegExp
13710     * @property
13711     */
13712     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13713
13714     /**
13715      * Applies the passed values to a child template.
13716      * @param {String/Number} name (optional) The name or index of the child template
13717      * @param {Array/Object} values The values to be applied to the template
13718      * @return {MasterTemplate} this
13719      */
13720      add : function(name, values){
13721         if(arguments.length == 1){
13722             values = arguments[0];
13723             name = 0;
13724         }
13725         var s = this.subs[name];
13726         s.buffer[s.buffer.length] = s.tpl.apply(values);
13727         return this;
13728     },
13729
13730     /**
13731      * Applies all the passed values to a child template.
13732      * @param {String/Number} name (optional) The name or index of the child template
13733      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13734      * @param {Boolean} reset (optional) True to reset the template first
13735      * @return {MasterTemplate} this
13736      */
13737     fill : function(name, values, reset){
13738         var a = arguments;
13739         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13740             values = a[0];
13741             name = 0;
13742             reset = a[1];
13743         }
13744         if(reset){
13745             this.reset();
13746         }
13747         for(var i = 0, len = values.length; i < len; i++){
13748             this.add(name, values[i]);
13749         }
13750         return this;
13751     },
13752
13753     /**
13754      * Resets the template for reuse
13755      * @return {MasterTemplate} this
13756      */
13757      reset : function(){
13758         var s = this.subs;
13759         for(var i = 0; i < this.subCount; i++){
13760             s[i].buffer = [];
13761         }
13762         return this;
13763     },
13764
13765     applyTemplate : function(values){
13766         var s = this.subs;
13767         var replaceIndex = -1;
13768         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13769             return s[++replaceIndex].buffer.join("");
13770         });
13771         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13772     },
13773
13774     apply : function(){
13775         return this.applyTemplate.apply(this, arguments);
13776     },
13777
13778     compile : function(){return this;}
13779 });
13780
13781 /**
13782  * Alias for fill().
13783  * @method
13784  */
13785 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13786  /**
13787  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13788  * var tpl = Roo.MasterTemplate.from('element-id');
13789  * @param {String/HTMLElement} el
13790  * @param {Object} config
13791  * @static
13792  */
13793 Roo.MasterTemplate.from = function(el, config){
13794     el = Roo.getDom(el);
13795     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13796 };/*
13797  * Based on:
13798  * Ext JS Library 1.1.1
13799  * Copyright(c) 2006-2007, Ext JS, LLC.
13800  *
13801  * Originally Released Under LGPL - original licence link has changed is not relivant.
13802  *
13803  * Fork - LGPL
13804  * <script type="text/javascript">
13805  */
13806
13807  
13808 /**
13809  * @class Roo.util.CSS
13810  * Utility class for manipulating CSS rules
13811  * @singleton
13812  */
13813 Roo.util.CSS = function(){
13814         var rules = null;
13815         var doc = document;
13816
13817     var camelRe = /(-[a-z])/gi;
13818     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13819
13820    return {
13821    /**
13822     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13823     * tag and appended to the HEAD of the document.
13824     * @param {String|Object} cssText The text containing the css rules
13825     * @param {String} id An id to add to the stylesheet for later removal
13826     * @return {StyleSheet}
13827     */
13828     createStyleSheet : function(cssText, id){
13829         var ss;
13830         var head = doc.getElementsByTagName("head")[0];
13831         var nrules = doc.createElement("style");
13832         nrules.setAttribute("type", "text/css");
13833         if(id){
13834             nrules.setAttribute("id", id);
13835         }
13836         if (typeof(cssText) != 'string') {
13837             // support object maps..
13838             // not sure if this a good idea.. 
13839             // perhaps it should be merged with the general css handling
13840             // and handle js style props.
13841             var cssTextNew = [];
13842             for(var n in cssText) {
13843                 var citems = [];
13844                 for(var k in cssText[n]) {
13845                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13846                 }
13847                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13848                 
13849             }
13850             cssText = cssTextNew.join("\n");
13851             
13852         }
13853        
13854        
13855        if(Roo.isIE){
13856            head.appendChild(nrules);
13857            ss = nrules.styleSheet;
13858            ss.cssText = cssText;
13859        }else{
13860            try{
13861                 nrules.appendChild(doc.createTextNode(cssText));
13862            }catch(e){
13863                nrules.cssText = cssText; 
13864            }
13865            head.appendChild(nrules);
13866            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13867        }
13868        this.cacheStyleSheet(ss);
13869        return ss;
13870    },
13871
13872    /**
13873     * Removes a style or link tag by id
13874     * @param {String} id The id of the tag
13875     */
13876    removeStyleSheet : function(id){
13877        var existing = doc.getElementById(id);
13878        if(existing){
13879            existing.parentNode.removeChild(existing);
13880        }
13881    },
13882
13883    /**
13884     * Dynamically swaps an existing stylesheet reference for a new one
13885     * @param {String} id The id of an existing link tag to remove
13886     * @param {String} url The href of the new stylesheet to include
13887     */
13888    swapStyleSheet : function(id, url){
13889        this.removeStyleSheet(id);
13890        var ss = doc.createElement("link");
13891        ss.setAttribute("rel", "stylesheet");
13892        ss.setAttribute("type", "text/css");
13893        ss.setAttribute("id", id);
13894        ss.setAttribute("href", url);
13895        doc.getElementsByTagName("head")[0].appendChild(ss);
13896    },
13897    
13898    /**
13899     * Refresh the rule cache if you have dynamically added stylesheets
13900     * @return {Object} An object (hash) of rules indexed by selector
13901     */
13902    refreshCache : function(){
13903        return this.getRules(true);
13904    },
13905
13906    // private
13907    cacheStyleSheet : function(stylesheet){
13908        if(!rules){
13909            rules = {};
13910        }
13911        try{// try catch for cross domain access issue
13912            var ssRules = stylesheet.cssRules || stylesheet.rules;
13913            for(var j = ssRules.length-1; j >= 0; --j){
13914                rules[ssRules[j].selectorText] = ssRules[j];
13915            }
13916        }catch(e){}
13917    },
13918    
13919    /**
13920     * Gets all css rules for the document
13921     * @param {Boolean} refreshCache true to refresh the internal cache
13922     * @return {Object} An object (hash) of rules indexed by selector
13923     */
13924    getRules : function(refreshCache){
13925                 if(rules == null || refreshCache){
13926                         rules = {};
13927                         var ds = doc.styleSheets;
13928                         for(var i =0, len = ds.length; i < len; i++){
13929                             try{
13930                         this.cacheStyleSheet(ds[i]);
13931                     }catch(e){} 
13932                 }
13933                 }
13934                 return rules;
13935         },
13936         
13937         /**
13938     * Gets an an individual CSS rule by selector(s)
13939     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13940     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13941     * @return {CSSRule} The CSS rule or null if one is not found
13942     */
13943    getRule : function(selector, refreshCache){
13944                 var rs = this.getRules(refreshCache);
13945                 if(!(selector instanceof Array)){
13946                     return rs[selector];
13947                 }
13948                 for(var i = 0; i < selector.length; i++){
13949                         if(rs[selector[i]]){
13950                                 return rs[selector[i]];
13951                         }
13952                 }
13953                 return null;
13954         },
13955         
13956         
13957         /**
13958     * Updates a rule property
13959     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13960     * @param {String} property The css property
13961     * @param {String} value The new value for the property
13962     * @return {Boolean} true If a rule was found and updated
13963     */
13964    updateRule : function(selector, property, value){
13965                 if(!(selector instanceof Array)){
13966                         var rule = this.getRule(selector);
13967                         if(rule){
13968                                 rule.style[property.replace(camelRe, camelFn)] = value;
13969                                 return true;
13970                         }
13971                 }else{
13972                         for(var i = 0; i < selector.length; i++){
13973                                 if(this.updateRule(selector[i], property, value)){
13974                                         return true;
13975                                 }
13976                         }
13977                 }
13978                 return false;
13979         }
13980    };   
13981 }();/*
13982  * Based on:
13983  * Ext JS Library 1.1.1
13984  * Copyright(c) 2006-2007, Ext JS, LLC.
13985  *
13986  * Originally Released Under LGPL - original licence link has changed is not relivant.
13987  *
13988  * Fork - LGPL
13989  * <script type="text/javascript">
13990  */
13991
13992  
13993
13994 /**
13995  * @class Roo.util.ClickRepeater
13996  * @extends Roo.util.Observable
13997  * 
13998  * A wrapper class which can be applied to any element. Fires a "click" event while the
13999  * mouse is pressed. The interval between firings may be specified in the config but
14000  * defaults to 10 milliseconds.
14001  * 
14002  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14003  * 
14004  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14005  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14006  * Similar to an autorepeat key delay.
14007  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14008  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14009  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14010  *           "interval" and "delay" are ignored. "immediate" is honored.
14011  * @cfg {Boolean} preventDefault True to prevent the default click event
14012  * @cfg {Boolean} stopDefault True to stop the default click event
14013  * 
14014  * @history
14015  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14016  *     2007-02-02 jvs Renamed to ClickRepeater
14017  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14018  *
14019  *  @constructor
14020  * @param {String/HTMLElement/Element} el The element to listen on
14021  * @param {Object} config
14022  **/
14023 Roo.util.ClickRepeater = function(el, config)
14024 {
14025     this.el = Roo.get(el);
14026     this.el.unselectable();
14027
14028     Roo.apply(this, config);
14029
14030     this.addEvents({
14031     /**
14032      * @event mousedown
14033      * Fires when the mouse button is depressed.
14034      * @param {Roo.util.ClickRepeater} this
14035      */
14036         "mousedown" : true,
14037     /**
14038      * @event click
14039      * Fires on a specified interval during the time the element is pressed.
14040      * @param {Roo.util.ClickRepeater} this
14041      */
14042         "click" : true,
14043     /**
14044      * @event mouseup
14045      * Fires when the mouse key is released.
14046      * @param {Roo.util.ClickRepeater} this
14047      */
14048         "mouseup" : true
14049     });
14050
14051     this.el.on("mousedown", this.handleMouseDown, this);
14052     if(this.preventDefault || this.stopDefault){
14053         this.el.on("click", function(e){
14054             if(this.preventDefault){
14055                 e.preventDefault();
14056             }
14057             if(this.stopDefault){
14058                 e.stopEvent();
14059             }
14060         }, this);
14061     }
14062
14063     // allow inline handler
14064     if(this.handler){
14065         this.on("click", this.handler,  this.scope || this);
14066     }
14067
14068     Roo.util.ClickRepeater.superclass.constructor.call(this);
14069 };
14070
14071 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14072     interval : 20,
14073     delay: 250,
14074     preventDefault : true,
14075     stopDefault : false,
14076     timer : 0,
14077
14078     // private
14079     handleMouseDown : function(){
14080         clearTimeout(this.timer);
14081         this.el.blur();
14082         if(this.pressClass){
14083             this.el.addClass(this.pressClass);
14084         }
14085         this.mousedownTime = new Date();
14086
14087         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14088         this.el.on("mouseout", this.handleMouseOut, this);
14089
14090         this.fireEvent("mousedown", this);
14091         this.fireEvent("click", this);
14092         
14093         this.timer = this.click.defer(this.delay || this.interval, this);
14094     },
14095
14096     // private
14097     click : function(){
14098         this.fireEvent("click", this);
14099         this.timer = this.click.defer(this.getInterval(), this);
14100     },
14101
14102     // private
14103     getInterval: function(){
14104         if(!this.accelerate){
14105             return this.interval;
14106         }
14107         var pressTime = this.mousedownTime.getElapsed();
14108         if(pressTime < 500){
14109             return 400;
14110         }else if(pressTime < 1700){
14111             return 320;
14112         }else if(pressTime < 2600){
14113             return 250;
14114         }else if(pressTime < 3500){
14115             return 180;
14116         }else if(pressTime < 4400){
14117             return 140;
14118         }else if(pressTime < 5300){
14119             return 80;
14120         }else if(pressTime < 6200){
14121             return 50;
14122         }else{
14123             return 10;
14124         }
14125     },
14126
14127     // private
14128     handleMouseOut : function(){
14129         clearTimeout(this.timer);
14130         if(this.pressClass){
14131             this.el.removeClass(this.pressClass);
14132         }
14133         this.el.on("mouseover", this.handleMouseReturn, this);
14134     },
14135
14136     // private
14137     handleMouseReturn : function(){
14138         this.el.un("mouseover", this.handleMouseReturn);
14139         if(this.pressClass){
14140             this.el.addClass(this.pressClass);
14141         }
14142         this.click();
14143     },
14144
14145     // private
14146     handleMouseUp : function(){
14147         clearTimeout(this.timer);
14148         this.el.un("mouseover", this.handleMouseReturn);
14149         this.el.un("mouseout", this.handleMouseOut);
14150         Roo.get(document).un("mouseup", this.handleMouseUp);
14151         this.el.removeClass(this.pressClass);
14152         this.fireEvent("mouseup", this);
14153     }
14154 });/*
14155  * Based on:
14156  * Ext JS Library 1.1.1
14157  * Copyright(c) 2006-2007, Ext JS, LLC.
14158  *
14159  * Originally Released Under LGPL - original licence link has changed is not relivant.
14160  *
14161  * Fork - LGPL
14162  * <script type="text/javascript">
14163  */
14164
14165  
14166 /**
14167  * @class Roo.KeyNav
14168  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14169  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14170  * way to implement custom navigation schemes for any UI component.</p>
14171  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14172  * pageUp, pageDown, del, home, end.  Usage:</p>
14173  <pre><code>
14174 var nav = new Roo.KeyNav("my-element", {
14175     "left" : function(e){
14176         this.moveLeft(e.ctrlKey);
14177     },
14178     "right" : function(e){
14179         this.moveRight(e.ctrlKey);
14180     },
14181     "enter" : function(e){
14182         this.save();
14183     },
14184     scope : this
14185 });
14186 </code></pre>
14187  * @constructor
14188  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14189  * @param {Object} config The config
14190  */
14191 Roo.KeyNav = function(el, config){
14192     this.el = Roo.get(el);
14193     Roo.apply(this, config);
14194     if(!this.disabled){
14195         this.disabled = true;
14196         this.enable();
14197     }
14198 };
14199
14200 Roo.KeyNav.prototype = {
14201     /**
14202      * @cfg {Boolean} disabled
14203      * True to disable this KeyNav instance (defaults to false)
14204      */
14205     disabled : false,
14206     /**
14207      * @cfg {String} defaultEventAction
14208      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14209      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14210      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14211      */
14212     defaultEventAction: "stopEvent",
14213     /**
14214      * @cfg {Boolean} forceKeyDown
14215      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14216      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14217      * handle keydown instead of keypress.
14218      */
14219     forceKeyDown : false,
14220
14221     // private
14222     prepareEvent : function(e){
14223         var k = e.getKey();
14224         var h = this.keyToHandler[k];
14225         //if(h && this[h]){
14226         //    e.stopPropagation();
14227         //}
14228         if(Roo.isSafari && h && k >= 37 && k <= 40){
14229             e.stopEvent();
14230         }
14231     },
14232
14233     // private
14234     relay : function(e){
14235         var k = e.getKey();
14236         var h = this.keyToHandler[k];
14237         if(h && this[h]){
14238             if(this.doRelay(e, this[h], h) !== true){
14239                 e[this.defaultEventAction]();
14240             }
14241         }
14242     },
14243
14244     // private
14245     doRelay : function(e, h, hname){
14246         return h.call(this.scope || this, e);
14247     },
14248
14249     // possible handlers
14250     enter : false,
14251     left : false,
14252     right : false,
14253     up : false,
14254     down : false,
14255     tab : false,
14256     esc : false,
14257     pageUp : false,
14258     pageDown : false,
14259     del : false,
14260     home : false,
14261     end : false,
14262
14263     // quick lookup hash
14264     keyToHandler : {
14265         37 : "left",
14266         39 : "right",
14267         38 : "up",
14268         40 : "down",
14269         33 : "pageUp",
14270         34 : "pageDown",
14271         46 : "del",
14272         36 : "home",
14273         35 : "end",
14274         13 : "enter",
14275         27 : "esc",
14276         9  : "tab"
14277     },
14278
14279         /**
14280          * Enable this KeyNav
14281          */
14282         enable: function(){
14283                 if(this.disabled){
14284             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14285             // the EventObject will normalize Safari automatically
14286             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14287                 this.el.on("keydown", this.relay,  this);
14288             }else{
14289                 this.el.on("keydown", this.prepareEvent,  this);
14290                 this.el.on("keypress", this.relay,  this);
14291             }
14292                     this.disabled = false;
14293                 }
14294         },
14295
14296         /**
14297          * Disable this KeyNav
14298          */
14299         disable: function(){
14300                 if(!this.disabled){
14301                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14302                 this.el.un("keydown", this.relay);
14303             }else{
14304                 this.el.un("keydown", this.prepareEvent);
14305                 this.el.un("keypress", this.relay);
14306             }
14307                     this.disabled = true;
14308                 }
14309         }
14310 };/*
14311  * Based on:
14312  * Ext JS Library 1.1.1
14313  * Copyright(c) 2006-2007, Ext JS, LLC.
14314  *
14315  * Originally Released Under LGPL - original licence link has changed is not relivant.
14316  *
14317  * Fork - LGPL
14318  * <script type="text/javascript">
14319  */
14320
14321  
14322 /**
14323  * @class Roo.KeyMap
14324  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14325  * The constructor accepts the same config object as defined by {@link #addBinding}.
14326  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14327  * combination it will call the function with this signature (if the match is a multi-key
14328  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14329  * A KeyMap can also handle a string representation of keys.<br />
14330  * Usage:
14331  <pre><code>
14332 // map one key by key code
14333 var map = new Roo.KeyMap("my-element", {
14334     key: 13, // or Roo.EventObject.ENTER
14335     fn: myHandler,
14336     scope: myObject
14337 });
14338
14339 // map multiple keys to one action by string
14340 var map = new Roo.KeyMap("my-element", {
14341     key: "a\r\n\t",
14342     fn: myHandler,
14343     scope: myObject
14344 });
14345
14346 // map multiple keys to multiple actions by strings and array of codes
14347 var map = new Roo.KeyMap("my-element", [
14348     {
14349         key: [10,13],
14350         fn: function(){ alert("Return was pressed"); }
14351     }, {
14352         key: "abc",
14353         fn: function(){ alert('a, b or c was pressed'); }
14354     }, {
14355         key: "\t",
14356         ctrl:true,
14357         shift:true,
14358         fn: function(){ alert('Control + shift + tab was pressed.'); }
14359     }
14360 ]);
14361 </code></pre>
14362  * <b>Note: A KeyMap starts enabled</b>
14363  * @constructor
14364  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14365  * @param {Object} config The config (see {@link #addBinding})
14366  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14367  */
14368 Roo.KeyMap = function(el, config, eventName){
14369     this.el  = Roo.get(el);
14370     this.eventName = eventName || "keydown";
14371     this.bindings = [];
14372     if(config){
14373         this.addBinding(config);
14374     }
14375     this.enable();
14376 };
14377
14378 Roo.KeyMap.prototype = {
14379     /**
14380      * True to stop the event from bubbling and prevent the default browser action if the
14381      * key was handled by the KeyMap (defaults to false)
14382      * @type Boolean
14383      */
14384     stopEvent : false,
14385
14386     /**
14387      * Add a new binding to this KeyMap. The following config object properties are supported:
14388      * <pre>
14389 Property    Type             Description
14390 ----------  ---------------  ----------------------------------------------------------------------
14391 key         String/Array     A single keycode or an array of keycodes to handle
14392 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14393 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14394 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14395 fn          Function         The function to call when KeyMap finds the expected key combination
14396 scope       Object           The scope of the callback function
14397 </pre>
14398      *
14399      * Usage:
14400      * <pre><code>
14401 // Create a KeyMap
14402 var map = new Roo.KeyMap(document, {
14403     key: Roo.EventObject.ENTER,
14404     fn: handleKey,
14405     scope: this
14406 });
14407
14408 //Add a new binding to the existing KeyMap later
14409 map.addBinding({
14410     key: 'abc',
14411     shift: true,
14412     fn: handleKey,
14413     scope: this
14414 });
14415 </code></pre>
14416      * @param {Object/Array} config A single KeyMap config or an array of configs
14417      */
14418         addBinding : function(config){
14419         if(config instanceof Array){
14420             for(var i = 0, len = config.length; i < len; i++){
14421                 this.addBinding(config[i]);
14422             }
14423             return;
14424         }
14425         var keyCode = config.key,
14426             shift = config.shift, 
14427             ctrl = config.ctrl, 
14428             alt = config.alt,
14429             fn = config.fn,
14430             scope = config.scope;
14431         if(typeof keyCode == "string"){
14432             var ks = [];
14433             var keyString = keyCode.toUpperCase();
14434             for(var j = 0, len = keyString.length; j < len; j++){
14435                 ks.push(keyString.charCodeAt(j));
14436             }
14437             keyCode = ks;
14438         }
14439         var keyArray = keyCode instanceof Array;
14440         var handler = function(e){
14441             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14442                 var k = e.getKey();
14443                 if(keyArray){
14444                     for(var i = 0, len = keyCode.length; i < len; i++){
14445                         if(keyCode[i] == k){
14446                           if(this.stopEvent){
14447                               e.stopEvent();
14448                           }
14449                           fn.call(scope || window, k, e);
14450                           return;
14451                         }
14452                     }
14453                 }else{
14454                     if(k == keyCode){
14455                         if(this.stopEvent){
14456                            e.stopEvent();
14457                         }
14458                         fn.call(scope || window, k, e);
14459                     }
14460                 }
14461             }
14462         };
14463         this.bindings.push(handler);  
14464         },
14465
14466     /**
14467      * Shorthand for adding a single key listener
14468      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14469      * following options:
14470      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14471      * @param {Function} fn The function to call
14472      * @param {Object} scope (optional) The scope of the function
14473      */
14474     on : function(key, fn, scope){
14475         var keyCode, shift, ctrl, alt;
14476         if(typeof key == "object" && !(key instanceof Array)){
14477             keyCode = key.key;
14478             shift = key.shift;
14479             ctrl = key.ctrl;
14480             alt = key.alt;
14481         }else{
14482             keyCode = key;
14483         }
14484         this.addBinding({
14485             key: keyCode,
14486             shift: shift,
14487             ctrl: ctrl,
14488             alt: alt,
14489             fn: fn,
14490             scope: scope
14491         })
14492     },
14493
14494     // private
14495     handleKeyDown : function(e){
14496             if(this.enabled){ //just in case
14497             var b = this.bindings;
14498             for(var i = 0, len = b.length; i < len; i++){
14499                 b[i].call(this, e);
14500             }
14501             }
14502         },
14503         
14504         /**
14505          * Returns true if this KeyMap is enabled
14506          * @return {Boolean} 
14507          */
14508         isEnabled : function(){
14509             return this.enabled;  
14510         },
14511         
14512         /**
14513          * Enables this KeyMap
14514          */
14515         enable: function(){
14516                 if(!this.enabled){
14517                     this.el.on(this.eventName, this.handleKeyDown, this);
14518                     this.enabled = true;
14519                 }
14520         },
14521
14522         /**
14523          * Disable this KeyMap
14524          */
14525         disable: function(){
14526                 if(this.enabled){
14527                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14528                     this.enabled = false;
14529                 }
14530         }
14531 };/*
14532  * Based on:
14533  * Ext JS Library 1.1.1
14534  * Copyright(c) 2006-2007, Ext JS, LLC.
14535  *
14536  * Originally Released Under LGPL - original licence link has changed is not relivant.
14537  *
14538  * Fork - LGPL
14539  * <script type="text/javascript">
14540  */
14541
14542  
14543 /**
14544  * @class Roo.util.TextMetrics
14545  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14546  * wide, in pixels, a given block of text will be.
14547  * @singleton
14548  */
14549 Roo.util.TextMetrics = function(){
14550     var shared;
14551     return {
14552         /**
14553          * Measures the size of the specified text
14554          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14555          * that can affect the size of the rendered text
14556          * @param {String} text The text to measure
14557          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14558          * in order to accurately measure the text height
14559          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14560          */
14561         measure : function(el, text, fixedWidth){
14562             if(!shared){
14563                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14564             }
14565             shared.bind(el);
14566             shared.setFixedWidth(fixedWidth || 'auto');
14567             return shared.getSize(text);
14568         },
14569
14570         /**
14571          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14572          * the overhead of multiple calls to initialize the style properties on each measurement.
14573          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14574          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14575          * in order to accurately measure the text height
14576          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14577          */
14578         createInstance : function(el, fixedWidth){
14579             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14580         }
14581     };
14582 }();
14583
14584  
14585
14586 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14587     var ml = new Roo.Element(document.createElement('div'));
14588     document.body.appendChild(ml.dom);
14589     ml.position('absolute');
14590     ml.setLeftTop(-1000, -1000);
14591     ml.hide();
14592
14593     if(fixedWidth){
14594         ml.setWidth(fixedWidth);
14595     }
14596      
14597     var instance = {
14598         /**
14599          * Returns the size of the specified text based on the internal element's style and width properties
14600          * @memberOf Roo.util.TextMetrics.Instance#
14601          * @param {String} text The text to measure
14602          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14603          */
14604         getSize : function(text){
14605             ml.update(text);
14606             var s = ml.getSize();
14607             ml.update('');
14608             return s;
14609         },
14610
14611         /**
14612          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14613          * that can affect the size of the rendered text
14614          * @memberOf Roo.util.TextMetrics.Instance#
14615          * @param {String/HTMLElement} el The element, dom node or id
14616          */
14617         bind : function(el){
14618             ml.setStyle(
14619                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14620             );
14621         },
14622
14623         /**
14624          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14625          * to set a fixed width in order to accurately measure the text height.
14626          * @memberOf Roo.util.TextMetrics.Instance#
14627          * @param {Number} width The width to set on the element
14628          */
14629         setFixedWidth : function(width){
14630             ml.setWidth(width);
14631         },
14632
14633         /**
14634          * Returns the measured width of the specified text
14635          * @memberOf Roo.util.TextMetrics.Instance#
14636          * @param {String} text The text to measure
14637          * @return {Number} width The width in pixels
14638          */
14639         getWidth : function(text){
14640             ml.dom.style.width = 'auto';
14641             return this.getSize(text).width;
14642         },
14643
14644         /**
14645          * Returns the measured height of the specified text.  For multiline text, be sure to call
14646          * {@link #setFixedWidth} if necessary.
14647          * @memberOf Roo.util.TextMetrics.Instance#
14648          * @param {String} text The text to measure
14649          * @return {Number} height The height in pixels
14650          */
14651         getHeight : function(text){
14652             return this.getSize(text).height;
14653         }
14654     };
14655
14656     instance.bind(bindTo);
14657
14658     return instance;
14659 };
14660
14661 // backwards compat
14662 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14663  * Based on:
14664  * Ext JS Library 1.1.1
14665  * Copyright(c) 2006-2007, Ext JS, LLC.
14666  *
14667  * Originally Released Under LGPL - original licence link has changed is not relivant.
14668  *
14669  * Fork - LGPL
14670  * <script type="text/javascript">
14671  */
14672
14673 /**
14674  * @class Roo.state.Provider
14675  * Abstract base class for state provider implementations. This class provides methods
14676  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14677  * Provider interface.
14678  */
14679 Roo.state.Provider = function(){
14680     /**
14681      * @event statechange
14682      * Fires when a state change occurs.
14683      * @param {Provider} this This state provider
14684      * @param {String} key The state key which was changed
14685      * @param {String} value The encoded value for the state
14686      */
14687     this.addEvents({
14688         "statechange": true
14689     });
14690     this.state = {};
14691     Roo.state.Provider.superclass.constructor.call(this);
14692 };
14693 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14694     /**
14695      * Returns the current value for a key
14696      * @param {String} name The key name
14697      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14698      * @return {Mixed} The state data
14699      */
14700     get : function(name, defaultValue){
14701         return typeof this.state[name] == "undefined" ?
14702             defaultValue : this.state[name];
14703     },
14704     
14705     /**
14706      * Clears a value from the state
14707      * @param {String} name The key name
14708      */
14709     clear : function(name){
14710         delete this.state[name];
14711         this.fireEvent("statechange", this, name, null);
14712     },
14713     
14714     /**
14715      * Sets the value for a key
14716      * @param {String} name The key name
14717      * @param {Mixed} value The value to set
14718      */
14719     set : function(name, value){
14720         this.state[name] = value;
14721         this.fireEvent("statechange", this, name, value);
14722     },
14723     
14724     /**
14725      * Decodes a string previously encoded with {@link #encodeValue}.
14726      * @param {String} value The value to decode
14727      * @return {Mixed} The decoded value
14728      */
14729     decodeValue : function(cookie){
14730         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14731         var matches = re.exec(unescape(cookie));
14732         if(!matches || !matches[1]) return; // non state cookie
14733         var type = matches[1];
14734         var v = matches[2];
14735         switch(type){
14736             case "n":
14737                 return parseFloat(v);
14738             case "d":
14739                 return new Date(Date.parse(v));
14740             case "b":
14741                 return (v == "1");
14742             case "a":
14743                 var all = [];
14744                 var values = v.split("^");
14745                 for(var i = 0, len = values.length; i < len; i++){
14746                     all.push(this.decodeValue(values[i]));
14747                 }
14748                 return all;
14749            case "o":
14750                 var all = {};
14751                 var values = v.split("^");
14752                 for(var i = 0, len = values.length; i < len; i++){
14753                     var kv = values[i].split("=");
14754                     all[kv[0]] = this.decodeValue(kv[1]);
14755                 }
14756                 return all;
14757            default:
14758                 return v;
14759         }
14760     },
14761     
14762     /**
14763      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14764      * @param {Mixed} value The value to encode
14765      * @return {String} The encoded value
14766      */
14767     encodeValue : function(v){
14768         var enc;
14769         if(typeof v == "number"){
14770             enc = "n:" + v;
14771         }else if(typeof v == "boolean"){
14772             enc = "b:" + (v ? "1" : "0");
14773         }else if(v instanceof Date){
14774             enc = "d:" + v.toGMTString();
14775         }else if(v instanceof Array){
14776             var flat = "";
14777             for(var i = 0, len = v.length; i < len; i++){
14778                 flat += this.encodeValue(v[i]);
14779                 if(i != len-1) flat += "^";
14780             }
14781             enc = "a:" + flat;
14782         }else if(typeof v == "object"){
14783             var flat = "";
14784             for(var key in v){
14785                 if(typeof v[key] != "function"){
14786                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14787                 }
14788             }
14789             enc = "o:" + flat.substring(0, flat.length-1);
14790         }else{
14791             enc = "s:" + v;
14792         }
14793         return escape(enc);        
14794     }
14795 });
14796
14797 /*
14798  * Based on:
14799  * Ext JS Library 1.1.1
14800  * Copyright(c) 2006-2007, Ext JS, LLC.
14801  *
14802  * Originally Released Under LGPL - original licence link has changed is not relivant.
14803  *
14804  * Fork - LGPL
14805  * <script type="text/javascript">
14806  */
14807 /**
14808  * @class Roo.state.Manager
14809  * This is the global state manager. By default all components that are "state aware" check this class
14810  * for state information if you don't pass them a custom state provider. In order for this class
14811  * to be useful, it must be initialized with a provider when your application initializes.
14812  <pre><code>
14813 // in your initialization function
14814 init : function(){
14815    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14816    ...
14817    // supposed you have a {@link Roo.BorderLayout}
14818    var layout = new Roo.BorderLayout(...);
14819    layout.restoreState();
14820    // or a {Roo.BasicDialog}
14821    var dialog = new Roo.BasicDialog(...);
14822    dialog.restoreState();
14823  </code></pre>
14824  * @singleton
14825  */
14826 Roo.state.Manager = function(){
14827     var provider = new Roo.state.Provider();
14828     
14829     return {
14830         /**
14831          * Configures the default state provider for your application
14832          * @param {Provider} stateProvider The state provider to set
14833          */
14834         setProvider : function(stateProvider){
14835             provider = stateProvider;
14836         },
14837         
14838         /**
14839          * Returns the current value for a key
14840          * @param {String} name The key name
14841          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14842          * @return {Mixed} The state data
14843          */
14844         get : function(key, defaultValue){
14845             return provider.get(key, defaultValue);
14846         },
14847         
14848         /**
14849          * Sets the value for a key
14850          * @param {String} name The key name
14851          * @param {Mixed} value The state data
14852          */
14853          set : function(key, value){
14854             provider.set(key, value);
14855         },
14856         
14857         /**
14858          * Clears a value from the state
14859          * @param {String} name The key name
14860          */
14861         clear : function(key){
14862             provider.clear(key);
14863         },
14864         
14865         /**
14866          * Gets the currently configured state provider
14867          * @return {Provider} The state provider
14868          */
14869         getProvider : function(){
14870             return provider;
14871         }
14872     };
14873 }();
14874 /*
14875  * Based on:
14876  * Ext JS Library 1.1.1
14877  * Copyright(c) 2006-2007, Ext JS, LLC.
14878  *
14879  * Originally Released Under LGPL - original licence link has changed is not relivant.
14880  *
14881  * Fork - LGPL
14882  * <script type="text/javascript">
14883  */
14884 /**
14885  * @class Roo.state.CookieProvider
14886  * @extends Roo.state.Provider
14887  * The default Provider implementation which saves state via cookies.
14888  * <br />Usage:
14889  <pre><code>
14890    var cp = new Roo.state.CookieProvider({
14891        path: "/cgi-bin/",
14892        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14893        domain: "roojs.com"
14894    })
14895    Roo.state.Manager.setProvider(cp);
14896  </code></pre>
14897  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14898  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14899  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14900  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14901  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14902  * domain the page is running on including the 'www' like 'www.roojs.com')
14903  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14904  * @constructor
14905  * Create a new CookieProvider
14906  * @param {Object} config The configuration object
14907  */
14908 Roo.state.CookieProvider = function(config){
14909     Roo.state.CookieProvider.superclass.constructor.call(this);
14910     this.path = "/";
14911     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14912     this.domain = null;
14913     this.secure = false;
14914     Roo.apply(this, config);
14915     this.state = this.readCookies();
14916 };
14917
14918 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14919     // private
14920     set : function(name, value){
14921         if(typeof value == "undefined" || value === null){
14922             this.clear(name);
14923             return;
14924         }
14925         this.setCookie(name, value);
14926         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14927     },
14928
14929     // private
14930     clear : function(name){
14931         this.clearCookie(name);
14932         Roo.state.CookieProvider.superclass.clear.call(this, name);
14933     },
14934
14935     // private
14936     readCookies : function(){
14937         var cookies = {};
14938         var c = document.cookie + ";";
14939         var re = /\s?(.*?)=(.*?);/g;
14940         var matches;
14941         while((matches = re.exec(c)) != null){
14942             var name = matches[1];
14943             var value = matches[2];
14944             if(name && name.substring(0,3) == "ys-"){
14945                 cookies[name.substr(3)] = this.decodeValue(value);
14946             }
14947         }
14948         return cookies;
14949     },
14950
14951     // private
14952     setCookie : function(name, value){
14953         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14954            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14955            ((this.path == null) ? "" : ("; path=" + this.path)) +
14956            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14957            ((this.secure == true) ? "; secure" : "");
14958     },
14959
14960     // private
14961     clearCookie : function(name){
14962         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14963            ((this.path == null) ? "" : ("; path=" + this.path)) +
14964            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14965            ((this.secure == true) ? "; secure" : "");
14966     }
14967 });/*
14968  * Based on:
14969  * Ext JS Library 1.1.1
14970  * Copyright(c) 2006-2007, Ext JS, LLC.
14971  *
14972  * Originally Released Under LGPL - original licence link has changed is not relivant.
14973  *
14974  * Fork - LGPL
14975  * <script type="text/javascript">
14976  */
14977  
14978
14979 /**
14980  * @class Roo.ComponentMgr
14981  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14982  * @singleton
14983  */
14984 Roo.ComponentMgr = function(){
14985     var all = new Roo.util.MixedCollection();
14986
14987     return {
14988         /**
14989          * Registers a component.
14990          * @param {Roo.Component} c The component
14991          */
14992         register : function(c){
14993             all.add(c);
14994         },
14995
14996         /**
14997          * Unregisters a component.
14998          * @param {Roo.Component} c The component
14999          */
15000         unregister : function(c){
15001             all.remove(c);
15002         },
15003
15004         /**
15005          * Returns a component by id
15006          * @param {String} id The component id
15007          */
15008         get : function(id){
15009             return all.get(id);
15010         },
15011
15012         /**
15013          * Registers a function that will be called when a specified component is added to ComponentMgr
15014          * @param {String} id The component id
15015          * @param {Funtction} fn The callback function
15016          * @param {Object} scope The scope of the callback
15017          */
15018         onAvailable : function(id, fn, scope){
15019             all.on("add", function(index, o){
15020                 if(o.id == id){
15021                     fn.call(scope || o, o);
15022                     all.un("add", fn, scope);
15023                 }
15024             });
15025         }
15026     };
15027 }();/*
15028  * Based on:
15029  * Ext JS Library 1.1.1
15030  * Copyright(c) 2006-2007, Ext JS, LLC.
15031  *
15032  * Originally Released Under LGPL - original licence link has changed is not relivant.
15033  *
15034  * Fork - LGPL
15035  * <script type="text/javascript">
15036  */
15037  
15038 /**
15039  * @class Roo.Component
15040  * @extends Roo.util.Observable
15041  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15042  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15043  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15044  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15045  * All visual components (widgets) that require rendering into a layout should subclass Component.
15046  * @constructor
15047  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15048  * 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
15049  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15050  */
15051 Roo.Component = function(config){
15052     config = config || {};
15053     if(config.tagName || config.dom || typeof config == "string"){ // element object
15054         config = {el: config, id: config.id || config};
15055     }
15056     this.initialConfig = config;
15057
15058     Roo.apply(this, config);
15059     this.addEvents({
15060         /**
15061          * @event disable
15062          * Fires after the component is disabled.
15063              * @param {Roo.Component} this
15064              */
15065         disable : true,
15066         /**
15067          * @event enable
15068          * Fires after the component is enabled.
15069              * @param {Roo.Component} this
15070              */
15071         enable : true,
15072         /**
15073          * @event beforeshow
15074          * Fires before the component is shown.  Return false to stop the show.
15075              * @param {Roo.Component} this
15076              */
15077         beforeshow : true,
15078         /**
15079          * @event show
15080          * Fires after the component is shown.
15081              * @param {Roo.Component} this
15082              */
15083         show : true,
15084         /**
15085          * @event beforehide
15086          * Fires before the component is hidden. Return false to stop the hide.
15087              * @param {Roo.Component} this
15088              */
15089         beforehide : true,
15090         /**
15091          * @event hide
15092          * Fires after the component is hidden.
15093              * @param {Roo.Component} this
15094              */
15095         hide : true,
15096         /**
15097          * @event beforerender
15098          * Fires before the component is rendered. Return false to stop the render.
15099              * @param {Roo.Component} this
15100              */
15101         beforerender : true,
15102         /**
15103          * @event render
15104          * Fires after the component is rendered.
15105              * @param {Roo.Component} this
15106              */
15107         render : true,
15108         /**
15109          * @event beforedestroy
15110          * Fires before the component is destroyed. Return false to stop the destroy.
15111              * @param {Roo.Component} this
15112              */
15113         beforedestroy : true,
15114         /**
15115          * @event destroy
15116          * Fires after the component is destroyed.
15117              * @param {Roo.Component} this
15118              */
15119         destroy : true
15120     });
15121     if(!this.id){
15122         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15123     }
15124     Roo.ComponentMgr.register(this);
15125     Roo.Component.superclass.constructor.call(this);
15126     this.initComponent();
15127     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15128         this.render(this.renderTo);
15129         delete this.renderTo;
15130     }
15131 };
15132
15133 /** @private */
15134 Roo.Component.AUTO_ID = 1000;
15135
15136 Roo.extend(Roo.Component, Roo.util.Observable, {
15137     /**
15138      * @scope Roo.Component.prototype
15139      * @type {Boolean}
15140      * true if this component is hidden. Read-only.
15141      */
15142     hidden : false,
15143     /**
15144      * @type {Boolean}
15145      * true if this component is disabled. Read-only.
15146      */
15147     disabled : false,
15148     /**
15149      * @type {Boolean}
15150      * true if this component has been rendered. Read-only.
15151      */
15152     rendered : false,
15153     
15154     /** @cfg {String} disableClass
15155      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15156      */
15157     disabledClass : "x-item-disabled",
15158         /** @cfg {Boolean} allowDomMove
15159          * Whether the component can move the Dom node when rendering (defaults to true).
15160          */
15161     allowDomMove : true,
15162     /** @cfg {String} hideMode
15163      * How this component should hidden. Supported values are
15164      * "visibility" (css visibility), "offsets" (negative offset position) and
15165      * "display" (css display) - defaults to "display".
15166      */
15167     hideMode: 'display',
15168
15169     /** @private */
15170     ctype : "Roo.Component",
15171
15172     /**
15173      * @cfg {String} actionMode 
15174      * which property holds the element that used for  hide() / show() / disable() / enable()
15175      * default is 'el' 
15176      */
15177     actionMode : "el",
15178
15179     /** @private */
15180     getActionEl : function(){
15181         return this[this.actionMode];
15182     },
15183
15184     initComponent : Roo.emptyFn,
15185     /**
15186      * If this is a lazy rendering component, render it to its container element.
15187      * @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.
15188      */
15189     render : function(container, position){
15190         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15191             if(!container && this.el){
15192                 this.el = Roo.get(this.el);
15193                 container = this.el.dom.parentNode;
15194                 this.allowDomMove = false;
15195             }
15196             this.container = Roo.get(container);
15197             this.rendered = true;
15198             if(position !== undefined){
15199                 if(typeof position == 'number'){
15200                     position = this.container.dom.childNodes[position];
15201                 }else{
15202                     position = Roo.getDom(position);
15203                 }
15204             }
15205             this.onRender(this.container, position || null);
15206             if(this.cls){
15207                 this.el.addClass(this.cls);
15208                 delete this.cls;
15209             }
15210             if(this.style){
15211                 this.el.applyStyles(this.style);
15212                 delete this.style;
15213             }
15214             this.fireEvent("render", this);
15215             this.afterRender(this.container);
15216             if(this.hidden){
15217                 this.hide();
15218             }
15219             if(this.disabled){
15220                 this.disable();
15221             }
15222         }
15223         return this;
15224     },
15225
15226     /** @private */
15227     // default function is not really useful
15228     onRender : function(ct, position){
15229         if(this.el){
15230             this.el = Roo.get(this.el);
15231             if(this.allowDomMove !== false){
15232                 ct.dom.insertBefore(this.el.dom, position);
15233             }
15234         }
15235     },
15236
15237     /** @private */
15238     getAutoCreate : function(){
15239         var cfg = typeof this.autoCreate == "object" ?
15240                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15241         if(this.id && !cfg.id){
15242             cfg.id = this.id;
15243         }
15244         return cfg;
15245     },
15246
15247     /** @private */
15248     afterRender : Roo.emptyFn,
15249
15250     /**
15251      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15252      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15253      */
15254     destroy : function(){
15255         if(this.fireEvent("beforedestroy", this) !== false){
15256             this.purgeListeners();
15257             this.beforeDestroy();
15258             if(this.rendered){
15259                 this.el.removeAllListeners();
15260                 this.el.remove();
15261                 if(this.actionMode == "container"){
15262                     this.container.remove();
15263                 }
15264             }
15265             this.onDestroy();
15266             Roo.ComponentMgr.unregister(this);
15267             this.fireEvent("destroy", this);
15268         }
15269     },
15270
15271         /** @private */
15272     beforeDestroy : function(){
15273
15274     },
15275
15276         /** @private */
15277         onDestroy : function(){
15278
15279     },
15280
15281     /**
15282      * Returns the underlying {@link Roo.Element}.
15283      * @return {Roo.Element} The element
15284      */
15285     getEl : function(){
15286         return this.el;
15287     },
15288
15289     /**
15290      * Returns the id of this component.
15291      * @return {String}
15292      */
15293     getId : function(){
15294         return this.id;
15295     },
15296
15297     /**
15298      * Try to focus this component.
15299      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15300      * @return {Roo.Component} this
15301      */
15302     focus : function(selectText){
15303         if(this.rendered){
15304             this.el.focus();
15305             if(selectText === true){
15306                 this.el.dom.select();
15307             }
15308         }
15309         return this;
15310     },
15311
15312     /** @private */
15313     blur : function(){
15314         if(this.rendered){
15315             this.el.blur();
15316         }
15317         return this;
15318     },
15319
15320     /**
15321      * Disable this component.
15322      * @return {Roo.Component} this
15323      */
15324     disable : function(){
15325         if(this.rendered){
15326             this.onDisable();
15327         }
15328         this.disabled = true;
15329         this.fireEvent("disable", this);
15330         return this;
15331     },
15332
15333         // private
15334     onDisable : function(){
15335         this.getActionEl().addClass(this.disabledClass);
15336         this.el.dom.disabled = true;
15337     },
15338
15339     /**
15340      * Enable this component.
15341      * @return {Roo.Component} this
15342      */
15343     enable : function(){
15344         if(this.rendered){
15345             this.onEnable();
15346         }
15347         this.disabled = false;
15348         this.fireEvent("enable", this);
15349         return this;
15350     },
15351
15352         // private
15353     onEnable : function(){
15354         this.getActionEl().removeClass(this.disabledClass);
15355         this.el.dom.disabled = false;
15356     },
15357
15358     /**
15359      * Convenience function for setting disabled/enabled by boolean.
15360      * @param {Boolean} disabled
15361      */
15362     setDisabled : function(disabled){
15363         this[disabled ? "disable" : "enable"]();
15364     },
15365
15366     /**
15367      * Show this component.
15368      * @return {Roo.Component} this
15369      */
15370     show: function(){
15371         if(this.fireEvent("beforeshow", this) !== false){
15372             this.hidden = false;
15373             if(this.rendered){
15374                 this.onShow();
15375             }
15376             this.fireEvent("show", this);
15377         }
15378         return this;
15379     },
15380
15381     // private
15382     onShow : function(){
15383         var ae = this.getActionEl();
15384         if(this.hideMode == 'visibility'){
15385             ae.dom.style.visibility = "visible";
15386         }else if(this.hideMode == 'offsets'){
15387             ae.removeClass('x-hidden');
15388         }else{
15389             ae.dom.style.display = "";
15390         }
15391     },
15392
15393     /**
15394      * Hide this component.
15395      * @return {Roo.Component} this
15396      */
15397     hide: function(){
15398         if(this.fireEvent("beforehide", this) !== false){
15399             this.hidden = true;
15400             if(this.rendered){
15401                 this.onHide();
15402             }
15403             this.fireEvent("hide", this);
15404         }
15405         return this;
15406     },
15407
15408     // private
15409     onHide : function(){
15410         var ae = this.getActionEl();
15411         if(this.hideMode == 'visibility'){
15412             ae.dom.style.visibility = "hidden";
15413         }else if(this.hideMode == 'offsets'){
15414             ae.addClass('x-hidden');
15415         }else{
15416             ae.dom.style.display = "none";
15417         }
15418     },
15419
15420     /**
15421      * Convenience function to hide or show this component by boolean.
15422      * @param {Boolean} visible True to show, false to hide
15423      * @return {Roo.Component} this
15424      */
15425     setVisible: function(visible){
15426         if(visible) {
15427             this.show();
15428         }else{
15429             this.hide();
15430         }
15431         return this;
15432     },
15433
15434     /**
15435      * Returns true if this component is visible.
15436      */
15437     isVisible : function(){
15438         return this.getActionEl().isVisible();
15439     },
15440
15441     cloneConfig : function(overrides){
15442         overrides = overrides || {};
15443         var id = overrides.id || Roo.id();
15444         var cfg = Roo.applyIf(overrides, this.initialConfig);
15445         cfg.id = id; // prevent dup id
15446         return new this.constructor(cfg);
15447     }
15448 });/*
15449  * Based on:
15450  * Ext JS Library 1.1.1
15451  * Copyright(c) 2006-2007, Ext JS, LLC.
15452  *
15453  * Originally Released Under LGPL - original licence link has changed is not relivant.
15454  *
15455  * Fork - LGPL
15456  * <script type="text/javascript">
15457  */
15458
15459 /**
15460  * @class Roo.BoxComponent
15461  * @extends Roo.Component
15462  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15463  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15464  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15465  * layout containers.
15466  * @constructor
15467  * @param {Roo.Element/String/Object} config The configuration options.
15468  */
15469 Roo.BoxComponent = function(config){
15470     Roo.Component.call(this, config);
15471     this.addEvents({
15472         /**
15473          * @event resize
15474          * Fires after the component is resized.
15475              * @param {Roo.Component} this
15476              * @param {Number} adjWidth The box-adjusted width that was set
15477              * @param {Number} adjHeight The box-adjusted height that was set
15478              * @param {Number} rawWidth The width that was originally specified
15479              * @param {Number} rawHeight The height that was originally specified
15480              */
15481         resize : true,
15482         /**
15483          * @event move
15484          * Fires after the component is moved.
15485              * @param {Roo.Component} this
15486              * @param {Number} x The new x position
15487              * @param {Number} y The new y position
15488              */
15489         move : true
15490     });
15491 };
15492
15493 Roo.extend(Roo.BoxComponent, Roo.Component, {
15494     // private, set in afterRender to signify that the component has been rendered
15495     boxReady : false,
15496     // private, used to defer height settings to subclasses
15497     deferHeight: false,
15498     /** @cfg {Number} width
15499      * width (optional) size of component
15500      */
15501      /** @cfg {Number} height
15502      * height (optional) size of component
15503      */
15504      
15505     /**
15506      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15507      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15508      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15509      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15510      * @return {Roo.BoxComponent} this
15511      */
15512     setSize : function(w, h){
15513         // support for standard size objects
15514         if(typeof w == 'object'){
15515             h = w.height;
15516             w = w.width;
15517         }
15518         // not rendered
15519         if(!this.boxReady){
15520             this.width = w;
15521             this.height = h;
15522             return this;
15523         }
15524
15525         // prevent recalcs when not needed
15526         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15527             return this;
15528         }
15529         this.lastSize = {width: w, height: h};
15530
15531         var adj = this.adjustSize(w, h);
15532         var aw = adj.width, ah = adj.height;
15533         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15534             var rz = this.getResizeEl();
15535             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15536                 rz.setSize(aw, ah);
15537             }else if(!this.deferHeight && ah !== undefined){
15538                 rz.setHeight(ah);
15539             }else if(aw !== undefined){
15540                 rz.setWidth(aw);
15541             }
15542             this.onResize(aw, ah, w, h);
15543             this.fireEvent('resize', this, aw, ah, w, h);
15544         }
15545         return this;
15546     },
15547
15548     /**
15549      * Gets the current size of the component's underlying element.
15550      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15551      */
15552     getSize : function(){
15553         return this.el.getSize();
15554     },
15555
15556     /**
15557      * Gets the current XY position of the component's underlying element.
15558      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15559      * @return {Array} The XY position of the element (e.g., [100, 200])
15560      */
15561     getPosition : function(local){
15562         if(local === true){
15563             return [this.el.getLeft(true), this.el.getTop(true)];
15564         }
15565         return this.xy || this.el.getXY();
15566     },
15567
15568     /**
15569      * Gets the current box measurements of the component's underlying element.
15570      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15571      * @returns {Object} box An object in the format {x, y, width, height}
15572      */
15573     getBox : function(local){
15574         var s = this.el.getSize();
15575         if(local){
15576             s.x = this.el.getLeft(true);
15577             s.y = this.el.getTop(true);
15578         }else{
15579             var xy = this.xy || this.el.getXY();
15580             s.x = xy[0];
15581             s.y = xy[1];
15582         }
15583         return s;
15584     },
15585
15586     /**
15587      * Sets the current box measurements of the component's underlying element.
15588      * @param {Object} box An object in the format {x, y, width, height}
15589      * @returns {Roo.BoxComponent} this
15590      */
15591     updateBox : function(box){
15592         this.setSize(box.width, box.height);
15593         this.setPagePosition(box.x, box.y);
15594         return this;
15595     },
15596
15597     // protected
15598     getResizeEl : function(){
15599         return this.resizeEl || this.el;
15600     },
15601
15602     // protected
15603     getPositionEl : function(){
15604         return this.positionEl || this.el;
15605     },
15606
15607     /**
15608      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15609      * This method fires the move event.
15610      * @param {Number} left The new left
15611      * @param {Number} top The new top
15612      * @returns {Roo.BoxComponent} this
15613      */
15614     setPosition : function(x, y){
15615         this.x = x;
15616         this.y = y;
15617         if(!this.boxReady){
15618             return this;
15619         }
15620         var adj = this.adjustPosition(x, y);
15621         var ax = adj.x, ay = adj.y;
15622
15623         var el = this.getPositionEl();
15624         if(ax !== undefined || ay !== undefined){
15625             if(ax !== undefined && ay !== undefined){
15626                 el.setLeftTop(ax, ay);
15627             }else if(ax !== undefined){
15628                 el.setLeft(ax);
15629             }else if(ay !== undefined){
15630                 el.setTop(ay);
15631             }
15632             this.onPosition(ax, ay);
15633             this.fireEvent('move', this, ax, ay);
15634         }
15635         return this;
15636     },
15637
15638     /**
15639      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15640      * This method fires the move event.
15641      * @param {Number} x The new x position
15642      * @param {Number} y The new y position
15643      * @returns {Roo.BoxComponent} this
15644      */
15645     setPagePosition : function(x, y){
15646         this.pageX = x;
15647         this.pageY = y;
15648         if(!this.boxReady){
15649             return;
15650         }
15651         if(x === undefined || y === undefined){ // cannot translate undefined points
15652             return;
15653         }
15654         var p = this.el.translatePoints(x, y);
15655         this.setPosition(p.left, p.top);
15656         return this;
15657     },
15658
15659     // private
15660     onRender : function(ct, position){
15661         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15662         if(this.resizeEl){
15663             this.resizeEl = Roo.get(this.resizeEl);
15664         }
15665         if(this.positionEl){
15666             this.positionEl = Roo.get(this.positionEl);
15667         }
15668     },
15669
15670     // private
15671     afterRender : function(){
15672         Roo.BoxComponent.superclass.afterRender.call(this);
15673         this.boxReady = true;
15674         this.setSize(this.width, this.height);
15675         if(this.x || this.y){
15676             this.setPosition(this.x, this.y);
15677         }
15678         if(this.pageX || this.pageY){
15679             this.setPagePosition(this.pageX, this.pageY);
15680         }
15681     },
15682
15683     /**
15684      * Force the component's size to recalculate based on the underlying element's current height and width.
15685      * @returns {Roo.BoxComponent} this
15686      */
15687     syncSize : function(){
15688         delete this.lastSize;
15689         this.setSize(this.el.getWidth(), this.el.getHeight());
15690         return this;
15691     },
15692
15693     /**
15694      * Called after the component is resized, this method is empty by default but can be implemented by any
15695      * subclass that needs to perform custom logic after a resize occurs.
15696      * @param {Number} adjWidth The box-adjusted width that was set
15697      * @param {Number} adjHeight The box-adjusted height that was set
15698      * @param {Number} rawWidth The width that was originally specified
15699      * @param {Number} rawHeight The height that was originally specified
15700      */
15701     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15702
15703     },
15704
15705     /**
15706      * Called after the component is moved, this method is empty by default but can be implemented by any
15707      * subclass that needs to perform custom logic after a move occurs.
15708      * @param {Number} x The new x position
15709      * @param {Number} y The new y position
15710      */
15711     onPosition : function(x, y){
15712
15713     },
15714
15715     // private
15716     adjustSize : function(w, h){
15717         if(this.autoWidth){
15718             w = 'auto';
15719         }
15720         if(this.autoHeight){
15721             h = 'auto';
15722         }
15723         return {width : w, height: h};
15724     },
15725
15726     // private
15727     adjustPosition : function(x, y){
15728         return {x : x, y: y};
15729     }
15730 });/*
15731  * Original code for Roojs - LGPL
15732  * <script type="text/javascript">
15733  */
15734  
15735 /**
15736  * @class Roo.XComponent
15737  * A delayed Element creator...
15738  * Or a way to group chunks of interface together.
15739  * 
15740  * Mypart.xyx = new Roo.XComponent({
15741
15742     parent : 'Mypart.xyz', // empty == document.element.!!
15743     order : '001',
15744     name : 'xxxx'
15745     region : 'xxxx'
15746     disabled : function() {} 
15747      
15748     tree : function() { // return an tree of xtype declared components
15749         var MODULE = this;
15750         return 
15751         {
15752             xtype : 'NestedLayoutPanel',
15753             // technicall
15754         }
15755      ]
15756  *})
15757  *
15758  *
15759  * It can be used to build a big heiracy, with parent etc.
15760  * or you can just use this to render a single compoent to a dom element
15761  * MYPART.render(Roo.Element | String(id) | dom_element )
15762  * 
15763  * @extends Roo.util.Observable
15764  * @constructor
15765  * @param cfg {Object} configuration of component
15766  * 
15767  */
15768 Roo.XComponent = function(cfg) {
15769     Roo.apply(this, cfg);
15770     this.addEvents({ 
15771         /**
15772              * @event built
15773              * Fires when this the componnt is built
15774              * @param {Roo.XComponent} c the component
15775              */
15776         'built' : true
15777         
15778     });
15779     this.region = this.region || 'center'; // default..
15780     Roo.XComponent.register(this);
15781     this.modules = false;
15782     this.el = false; // where the layout goes..
15783     
15784     
15785 }
15786 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15787     /**
15788      * @property el
15789      * The created element (with Roo.factory())
15790      * @type {Roo.Layout}
15791      */
15792     el  : false,
15793     
15794     /**
15795      * @property el
15796      * for BC  - use el in new code
15797      * @type {Roo.Layout}
15798      */
15799     panel : false,
15800     
15801     /**
15802      * @property layout
15803      * for BC  - use el in new code
15804      * @type {Roo.Layout}
15805      */
15806     layout : false,
15807     
15808      /**
15809      * @cfg {Function|boolean} disabled
15810      * If this module is disabled by some rule, return true from the funtion
15811      */
15812     disabled : false,
15813     
15814     /**
15815      * @cfg {String} parent 
15816      * Name of parent element which it get xtype added to..
15817      */
15818     parent: false,
15819     
15820     /**
15821      * @cfg {String} order
15822      * Used to set the order in which elements are created (usefull for multiple tabs)
15823      */
15824     
15825     order : false,
15826     /**
15827      * @cfg {String} name
15828      * String to display while loading.
15829      */
15830     name : false,
15831     /**
15832      * @cfg {String} region
15833      * Region to render component to (defaults to center)
15834      */
15835     region : 'center',
15836     
15837     /**
15838      * @cfg {Array} items
15839      * A single item array - the first element is the root of the tree..
15840      * It's done this way to stay compatible with the Xtype system...
15841      */
15842     items : false,
15843     
15844     /**
15845      * @property _tree
15846      * The method that retuns the tree of parts that make up this compoennt 
15847      * @type {function}
15848      */
15849     _tree  : false,
15850     
15851      /**
15852      * render
15853      * render element to dom or tree
15854      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15855      */
15856     
15857     render : function(el)
15858     {
15859         
15860         el = el || false;
15861         var hp = this.parent ? 1 : 0;
15862         
15863         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15864             // if parent is a '#.....' string, then let's use that..
15865             var ename = this.parent.substr(1)
15866             this.parent = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
15867             el = Roo.get(ename);
15868             if (!el && !this.parent) {
15869                 Roo.log("Warning - element can not be found :#" + ename );
15870                 return;
15871             }
15872         }
15873         var tree = this._tree ? this._tree() : this.tree();
15874
15875         
15876         if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15877             //el = Roo.get(document.body);
15878             this.parent = { el : true };
15879         }
15880             
15881             
15882         
15883         if (!this.parent) {
15884             
15885             Roo.log("no parent - creating one");
15886             
15887             el = el ? Roo.get(el) : false;      
15888             
15889             // it's a top level one..
15890             this.parent =  {
15891                 el : new Roo.BorderLayout(el || document.body, {
15892                 
15893                      center: {
15894                          titlebar: false,
15895                          autoScroll:false,
15896                          closeOnTab: true,
15897                          tabPosition: 'top',
15898                           //resizeTabs: true,
15899                          alwaysShowTabs: el && hp? false :  true,
15900                          hideTabs: el || !hp ? true :  false,
15901                          minTabWidth: 140
15902                      }
15903                  })
15904             }
15905         }
15906         
15907                 if (!this.parent.el) {
15908                         // probably an old style ctor, which has been disabled.
15909                         return;
15910                         
15911                 }
15912                 // The 'tree' method is  '_tree now' 
15913             
15914         tree.region = tree.region || this.region;
15915         
15916         if (this.parent.el === true) {
15917             // bootstrap... - body..
15918             this.parent.el = Roo.factory(tree);
15919         }
15920         
15921         this.el = this.parent.el.addxtype(tree);
15922         this.fireEvent('built', this);
15923         
15924         this.panel = this.el;
15925         this.layout = this.panel.layout;
15926                 this.parentLayout = this.parent.layout  || false;  
15927          
15928     }
15929     
15930 });
15931
15932 Roo.apply(Roo.XComponent, {
15933     /**
15934      * @property  hideProgress
15935      * true to disable the building progress bar.. usefull on single page renders.
15936      * @type Boolean
15937      */
15938     hideProgress : false,
15939     /**
15940      * @property  buildCompleted
15941      * True when the builder has completed building the interface.
15942      * @type Boolean
15943      */
15944     buildCompleted : false,
15945      
15946     /**
15947      * @property  topModule
15948      * the upper most module - uses document.element as it's constructor.
15949      * @type Object
15950      */
15951      
15952     topModule  : false,
15953       
15954     /**
15955      * @property  modules
15956      * array of modules to be created by registration system.
15957      * @type {Array} of Roo.XComponent
15958      */
15959     
15960     modules : [],
15961     /**
15962      * @property  elmodules
15963      * array of modules to be created by which use #ID 
15964      * @type {Array} of Roo.XComponent
15965      */
15966      
15967     elmodules : [],
15968
15969      /**
15970      * @property  build_from_html
15971      * Build elements from html - used by bootstrap HTML stuff 
15972      *    - this is cleared after build is completed
15973      * @type {boolean} true  (default false)
15974      */
15975      
15976     build_from_html : false,
15977
15978     /**
15979      * Register components to be built later.
15980      *
15981      * This solves the following issues
15982      * - Building is not done on page load, but after an authentication process has occured.
15983      * - Interface elements are registered on page load
15984      * - Parent Interface elements may not be loaded before child, so this handles that..
15985      * 
15986      *
15987      * example:
15988      * 
15989      * MyApp.register({
15990           order : '000001',
15991           module : 'Pman.Tab.projectMgr',
15992           region : 'center',
15993           parent : 'Pman.layout',
15994           disabled : false,  // or use a function..
15995         })
15996      
15997      * * @param {Object} details about module
15998      */
15999     register : function(obj) {
16000                 
16001         Roo.XComponent.event.fireEvent('register', obj);
16002         switch(typeof(obj.disabled) ) {
16003                 
16004             case 'undefined':
16005                 break;
16006             
16007             case 'function':
16008                 if ( obj.disabled() ) {
16009                         return;
16010                 }
16011                 break;
16012             
16013             default:
16014                 if (obj.disabled) {
16015                         return;
16016                 }
16017                 break;
16018         }
16019                 
16020         this.modules.push(obj);
16021          
16022     },
16023     /**
16024      * convert a string to an object..
16025      * eg. 'AAA.BBB' -> finds AAA.BBB
16026
16027      */
16028     
16029     toObject : function(str)
16030     {
16031         if (!str || typeof(str) == 'object') {
16032             return str;
16033         }
16034         if (str.substring(0,1) == '#') {
16035             return str;
16036         }
16037
16038         var ar = str.split('.');
16039         var rt, o;
16040         rt = ar.shift();
16041             /** eval:var:o */
16042         try {
16043             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16044         } catch (e) {
16045             throw "Module not found : " + str;
16046         }
16047         
16048         if (o === false) {
16049             throw "Module not found : " + str;
16050         }
16051         Roo.each(ar, function(e) {
16052             if (typeof(o[e]) == 'undefined') {
16053                 throw "Module not found : " + str;
16054             }
16055             o = o[e];
16056         });
16057         
16058         return o;
16059         
16060     },
16061     
16062     
16063     /**
16064      * move modules into their correct place in the tree..
16065      * 
16066      */
16067     preBuild : function ()
16068     {
16069         var _t = this;
16070         Roo.each(this.modules , function (obj)
16071         {
16072             Roo.XComponent.event.fireEvent('beforebuild', obj);
16073             
16074             var opar = obj.parent;
16075             try { 
16076                 obj.parent = this.toObject(opar);
16077             } catch(e) {
16078                 Roo.log("parent:toObject failed: " + e.toString());
16079                 return;
16080             }
16081             
16082             if (!obj.parent) {
16083                 Roo.debug && Roo.log("GOT top level module");
16084                 Roo.debug && Roo.log(obj);
16085                 obj.modules = new Roo.util.MixedCollection(false, 
16086                     function(o) { return o.order + '' }
16087                 );
16088                 this.topModule = obj;
16089                 return;
16090             }
16091                         // parent is a string (usually a dom element name..)
16092             if (typeof(obj.parent) == 'string') {
16093                 this.elmodules.push(obj);
16094                 return;
16095             }
16096             if (obj.parent.constructor != Roo.XComponent) {
16097                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16098             }
16099             if (!obj.parent.modules) {
16100                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16101                     function(o) { return o.order + '' }
16102                 );
16103             }
16104             if (obj.parent.disabled) {
16105                 obj.disabled = true;
16106             }
16107             obj.parent.modules.add(obj);
16108         }, this);
16109     },
16110     
16111      /**
16112      * make a list of modules to build.
16113      * @return {Array} list of modules. 
16114      */ 
16115     
16116     buildOrder : function()
16117     {
16118         var _this = this;
16119         var cmp = function(a,b) {   
16120             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16121         };
16122         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16123             throw "No top level modules to build";
16124         }
16125         
16126         // make a flat list in order of modules to build.
16127         var mods = this.topModule ? [ this.topModule ] : [];
16128                 
16129         
16130         // elmodules (is a list of DOM based modules )
16131         Roo.each(this.elmodules, function(e) {
16132             mods.push(e);
16133             if (!this.topModule &&
16134                 typeof(e.parent) == 'string' &&
16135                 e.parent.substring(0,1) == '#' &&
16136                 Roo.get(e.parent.substr(1))
16137                ) {
16138                 
16139                 _this.topModule = e;
16140             }
16141             
16142         });
16143
16144         
16145         // add modules to their parents..
16146         var addMod = function(m) {
16147             Roo.debug && Roo.log("build Order: add: " + m.name);
16148                 
16149             mods.push(m);
16150             if (m.modules && !m.disabled) {
16151                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16152                 m.modules.keySort('ASC',  cmp );
16153                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16154     
16155                 m.modules.each(addMod);
16156             } else {
16157                 Roo.debug && Roo.log("build Order: no child modules");
16158             }
16159             // not sure if this is used any more..
16160             if (m.finalize) {
16161                 m.finalize.name = m.name + " (clean up) ";
16162                 mods.push(m.finalize);
16163             }
16164             
16165         }
16166         if (this.topModule && this.topModule.modules) { 
16167             this.topModule.modules.keySort('ASC',  cmp );
16168             this.topModule.modules.each(addMod);
16169         } 
16170         return mods;
16171     },
16172     
16173      /**
16174      * Build the registered modules.
16175      * @param {Object} parent element.
16176      * @param {Function} optional method to call after module has been added.
16177      * 
16178      */ 
16179    
16180     build : function(opts) 
16181     {
16182         
16183         if (typeof(opts) != 'undefined') {
16184             Roo.apply(this,opts);
16185         }
16186         
16187         this.preBuild();
16188         var mods = this.buildOrder();
16189       
16190         //this.allmods = mods;
16191         //Roo.debug && Roo.log(mods);
16192         //return;
16193         if (!mods.length) { // should not happen
16194             throw "NO modules!!!";
16195         }
16196         
16197         
16198         var msg = "Building Interface...";
16199         // flash it up as modal - so we store the mask!?
16200         if (!this.hideProgress && Roo.MessageBox) {
16201             Roo.MessageBox.show({ title: 'loading' });
16202             Roo.MessageBox.show({
16203                title: "Please wait...",
16204                msg: msg,
16205                width:450,
16206                progress:true,
16207                closable:false,
16208                modal: false
16209               
16210             });
16211         }
16212         var total = mods.length;
16213         
16214         var _this = this;
16215         var progressRun = function() {
16216             if (!mods.length) {
16217                 Roo.debug && Roo.log('hide?');
16218                 if (!this.hideProgress && Roo.MessageBox) {
16219                     Roo.MessageBox.hide();
16220                 }
16221                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16222                 
16223                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16224                 
16225                 // THE END...
16226                 return false;   
16227             }
16228             
16229             var m = mods.shift();
16230             
16231             
16232             Roo.debug && Roo.log(m);
16233             // not sure if this is supported any more.. - modules that are are just function
16234             if (typeof(m) == 'function') { 
16235                 m.call(this);
16236                 return progressRun.defer(10, _this);
16237             } 
16238             
16239             
16240             msg = "Building Interface " + (total  - mods.length) + 
16241                     " of " + total + 
16242                     (m.name ? (' - ' + m.name) : '');
16243                         Roo.debug && Roo.log(msg);
16244             if (!this.hideProgress &&  Roo.MessageBox) { 
16245                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16246             }
16247             
16248          
16249             // is the module disabled?
16250             var disabled = (typeof(m.disabled) == 'function') ?
16251                 m.disabled.call(m.module.disabled) : m.disabled;    
16252             
16253             
16254             if (disabled) {
16255                 return progressRun(); // we do not update the display!
16256             }
16257             
16258             // now build 
16259             
16260                         
16261                         
16262             m.render();
16263             // it's 10 on top level, and 1 on others??? why...
16264             return progressRun.defer(10, _this);
16265              
16266         }
16267         progressRun.defer(1, _this);
16268      
16269         
16270         
16271     },
16272         
16273         
16274         /**
16275          * Event Object.
16276          *
16277          *
16278          */
16279         event: false, 
16280     /**
16281          * wrapper for event.on - aliased later..  
16282          * Typically use to register a event handler for register:
16283          *
16284          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16285          *
16286          */
16287     on : false
16288    
16289     
16290     
16291 });
16292
16293 Roo.XComponent.event = new Roo.util.Observable({
16294                 events : { 
16295                         /**
16296                          * @event register
16297                          * Fires when an Component is registered,
16298                          * set the disable property on the Component to stop registration.
16299                          * @param {Roo.XComponent} c the component being registerd.
16300                          * 
16301                          */
16302                         'register' : true,
16303             /**
16304                          * @event beforebuild
16305                          * Fires before each Component is built
16306                          * can be used to apply permissions.
16307                          * @param {Roo.XComponent} c the component being registerd.
16308                          * 
16309                          */
16310                         'beforebuild' : true,
16311                         /**
16312                          * @event buildcomplete
16313                          * Fires on the top level element when all elements have been built
16314                          * @param {Roo.XComponent} the top level component.
16315                          */
16316                         'buildcomplete' : true
16317                         
16318                 }
16319 });
16320
16321 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16322