Roo/DomQuery.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                 Roo.log(modeRe);
5272                 while(!(mm = q.match(modeRe))){
5273                     var matched = false;
5274                     for(var j = 0; j < tklen; j++){
5275                         var t = tk[j];
5276                         var m = q.match(t.re);
5277                         if(m){
5278                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5279                                                     return m[i];
5280                                                 });
5281                             q = q.replace(m[0], "");
5282                             matched = true;
5283                             break;
5284                         }
5285                     }
5286                     // prevent infinite loop on bad selector
5287                     if(!matched){
5288                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5289                     }
5290                 }
5291                 if(mm[1]){
5292                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5293                     q = q.replace(mm[1], "");
5294                 }
5295             }
5296             fn[fn.length] = "return nodup(n);\n}";
5297             
5298              /** 
5299               * list of variables that need from compression as they are used by eval.
5300              *  eval:var:batch 
5301              *  eval:var:nodup
5302              *  eval:var:byTag
5303              *  eval:var:ById
5304              *  eval:var:getNodes
5305              *  eval:var:quickId
5306              *  eval:var:mode
5307              *  eval:var:root
5308              *  eval:var:n
5309              *  eval:var:byClassName
5310              *  eval:var:byPseudo
5311              *  eval:var:byAttribute
5312              *  eval:var:attrValue
5313              * 
5314              **/ 
5315             eval(fn.join(""));
5316             return f;
5317         },
5318
5319         /**
5320          * Selects a group of elements.
5321          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5322          * @param {Node} root (optional) The start of the query (defaults to document).
5323          * @return {Array}
5324          */
5325         select : function(path, root, type){
5326             if(!root || root == document){
5327                 root = document;
5328             }
5329             if(typeof root == "string"){
5330                 root = document.getElementById(root);
5331             }
5332             var paths = path.split(",");
5333             var results = [];
5334             for(var i = 0, len = paths.length; i < len; i++){
5335                 var p = paths[i].replace(trimRe, "");
5336                 if(!cache[p]){
5337                     cache[p] = Roo.DomQuery.compile(p);
5338                     if(!cache[p]){
5339                         throw p + " is not a valid selector";
5340                     }
5341                 }
5342                 var result = cache[p](root);
5343                 if(result && result != document){
5344                     results = results.concat(result);
5345                 }
5346             }
5347             if(paths.length > 1){
5348                 return nodup(results);
5349             }
5350             return results;
5351         },
5352
5353         /**
5354          * Selects a single element.
5355          * @param {String} selector The selector/xpath query
5356          * @param {Node} root (optional) The start of the query (defaults to document).
5357          * @return {Element}
5358          */
5359         selectNode : function(path, root){
5360             return Roo.DomQuery.select(path, root)[0];
5361         },
5362
5363         /**
5364          * Selects the value of a node, optionally replacing null with the defaultValue.
5365          * @param {String} selector The selector/xpath query
5366          * @param {Node} root (optional) The start of the query (defaults to document).
5367          * @param {String} defaultValue
5368          */
5369         selectValue : function(path, root, defaultValue){
5370             path = path.replace(trimRe, "");
5371             if(!valueCache[path]){
5372                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5373             }
5374             var n = valueCache[path](root);
5375             n = n[0] ? n[0] : n;
5376             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5377             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5378         },
5379
5380         /**
5381          * Selects the value of a node, parsing integers and floats.
5382          * @param {String} selector The selector/xpath query
5383          * @param {Node} root (optional) The start of the query (defaults to document).
5384          * @param {Number} defaultValue
5385          * @return {Number}
5386          */
5387         selectNumber : function(path, root, defaultValue){
5388             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5389             return parseFloat(v);
5390         },
5391
5392         /**
5393          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5394          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5395          * @param {String} selector The simple selector to test
5396          * @return {Boolean}
5397          */
5398         is : function(el, ss){
5399             if(typeof el == "string"){
5400                 el = document.getElementById(el);
5401             }
5402             var isArray = (el instanceof Array);
5403             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5404             return isArray ? (result.length == el.length) : (result.length > 0);
5405         },
5406
5407         /**
5408          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5409          * @param {Array} el An array of elements to filter
5410          * @param {String} selector The simple selector to test
5411          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5412          * the selector instead of the ones that match
5413          * @return {Array}
5414          */
5415         filter : function(els, ss, nonMatches){
5416             ss = ss.replace(trimRe, "");
5417             if(!simpleCache[ss]){
5418                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5419             }
5420             var result = simpleCache[ss](els);
5421             return nonMatches ? quickDiff(result, els) : result;
5422         },
5423
5424         /**
5425          * Collection of matching regular expressions and code snippets.
5426          */
5427         matchers : [{
5428                 re: /^\.([\w-]+)/,
5429                 select: 'n = byClassName(n, null, " {1} ");'
5430             }, {
5431                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5432                 select: 'n = byPseudo(n, "{1}", "{2}");'
5433             },{
5434                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5435                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5436             }, {
5437                 re: /^#([\w-]+)/,
5438                 select: 'n = byId(n, null, "{1}");'
5439             },{
5440                 re: /^@([\w-]+)/,
5441                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5442             }
5443         ],
5444
5445         /**
5446          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5447          * 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;.
5448          */
5449         operators : {
5450             "=" : function(a, v){
5451                 return a == v;
5452             },
5453             "!=" : function(a, v){
5454                 return a != v;
5455             },
5456             "^=" : function(a, v){
5457                 return a && a.substr(0, v.length) == v;
5458             },
5459             "$=" : function(a, v){
5460                 return a && a.substr(a.length-v.length) == v;
5461             },
5462             "*=" : function(a, v){
5463                 return a && a.indexOf(v) !== -1;
5464             },
5465             "%=" : function(a, v){
5466                 return (a % v) == 0;
5467             },
5468             "|=" : function(a, v){
5469                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5470             },
5471             "~=" : function(a, v){
5472                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5473             }
5474         },
5475
5476         /**
5477          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5478          * and the argument (if any) supplied in the selector.
5479          */
5480         pseudos : {
5481             "first-child" : function(c){
5482                 var r = [], ri = -1, n;
5483                 for(var i = 0, ci; ci = n = c[i]; i++){
5484                     while((n = n.previousSibling) && n.nodeType != 1);
5485                     if(!n){
5486                         r[++ri] = ci;
5487                     }
5488                 }
5489                 return r;
5490             },
5491
5492             "last-child" : function(c){
5493                 var r = [], ri = -1, n;
5494                 for(var i = 0, ci; ci = n = c[i]; i++){
5495                     while((n = n.nextSibling) && n.nodeType != 1);
5496                     if(!n){
5497                         r[++ri] = ci;
5498                     }
5499                 }
5500                 return r;
5501             },
5502
5503             "nth-child" : function(c, a) {
5504                 var r = [], ri = -1;
5505                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5506                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5507                 for(var i = 0, n; n = c[i]; i++){
5508                     var pn = n.parentNode;
5509                     if (batch != pn._batch) {
5510                         var j = 0;
5511                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5512                             if(cn.nodeType == 1){
5513                                cn.nodeIndex = ++j;
5514                             }
5515                         }
5516                         pn._batch = batch;
5517                     }
5518                     if (f == 1) {
5519                         if (l == 0 || n.nodeIndex == l){
5520                             r[++ri] = n;
5521                         }
5522                     } else if ((n.nodeIndex + l) % f == 0){
5523                         r[++ri] = n;
5524                     }
5525                 }
5526
5527                 return r;
5528             },
5529
5530             "only-child" : function(c){
5531                 var r = [], ri = -1;;
5532                 for(var i = 0, ci; ci = c[i]; i++){
5533                     if(!prev(ci) && !next(ci)){
5534                         r[++ri] = ci;
5535                     }
5536                 }
5537                 return r;
5538             },
5539
5540             "empty" : function(c){
5541                 var r = [], ri = -1;
5542                 for(var i = 0, ci; ci = c[i]; i++){
5543                     var cns = ci.childNodes, j = 0, cn, empty = true;
5544                     while(cn = cns[j]){
5545                         ++j;
5546                         if(cn.nodeType == 1 || cn.nodeType == 3){
5547                             empty = false;
5548                             break;
5549                         }
5550                     }
5551                     if(empty){
5552                         r[++ri] = ci;
5553                     }
5554                 }
5555                 return r;
5556             },
5557
5558             "contains" : function(c, v){
5559                 var r = [], ri = -1;
5560                 for(var i = 0, ci; ci = c[i]; i++){
5561                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5562                         r[++ri] = ci;
5563                     }
5564                 }
5565                 return r;
5566             },
5567
5568             "nodeValue" : function(c, v){
5569                 var r = [], ri = -1;
5570                 for(var i = 0, ci; ci = c[i]; i++){
5571                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5572                         r[++ri] = ci;
5573                     }
5574                 }
5575                 return r;
5576             },
5577
5578             "checked" : function(c){
5579                 var r = [], ri = -1;
5580                 for(var i = 0, ci; ci = c[i]; i++){
5581                     if(ci.checked == true){
5582                         r[++ri] = ci;
5583                     }
5584                 }
5585                 return r;
5586             },
5587
5588             "not" : function(c, ss){
5589                 return Roo.DomQuery.filter(c, ss, true);
5590             },
5591
5592             "odd" : function(c){
5593                 return this["nth-child"](c, "odd");
5594             },
5595
5596             "even" : function(c){
5597                 return this["nth-child"](c, "even");
5598             },
5599
5600             "nth" : function(c, a){
5601                 return c[a-1] || [];
5602             },
5603
5604             "first" : function(c){
5605                 return c[0] || [];
5606             },
5607
5608             "last" : function(c){
5609                 return c[c.length-1] || [];
5610             },
5611
5612             "has" : function(c, ss){
5613                 var s = Roo.DomQuery.select;
5614                 var r = [], ri = -1;
5615                 for(var i = 0, ci; ci = c[i]; i++){
5616                     if(s(ss, ci).length > 0){
5617                         r[++ri] = ci;
5618                     }
5619                 }
5620                 return r;
5621             },
5622
5623             "next" : function(c, ss){
5624                 var is = Roo.DomQuery.is;
5625                 var r = [], ri = -1;
5626                 for(var i = 0, ci; ci = c[i]; i++){
5627                     var n = next(ci);
5628                     if(n && is(n, ss)){
5629                         r[++ri] = ci;
5630                     }
5631                 }
5632                 return r;
5633             },
5634
5635             "prev" : function(c, ss){
5636                 var is = Roo.DomQuery.is;
5637                 var r = [], ri = -1;
5638                 for(var i = 0, ci; ci = c[i]; i++){
5639                     var n = prev(ci);
5640                     if(n && is(n, ss)){
5641                         r[++ri] = ci;
5642                     }
5643                 }
5644                 return r;
5645             }
5646         }
5647     };
5648 }();
5649
5650 /**
5651  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5652  * @param {String} path The selector/xpath query
5653  * @param {Node} root (optional) The start of the query (defaults to document).
5654  * @return {Array}
5655  * @member Roo
5656  * @method query
5657  */
5658 Roo.query = Roo.DomQuery.select;
5659 /*
5660  * Based on:
5661  * Ext JS Library 1.1.1
5662  * Copyright(c) 2006-2007, Ext JS, LLC.
5663  *
5664  * Originally Released Under LGPL - original licence link has changed is not relivant.
5665  *
5666  * Fork - LGPL
5667  * <script type="text/javascript">
5668  */
5669
5670 /**
5671  * @class Roo.util.Observable
5672  * Base class that provides a common interface for publishing events. Subclasses are expected to
5673  * to have a property "events" with all the events defined.<br>
5674  * For example:
5675  * <pre><code>
5676  Employee = function(name){
5677     this.name = name;
5678     this.addEvents({
5679         "fired" : true,
5680         "quit" : true
5681     });
5682  }
5683  Roo.extend(Employee, Roo.util.Observable);
5684 </code></pre>
5685  * @param {Object} config properties to use (incuding events / listeners)
5686  */
5687
5688 Roo.util.Observable = function(cfg){
5689     
5690     cfg = cfg|| {};
5691     this.addEvents(cfg.events || {});
5692     if (cfg.events) {
5693         delete cfg.events; // make sure
5694     }
5695      
5696     Roo.apply(this, cfg);
5697     
5698     if(this.listeners){
5699         this.on(this.listeners);
5700         delete this.listeners;
5701     }
5702 };
5703 Roo.util.Observable.prototype = {
5704     /** 
5705  * @cfg {Object} listeners  list of events and functions to call for this object, 
5706  * For example :
5707  * <pre><code>
5708     listeners :  { 
5709        'click' : function(e) {
5710            ..... 
5711         } ,
5712         .... 
5713     } 
5714   </code></pre>
5715  */
5716     
5717     
5718     /**
5719      * Fires the specified event with the passed parameters (minus the event name).
5720      * @param {String} eventName
5721      * @param {Object...} args Variable number of parameters are passed to handlers
5722      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5723      */
5724     fireEvent : function(){
5725         var ce = this.events[arguments[0].toLowerCase()];
5726         if(typeof ce == "object"){
5727             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5728         }else{
5729             return true;
5730         }
5731     },
5732
5733     // private
5734     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5735
5736     /**
5737      * Appends an event handler to this component
5738      * @param {String}   eventName The type of event to listen for
5739      * @param {Function} handler The method the event invokes
5740      * @param {Object}   scope (optional) The scope in which to execute the handler
5741      * function. The handler function's "this" context.
5742      * @param {Object}   options (optional) An object containing handler configuration
5743      * properties. This may contain any of the following properties:<ul>
5744      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5745      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5746      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5747      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5748      * by the specified number of milliseconds. If the event fires again within that time, the original
5749      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5750      * </ul><br>
5751      * <p>
5752      * <b>Combining Options</b><br>
5753      * Using the options argument, it is possible to combine different types of listeners:<br>
5754      * <br>
5755      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5756                 <pre><code>
5757                 el.on('click', this.onClick, this, {
5758                         single: true,
5759                 delay: 100,
5760                 forumId: 4
5761                 });
5762                 </code></pre>
5763      * <p>
5764      * <b>Attaching multiple handlers in 1 call</b><br>
5765      * The method also allows for a single argument to be passed which is a config object containing properties
5766      * which specify multiple handlers.
5767      * <pre><code>
5768                 el.on({
5769                         'click': {
5770                         fn: this.onClick,
5771                         scope: this,
5772                         delay: 100
5773                 }, 
5774                 'mouseover': {
5775                         fn: this.onMouseOver,
5776                         scope: this
5777                 },
5778                 'mouseout': {
5779                         fn: this.onMouseOut,
5780                         scope: this
5781                 }
5782                 });
5783                 </code></pre>
5784      * <p>
5785      * Or a shorthand syntax which passes the same scope object to all handlers:
5786         <pre><code>
5787                 el.on({
5788                         'click': this.onClick,
5789                 'mouseover': this.onMouseOver,
5790                 'mouseout': this.onMouseOut,
5791                 scope: this
5792                 });
5793                 </code></pre>
5794      */
5795     addListener : function(eventName, fn, scope, o){
5796         if(typeof eventName == "object"){
5797             o = eventName;
5798             for(var e in o){
5799                 if(this.filterOptRe.test(e)){
5800                     continue;
5801                 }
5802                 if(typeof o[e] == "function"){
5803                     // shared options
5804                     this.addListener(e, o[e], o.scope,  o);
5805                 }else{
5806                     // individual options
5807                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5808                 }
5809             }
5810             return;
5811         }
5812         o = (!o || typeof o == "boolean") ? {} : o;
5813         eventName = eventName.toLowerCase();
5814         var ce = this.events[eventName] || true;
5815         if(typeof ce == "boolean"){
5816             ce = new Roo.util.Event(this, eventName);
5817             this.events[eventName] = ce;
5818         }
5819         ce.addListener(fn, scope, o);
5820     },
5821
5822     /**
5823      * Removes a listener
5824      * @param {String}   eventName     The type of event to listen for
5825      * @param {Function} handler        The handler to remove
5826      * @param {Object}   scope  (optional) The scope (this object) for the handler
5827      */
5828     removeListener : function(eventName, fn, scope){
5829         var ce = this.events[eventName.toLowerCase()];
5830         if(typeof ce == "object"){
5831             ce.removeListener(fn, scope);
5832         }
5833     },
5834
5835     /**
5836      * Removes all listeners for this object
5837      */
5838     purgeListeners : function(){
5839         for(var evt in this.events){
5840             if(typeof this.events[evt] == "object"){
5841                  this.events[evt].clearListeners();
5842             }
5843         }
5844     },
5845
5846     relayEvents : function(o, events){
5847         var createHandler = function(ename){
5848             return function(){
5849                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5850             };
5851         };
5852         for(var i = 0, len = events.length; i < len; i++){
5853             var ename = events[i];
5854             if(!this.events[ename]){ this.events[ename] = true; };
5855             o.on(ename, createHandler(ename), this);
5856         }
5857     },
5858
5859     /**
5860      * Used to define events on this Observable
5861      * @param {Object} object The object with the events defined
5862      */
5863     addEvents : function(o){
5864         if(!this.events){
5865             this.events = {};
5866         }
5867         Roo.applyIf(this.events, o);
5868     },
5869
5870     /**
5871      * Checks to see if this object has any listeners for a specified event
5872      * @param {String} eventName The name of the event to check for
5873      * @return {Boolean} True if the event is being listened for, else false
5874      */
5875     hasListener : function(eventName){
5876         var e = this.events[eventName];
5877         return typeof e == "object" && e.listeners.length > 0;
5878     }
5879 };
5880 /**
5881  * Appends an event handler to this element (shorthand for addListener)
5882  * @param {String}   eventName     The type of event to listen for
5883  * @param {Function} handler        The method the event invokes
5884  * @param {Object}   scope (optional) The scope in which to execute the handler
5885  * function. The handler function's "this" context.
5886  * @param {Object}   options  (optional)
5887  * @method
5888  */
5889 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5890 /**
5891  * Removes a listener (shorthand for removeListener)
5892  * @param {String}   eventName     The type of event to listen for
5893  * @param {Function} handler        The handler to remove
5894  * @param {Object}   scope  (optional) The scope (this object) for the handler
5895  * @method
5896  */
5897 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5898
5899 /**
5900  * Starts capture on the specified Observable. All events will be passed
5901  * to the supplied function with the event name + standard signature of the event
5902  * <b>before</b> the event is fired. If the supplied function returns false,
5903  * the event will not fire.
5904  * @param {Observable} o The Observable to capture
5905  * @param {Function} fn The function to call
5906  * @param {Object} scope (optional) The scope (this object) for the fn
5907  * @static
5908  */
5909 Roo.util.Observable.capture = function(o, fn, scope){
5910     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5911 };
5912
5913 /**
5914  * Removes <b>all</b> added captures from the Observable.
5915  * @param {Observable} o The Observable to release
5916  * @static
5917  */
5918 Roo.util.Observable.releaseCapture = function(o){
5919     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5920 };
5921
5922 (function(){
5923
5924     var createBuffered = function(h, o, scope){
5925         var task = new Roo.util.DelayedTask();
5926         return function(){
5927             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5928         };
5929     };
5930
5931     var createSingle = function(h, e, fn, scope){
5932         return function(){
5933             e.removeListener(fn, scope);
5934             return h.apply(scope, arguments);
5935         };
5936     };
5937
5938     var createDelayed = function(h, o, scope){
5939         return function(){
5940             var args = Array.prototype.slice.call(arguments, 0);
5941             setTimeout(function(){
5942                 h.apply(scope, args);
5943             }, o.delay || 10);
5944         };
5945     };
5946
5947     Roo.util.Event = function(obj, name){
5948         this.name = name;
5949         this.obj = obj;
5950         this.listeners = [];
5951     };
5952
5953     Roo.util.Event.prototype = {
5954         addListener : function(fn, scope, options){
5955             var o = options || {};
5956             scope = scope || this.obj;
5957             if(!this.isListening(fn, scope)){
5958                 var l = {fn: fn, scope: scope, options: o};
5959                 var h = fn;
5960                 if(o.delay){
5961                     h = createDelayed(h, o, scope);
5962                 }
5963                 if(o.single){
5964                     h = createSingle(h, this, fn, scope);
5965                 }
5966                 if(o.buffer){
5967                     h = createBuffered(h, o, scope);
5968                 }
5969                 l.fireFn = h;
5970                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5971                     this.listeners.push(l);
5972                 }else{
5973                     this.listeners = this.listeners.slice(0);
5974                     this.listeners.push(l);
5975                 }
5976             }
5977         },
5978
5979         findListener : function(fn, scope){
5980             scope = scope || this.obj;
5981             var ls = this.listeners;
5982             for(var i = 0, len = ls.length; i < len; i++){
5983                 var l = ls[i];
5984                 if(l.fn == fn && l.scope == scope){
5985                     return i;
5986                 }
5987             }
5988             return -1;
5989         },
5990
5991         isListening : function(fn, scope){
5992             return this.findListener(fn, scope) != -1;
5993         },
5994
5995         removeListener : function(fn, scope){
5996             var index;
5997             if((index = this.findListener(fn, scope)) != -1){
5998                 if(!this.firing){
5999                     this.listeners.splice(index, 1);
6000                 }else{
6001                     this.listeners = this.listeners.slice(0);
6002                     this.listeners.splice(index, 1);
6003                 }
6004                 return true;
6005             }
6006             return false;
6007         },
6008
6009         clearListeners : function(){
6010             this.listeners = [];
6011         },
6012
6013         fire : function(){
6014             var ls = this.listeners, scope, len = ls.length;
6015             if(len > 0){
6016                 this.firing = true;
6017                 var args = Array.prototype.slice.call(arguments, 0);
6018                 for(var i = 0; i < len; i++){
6019                     var l = ls[i];
6020                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6021                         this.firing = false;
6022                         return false;
6023                     }
6024                 }
6025                 this.firing = false;
6026             }
6027             return true;
6028         }
6029     };
6030 })();/*
6031  * Based on:
6032  * Ext JS Library 1.1.1
6033  * Copyright(c) 2006-2007, Ext JS, LLC.
6034  *
6035  * Originally Released Under LGPL - original licence link has changed is not relivant.
6036  *
6037  * Fork - LGPL
6038  * <script type="text/javascript">
6039  */
6040
6041 /**
6042  * @class Roo.EventManager
6043  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6044  * several useful events directly.
6045  * See {@link Roo.EventObject} for more details on normalized event objects.
6046  * @singleton
6047  */
6048 Roo.EventManager = function(){
6049     var docReadyEvent, docReadyProcId, docReadyState = false;
6050     var resizeEvent, resizeTask, textEvent, textSize;
6051     var E = Roo.lib.Event;
6052     var D = Roo.lib.Dom;
6053
6054
6055     var fireDocReady = function(){
6056         if(!docReadyState){
6057             docReadyState = true;
6058             Roo.isReady = true;
6059             if(docReadyProcId){
6060                 clearInterval(docReadyProcId);
6061             }
6062             if(Roo.isGecko || Roo.isOpera) {
6063                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6064             }
6065             if(Roo.isIE){
6066                 var defer = document.getElementById("ie-deferred-loader");
6067                 if(defer){
6068                     defer.onreadystatechange = null;
6069                     defer.parentNode.removeChild(defer);
6070                 }
6071             }
6072             if(docReadyEvent){
6073                 docReadyEvent.fire();
6074                 docReadyEvent.clearListeners();
6075             }
6076         }
6077     };
6078     
6079     var initDocReady = function(){
6080         docReadyEvent = new Roo.util.Event();
6081         if(Roo.isGecko || Roo.isOpera) {
6082             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6083         }else if(Roo.isIE){
6084             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6085             var defer = document.getElementById("ie-deferred-loader");
6086             defer.onreadystatechange = function(){
6087                 if(this.readyState == "complete"){
6088                     fireDocReady();
6089                 }
6090             };
6091         }else if(Roo.isSafari){ 
6092             docReadyProcId = setInterval(function(){
6093                 var rs = document.readyState;
6094                 if(rs == "complete") {
6095                     fireDocReady();     
6096                  }
6097             }, 10);
6098         }
6099         // no matter what, make sure it fires on load
6100         E.on(window, "load", fireDocReady);
6101     };
6102
6103     var createBuffered = function(h, o){
6104         var task = new Roo.util.DelayedTask(h);
6105         return function(e){
6106             // create new event object impl so new events don't wipe out properties
6107             e = new Roo.EventObjectImpl(e);
6108             task.delay(o.buffer, h, null, [e]);
6109         };
6110     };
6111
6112     var createSingle = function(h, el, ename, fn){
6113         return function(e){
6114             Roo.EventManager.removeListener(el, ename, fn);
6115             h(e);
6116         };
6117     };
6118
6119     var createDelayed = function(h, o){
6120         return function(e){
6121             // create new event object impl so new events don't wipe out properties
6122             e = new Roo.EventObjectImpl(e);
6123             setTimeout(function(){
6124                 h(e);
6125             }, o.delay || 10);
6126         };
6127     };
6128
6129     var listen = function(element, ename, opt, fn, scope){
6130         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6131         fn = fn || o.fn; scope = scope || o.scope;
6132         var el = Roo.getDom(element);
6133         if(!el){
6134             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6135         }
6136         var h = function(e){
6137             e = Roo.EventObject.setEvent(e);
6138             var t;
6139             if(o.delegate){
6140                 t = e.getTarget(o.delegate, el);
6141                 if(!t){
6142                     return;
6143                 }
6144             }else{
6145                 t = e.target;
6146             }
6147             if(o.stopEvent === true){
6148                 e.stopEvent();
6149             }
6150             if(o.preventDefault === true){
6151                e.preventDefault();
6152             }
6153             if(o.stopPropagation === true){
6154                 e.stopPropagation();
6155             }
6156
6157             if(o.normalized === false){
6158                 e = e.browserEvent;
6159             }
6160
6161             fn.call(scope || el, e, t, o);
6162         };
6163         if(o.delay){
6164             h = createDelayed(h, o);
6165         }
6166         if(o.single){
6167             h = createSingle(h, el, ename, fn);
6168         }
6169         if(o.buffer){
6170             h = createBuffered(h, o);
6171         }
6172         fn._handlers = fn._handlers || [];
6173         fn._handlers.push([Roo.id(el), ename, h]);
6174
6175         E.on(el, ename, h);
6176         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6177             el.addEventListener("DOMMouseScroll", h, false);
6178             E.on(window, 'unload', function(){
6179                 el.removeEventListener("DOMMouseScroll", h, false);
6180             });
6181         }
6182         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6183             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6184         }
6185         return h;
6186     };
6187
6188     var stopListening = function(el, ename, fn){
6189         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6190         if(hds){
6191             for(var i = 0, len = hds.length; i < len; i++){
6192                 var h = hds[i];
6193                 if(h[0] == id && h[1] == ename){
6194                     hd = h[2];
6195                     hds.splice(i, 1);
6196                     break;
6197                 }
6198             }
6199         }
6200         E.un(el, ename, hd);
6201         el = Roo.getDom(el);
6202         if(ename == "mousewheel" && el.addEventListener){
6203             el.removeEventListener("DOMMouseScroll", hd, false);
6204         }
6205         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6206             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6207         }
6208     };
6209
6210     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6211     
6212     var pub = {
6213         
6214         
6215         /** 
6216          * Fix for doc tools
6217          * @scope Roo.EventManager
6218          */
6219         
6220         
6221         /** 
6222          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6223          * object with a Roo.EventObject
6224          * @param {Function} fn        The method the event invokes
6225          * @param {Object}   scope    An object that becomes the scope of the handler
6226          * @param {boolean}  override If true, the obj passed in becomes
6227          *                             the execution scope of the listener
6228          * @return {Function} The wrapped function
6229          * @deprecated
6230          */
6231         wrap : function(fn, scope, override){
6232             return function(e){
6233                 Roo.EventObject.setEvent(e);
6234                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6235             };
6236         },
6237         
6238         /**
6239      * Appends an event handler to an element (shorthand for addListener)
6240      * @param {String/HTMLElement}   element        The html element or id to assign the
6241      * @param {String}   eventName The type of event to listen for
6242      * @param {Function} handler The method the event invokes
6243      * @param {Object}   scope (optional) The scope in which to execute the handler
6244      * function. The handler function's "this" context.
6245      * @param {Object}   options (optional) An object containing handler configuration
6246      * properties. This may contain any of the following properties:<ul>
6247      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6248      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6249      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6250      * <li>preventDefault {Boolean} True to prevent the default action</li>
6251      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6252      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6253      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6254      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6255      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6256      * by the specified number of milliseconds. If the event fires again within that time, the original
6257      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6258      * </ul><br>
6259      * <p>
6260      * <b>Combining Options</b><br>
6261      * Using the options argument, it is possible to combine different types of listeners:<br>
6262      * <br>
6263      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6264      * Code:<pre><code>
6265 el.on('click', this.onClick, this, {
6266     single: true,
6267     delay: 100,
6268     stopEvent : true,
6269     forumId: 4
6270 });</code></pre>
6271      * <p>
6272      * <b>Attaching multiple handlers in 1 call</b><br>
6273       * The method also allows for a single argument to be passed which is a config object containing properties
6274      * which specify multiple handlers.
6275      * <p>
6276      * Code:<pre><code>
6277 el.on({
6278     'click' : {
6279         fn: this.onClick
6280         scope: this,
6281         delay: 100
6282     },
6283     'mouseover' : {
6284         fn: this.onMouseOver
6285         scope: this
6286     },
6287     'mouseout' : {
6288         fn: this.onMouseOut
6289         scope: this
6290     }
6291 });</code></pre>
6292      * <p>
6293      * Or a shorthand syntax:<br>
6294      * Code:<pre><code>
6295 el.on({
6296     'click' : this.onClick,
6297     'mouseover' : this.onMouseOver,
6298     'mouseout' : this.onMouseOut
6299     scope: this
6300 });</code></pre>
6301      */
6302         addListener : function(element, eventName, fn, scope, options){
6303             if(typeof eventName == "object"){
6304                 var o = eventName;
6305                 for(var e in o){
6306                     if(propRe.test(e)){
6307                         continue;
6308                     }
6309                     if(typeof o[e] == "function"){
6310                         // shared options
6311                         listen(element, e, o, o[e], o.scope);
6312                     }else{
6313                         // individual options
6314                         listen(element, e, o[e]);
6315                     }
6316                 }
6317                 return;
6318             }
6319             return listen(element, eventName, options, fn, scope);
6320         },
6321         
6322         /**
6323          * Removes an event handler
6324          *
6325          * @param {String/HTMLElement}   element        The id or html element to remove the 
6326          *                             event from
6327          * @param {String}   eventName     The type of event
6328          * @param {Function} fn
6329          * @return {Boolean} True if a listener was actually removed
6330          */
6331         removeListener : function(element, eventName, fn){
6332             return stopListening(element, eventName, fn);
6333         },
6334         
6335         /**
6336          * Fires when the document is ready (before onload and before images are loaded). Can be 
6337          * accessed shorthanded Roo.onReady().
6338          * @param {Function} fn        The method the event invokes
6339          * @param {Object}   scope    An  object that becomes the scope of the handler
6340          * @param {boolean}  options
6341          */
6342         onDocumentReady : function(fn, scope, options){
6343             if(docReadyState){ // if it already fired
6344                 docReadyEvent.addListener(fn, scope, options);
6345                 docReadyEvent.fire();
6346                 docReadyEvent.clearListeners();
6347                 return;
6348             }
6349             if(!docReadyEvent){
6350                 initDocReady();
6351             }
6352             docReadyEvent.addListener(fn, scope, options);
6353         },
6354         
6355         /**
6356          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6357          * @param {Function} fn        The method the event invokes
6358          * @param {Object}   scope    An object that becomes the scope of the handler
6359          * @param {boolean}  options
6360          */
6361         onWindowResize : function(fn, scope, options){
6362             if(!resizeEvent){
6363                 resizeEvent = new Roo.util.Event();
6364                 resizeTask = new Roo.util.DelayedTask(function(){
6365                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6366                 });
6367                 E.on(window, "resize", function(){
6368                     if(Roo.isIE){
6369                         resizeTask.delay(50);
6370                     }else{
6371                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6372                     }
6373                 });
6374             }
6375             resizeEvent.addListener(fn, scope, options);
6376         },
6377
6378         /**
6379          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6380          * @param {Function} fn        The method the event invokes
6381          * @param {Object}   scope    An object that becomes the scope of the handler
6382          * @param {boolean}  options
6383          */
6384         onTextResize : function(fn, scope, options){
6385             if(!textEvent){
6386                 textEvent = new Roo.util.Event();
6387                 var textEl = new Roo.Element(document.createElement('div'));
6388                 textEl.dom.className = 'x-text-resize';
6389                 textEl.dom.innerHTML = 'X';
6390                 textEl.appendTo(document.body);
6391                 textSize = textEl.dom.offsetHeight;
6392                 setInterval(function(){
6393                     if(textEl.dom.offsetHeight != textSize){
6394                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6395                     }
6396                 }, this.textResizeInterval);
6397             }
6398             textEvent.addListener(fn, scope, options);
6399         },
6400
6401         /**
6402          * Removes the passed window resize listener.
6403          * @param {Function} fn        The method the event invokes
6404          * @param {Object}   scope    The scope of handler
6405          */
6406         removeResizeListener : function(fn, scope){
6407             if(resizeEvent){
6408                 resizeEvent.removeListener(fn, scope);
6409             }
6410         },
6411
6412         // private
6413         fireResize : function(){
6414             if(resizeEvent){
6415                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6416             }   
6417         },
6418         /**
6419          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6420          */
6421         ieDeferSrc : false,
6422         /**
6423          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6424          */
6425         textResizeInterval : 50
6426     };
6427     
6428     /**
6429      * Fix for doc tools
6430      * @scopeAlias pub=Roo.EventManager
6431      */
6432     
6433      /**
6434      * Appends an event handler to an element (shorthand for addListener)
6435      * @param {String/HTMLElement}   element        The html element or id to assign the
6436      * @param {String}   eventName The type of event to listen for
6437      * @param {Function} handler The method the event invokes
6438      * @param {Object}   scope (optional) The scope in which to execute the handler
6439      * function. The handler function's "this" context.
6440      * @param {Object}   options (optional) An object containing handler configuration
6441      * properties. This may contain any of the following properties:<ul>
6442      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6443      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6444      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6445      * <li>preventDefault {Boolean} True to prevent the default action</li>
6446      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6447      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6448      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6449      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6450      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6451      * by the specified number of milliseconds. If the event fires again within that time, the original
6452      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6453      * </ul><br>
6454      * <p>
6455      * <b>Combining Options</b><br>
6456      * Using the options argument, it is possible to combine different types of listeners:<br>
6457      * <br>
6458      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6459      * Code:<pre><code>
6460 el.on('click', this.onClick, this, {
6461     single: true,
6462     delay: 100,
6463     stopEvent : true,
6464     forumId: 4
6465 });</code></pre>
6466      * <p>
6467      * <b>Attaching multiple handlers in 1 call</b><br>
6468       * The method also allows for a single argument to be passed which is a config object containing properties
6469      * which specify multiple handlers.
6470      * <p>
6471      * Code:<pre><code>
6472 el.on({
6473     'click' : {
6474         fn: this.onClick
6475         scope: this,
6476         delay: 100
6477     },
6478     'mouseover' : {
6479         fn: this.onMouseOver
6480         scope: this
6481     },
6482     'mouseout' : {
6483         fn: this.onMouseOut
6484         scope: this
6485     }
6486 });</code></pre>
6487      * <p>
6488      * Or a shorthand syntax:<br>
6489      * Code:<pre><code>
6490 el.on({
6491     'click' : this.onClick,
6492     'mouseover' : this.onMouseOver,
6493     'mouseout' : this.onMouseOut
6494     scope: this
6495 });</code></pre>
6496      */
6497     pub.on = pub.addListener;
6498     pub.un = pub.removeListener;
6499
6500     pub.stoppedMouseDownEvent = new Roo.util.Event();
6501     return pub;
6502 }();
6503 /**
6504   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6505   * @param {Function} fn        The method the event invokes
6506   * @param {Object}   scope    An  object that becomes the scope of the handler
6507   * @param {boolean}  override If true, the obj passed in becomes
6508   *                             the execution scope of the listener
6509   * @member Roo
6510   * @method onReady
6511  */
6512 Roo.onReady = Roo.EventManager.onDocumentReady;
6513
6514 Roo.onReady(function(){
6515     var bd = Roo.get(document.body);
6516     if(!bd){ return; }
6517
6518     var cls = [
6519             Roo.isIE ? "roo-ie"
6520             : Roo.isGecko ? "roo-gecko"
6521             : Roo.isOpera ? "roo-opera"
6522             : Roo.isSafari ? "roo-safari" : ""];
6523
6524     if(Roo.isMac){
6525         cls.push("roo-mac");
6526     }
6527     if(Roo.isLinux){
6528         cls.push("roo-linux");
6529     }
6530     if(Roo.isBorderBox){
6531         cls.push('roo-border-box');
6532     }
6533     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6534         var p = bd.dom.parentNode;
6535         if(p){
6536             p.className += ' roo-strict';
6537         }
6538     }
6539     bd.addClass(cls.join(' '));
6540 });
6541
6542 /**
6543  * @class Roo.EventObject
6544  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6545  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6546  * Example:
6547  * <pre><code>
6548  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6549     e.preventDefault();
6550     var target = e.getTarget();
6551     ...
6552  }
6553  var myDiv = Roo.get("myDiv");
6554  myDiv.on("click", handleClick);
6555  //or
6556  Roo.EventManager.on("myDiv", 'click', handleClick);
6557  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6558  </code></pre>
6559  * @singleton
6560  */
6561 Roo.EventObject = function(){
6562     
6563     var E = Roo.lib.Event;
6564     
6565     // safari keypress events for special keys return bad keycodes
6566     var safariKeys = {
6567         63234 : 37, // left
6568         63235 : 39, // right
6569         63232 : 38, // up
6570         63233 : 40, // down
6571         63276 : 33, // page up
6572         63277 : 34, // page down
6573         63272 : 46, // delete
6574         63273 : 36, // home
6575         63275 : 35  // end
6576     };
6577
6578     // normalize button clicks
6579     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6580                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6581
6582     Roo.EventObjectImpl = function(e){
6583         if(e){
6584             this.setEvent(e.browserEvent || e);
6585         }
6586     };
6587     Roo.EventObjectImpl.prototype = {
6588         /**
6589          * Used to fix doc tools.
6590          * @scope Roo.EventObject.prototype
6591          */
6592             
6593
6594         
6595         
6596         /** The normal browser event */
6597         browserEvent : null,
6598         /** The button pressed in a mouse event */
6599         button : -1,
6600         /** True if the shift key was down during the event */
6601         shiftKey : false,
6602         /** True if the control key was down during the event */
6603         ctrlKey : false,
6604         /** True if the alt key was down during the event */
6605         altKey : false,
6606
6607         /** Key constant 
6608         * @type Number */
6609         BACKSPACE : 8,
6610         /** Key constant 
6611         * @type Number */
6612         TAB : 9,
6613         /** Key constant 
6614         * @type Number */
6615         RETURN : 13,
6616         /** Key constant 
6617         * @type Number */
6618         ENTER : 13,
6619         /** Key constant 
6620         * @type Number */
6621         SHIFT : 16,
6622         /** Key constant 
6623         * @type Number */
6624         CONTROL : 17,
6625         /** Key constant 
6626         * @type Number */
6627         ESC : 27,
6628         /** Key constant 
6629         * @type Number */
6630         SPACE : 32,
6631         /** Key constant 
6632         * @type Number */
6633         PAGEUP : 33,
6634         /** Key constant 
6635         * @type Number */
6636         PAGEDOWN : 34,
6637         /** Key constant 
6638         * @type Number */
6639         END : 35,
6640         /** Key constant 
6641         * @type Number */
6642         HOME : 36,
6643         /** Key constant 
6644         * @type Number */
6645         LEFT : 37,
6646         /** Key constant 
6647         * @type Number */
6648         UP : 38,
6649         /** Key constant 
6650         * @type Number */
6651         RIGHT : 39,
6652         /** Key constant 
6653         * @type Number */
6654         DOWN : 40,
6655         /** Key constant 
6656         * @type Number */
6657         DELETE : 46,
6658         /** Key constant 
6659         * @type Number */
6660         F5 : 116,
6661
6662            /** @private */
6663         setEvent : function(e){
6664             if(e == this || (e && e.browserEvent)){ // already wrapped
6665                 return e;
6666             }
6667             this.browserEvent = e;
6668             if(e){
6669                 // normalize buttons
6670                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6671                 if(e.type == 'click' && this.button == -1){
6672                     this.button = 0;
6673                 }
6674                 this.type = e.type;
6675                 this.shiftKey = e.shiftKey;
6676                 // mac metaKey behaves like ctrlKey
6677                 this.ctrlKey = e.ctrlKey || e.metaKey;
6678                 this.altKey = e.altKey;
6679                 // in getKey these will be normalized for the mac
6680                 this.keyCode = e.keyCode;
6681                 // keyup warnings on firefox.
6682                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6683                 // cache the target for the delayed and or buffered events
6684                 this.target = E.getTarget(e);
6685                 // same for XY
6686                 this.xy = E.getXY(e);
6687             }else{
6688                 this.button = -1;
6689                 this.shiftKey = false;
6690                 this.ctrlKey = false;
6691                 this.altKey = false;
6692                 this.keyCode = 0;
6693                 this.charCode =0;
6694                 this.target = null;
6695                 this.xy = [0, 0];
6696             }
6697             return this;
6698         },
6699
6700         /**
6701          * Stop the event (preventDefault and stopPropagation)
6702          */
6703         stopEvent : function(){
6704             if(this.browserEvent){
6705                 if(this.browserEvent.type == 'mousedown'){
6706                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6707                 }
6708                 E.stopEvent(this.browserEvent);
6709             }
6710         },
6711
6712         /**
6713          * Prevents the browsers default handling of the event.
6714          */
6715         preventDefault : function(){
6716             if(this.browserEvent){
6717                 E.preventDefault(this.browserEvent);
6718             }
6719         },
6720
6721         /** @private */
6722         isNavKeyPress : function(){
6723             var k = this.keyCode;
6724             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6725             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6726         },
6727
6728         isSpecialKey : function(){
6729             var k = this.keyCode;
6730             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6731             (k == 16) || (k == 17) ||
6732             (k >= 18 && k <= 20) ||
6733             (k >= 33 && k <= 35) ||
6734             (k >= 36 && k <= 39) ||
6735             (k >= 44 && k <= 45);
6736         },
6737         /**
6738          * Cancels bubbling of the event.
6739          */
6740         stopPropagation : function(){
6741             if(this.browserEvent){
6742                 if(this.type == 'mousedown'){
6743                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6744                 }
6745                 E.stopPropagation(this.browserEvent);
6746             }
6747         },
6748
6749         /**
6750          * Gets the key code for the event.
6751          * @return {Number}
6752          */
6753         getCharCode : function(){
6754             return this.charCode || this.keyCode;
6755         },
6756
6757         /**
6758          * Returns a normalized keyCode for the event.
6759          * @return {Number} The key code
6760          */
6761         getKey : function(){
6762             var k = this.keyCode || this.charCode;
6763             return Roo.isSafari ? (safariKeys[k] || k) : k;
6764         },
6765
6766         /**
6767          * Gets the x coordinate of the event.
6768          * @return {Number}
6769          */
6770         getPageX : function(){
6771             return this.xy[0];
6772         },
6773
6774         /**
6775          * Gets the y coordinate of the event.
6776          * @return {Number}
6777          */
6778         getPageY : function(){
6779             return this.xy[1];
6780         },
6781
6782         /**
6783          * Gets the time of the event.
6784          * @return {Number}
6785          */
6786         getTime : function(){
6787             if(this.browserEvent){
6788                 return E.getTime(this.browserEvent);
6789             }
6790             return null;
6791         },
6792
6793         /**
6794          * Gets the page coordinates of the event.
6795          * @return {Array} The xy values like [x, y]
6796          */
6797         getXY : function(){
6798             return this.xy;
6799         },
6800
6801         /**
6802          * Gets the target for the event.
6803          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6804          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6805                 search as a number or element (defaults to 10 || document.body)
6806          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6807          * @return {HTMLelement}
6808          */
6809         getTarget : function(selector, maxDepth, returnEl){
6810             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6811         },
6812         /**
6813          * Gets the related target.
6814          * @return {HTMLElement}
6815          */
6816         getRelatedTarget : function(){
6817             if(this.browserEvent){
6818                 return E.getRelatedTarget(this.browserEvent);
6819             }
6820             return null;
6821         },
6822
6823         /**
6824          * Normalizes mouse wheel delta across browsers
6825          * @return {Number} The delta
6826          */
6827         getWheelDelta : function(){
6828             var e = this.browserEvent;
6829             var delta = 0;
6830             if(e.wheelDelta){ /* IE/Opera. */
6831                 delta = e.wheelDelta/120;
6832             }else if(e.detail){ /* Mozilla case. */
6833                 delta = -e.detail/3;
6834             }
6835             return delta;
6836         },
6837
6838         /**
6839          * Returns true if the control, meta, shift or alt key was pressed during this event.
6840          * @return {Boolean}
6841          */
6842         hasModifier : function(){
6843             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6844         },
6845
6846         /**
6847          * Returns true if the target of this event equals el or is a child of el
6848          * @param {String/HTMLElement/Element} el
6849          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6850          * @return {Boolean}
6851          */
6852         within : function(el, related){
6853             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6854             return t && Roo.fly(el).contains(t);
6855         },
6856
6857         getPoint : function(){
6858             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6859         }
6860     };
6861
6862     return new Roo.EventObjectImpl();
6863 }();
6864             
6865     /*
6866  * Based on:
6867  * Ext JS Library 1.1.1
6868  * Copyright(c) 2006-2007, Ext JS, LLC.
6869  *
6870  * Originally Released Under LGPL - original licence link has changed is not relivant.
6871  *
6872  * Fork - LGPL
6873  * <script type="text/javascript">
6874  */
6875
6876  
6877 // was in Composite Element!??!?!
6878  
6879 (function(){
6880     var D = Roo.lib.Dom;
6881     var E = Roo.lib.Event;
6882     var A = Roo.lib.Anim;
6883
6884     // local style camelizing for speed
6885     var propCache = {};
6886     var camelRe = /(-[a-z])/gi;
6887     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6888     var view = document.defaultView;
6889
6890 /**
6891  * @class Roo.Element
6892  * Represents an Element in the DOM.<br><br>
6893  * Usage:<br>
6894 <pre><code>
6895 var el = Roo.get("my-div");
6896
6897 // or with getEl
6898 var el = getEl("my-div");
6899
6900 // or with a DOM element
6901 var el = Roo.get(myDivElement);
6902 </code></pre>
6903  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6904  * each call instead of constructing a new one.<br><br>
6905  * <b>Animations</b><br />
6906  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6907  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6908 <pre>
6909 Option    Default   Description
6910 --------- --------  ---------------------------------------------
6911 duration  .35       The duration of the animation in seconds
6912 easing    easeOut   The YUI easing method
6913 callback  none      A function to execute when the anim completes
6914 scope     this      The scope (this) of the callback function
6915 </pre>
6916 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6917 * manipulate the animation. Here's an example:
6918 <pre><code>
6919 var el = Roo.get("my-div");
6920
6921 // no animation
6922 el.setWidth(100);
6923
6924 // default animation
6925 el.setWidth(100, true);
6926
6927 // animation with some options set
6928 el.setWidth(100, {
6929     duration: 1,
6930     callback: this.foo,
6931     scope: this
6932 });
6933
6934 // using the "anim" property to get the Anim object
6935 var opt = {
6936     duration: 1,
6937     callback: this.foo,
6938     scope: this
6939 };
6940 el.setWidth(100, opt);
6941 ...
6942 if(opt.anim.isAnimated()){
6943     opt.anim.stop();
6944 }
6945 </code></pre>
6946 * <b> Composite (Collections of) Elements</b><br />
6947  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6948  * @constructor Create a new Element directly.
6949  * @param {String/HTMLElement} element
6950  * @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).
6951  */
6952     Roo.Element = function(element, forceNew){
6953         var dom = typeof element == "string" ?
6954                 document.getElementById(element) : element;
6955         if(!dom){ // invalid id/element
6956             return null;
6957         }
6958         var id = dom.id;
6959         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6960             return Roo.Element.cache[id];
6961         }
6962
6963         /**
6964          * The DOM element
6965          * @type HTMLElement
6966          */
6967         this.dom = dom;
6968
6969         /**
6970          * The DOM element ID
6971          * @type String
6972          */
6973         this.id = id || Roo.id(dom);
6974     };
6975
6976     var El = Roo.Element;
6977
6978     El.prototype = {
6979         /**
6980          * The element's default display mode  (defaults to "")
6981          * @type String
6982          */
6983         originalDisplay : "",
6984
6985         visibilityMode : 1,
6986         /**
6987          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6988          * @type String
6989          */
6990         defaultUnit : "px",
6991         /**
6992          * Sets the element's visibility mode. When setVisible() is called it
6993          * will use this to determine whether to set the visibility or the display property.
6994          * @param visMode Element.VISIBILITY or Element.DISPLAY
6995          * @return {Roo.Element} this
6996          */
6997         setVisibilityMode : function(visMode){
6998             this.visibilityMode = visMode;
6999             return this;
7000         },
7001         /**
7002          * Convenience method for setVisibilityMode(Element.DISPLAY)
7003          * @param {String} display (optional) What to set display to when visible
7004          * @return {Roo.Element} this
7005          */
7006         enableDisplayMode : function(display){
7007             this.setVisibilityMode(El.DISPLAY);
7008             if(typeof display != "undefined") this.originalDisplay = display;
7009             return this;
7010         },
7011
7012         /**
7013          * 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)
7014          * @param {String} selector The simple selector to test
7015          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7016                 search as a number or element (defaults to 10 || document.body)
7017          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7018          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7019          */
7020         findParent : function(simpleSelector, maxDepth, returnEl){
7021             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7022             maxDepth = maxDepth || 50;
7023             if(typeof maxDepth != "number"){
7024                 stopEl = Roo.getDom(maxDepth);
7025                 maxDepth = 10;
7026             }
7027             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7028                 if(dq.is(p, simpleSelector)){
7029                     return returnEl ? Roo.get(p) : p;
7030                 }
7031                 depth++;
7032                 p = p.parentNode;
7033             }
7034             return null;
7035         },
7036
7037
7038         /**
7039          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7040          * @param {String} selector The simple selector to test
7041          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7042                 search as a number or element (defaults to 10 || document.body)
7043          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7044          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7045          */
7046         findParentNode : function(simpleSelector, maxDepth, returnEl){
7047             var p = Roo.fly(this.dom.parentNode, '_internal');
7048             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7049         },
7050
7051         /**
7052          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7053          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7054          * @param {String} selector The simple selector to test
7055          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7056                 search as a number or element (defaults to 10 || document.body)
7057          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7058          */
7059         up : function(simpleSelector, maxDepth){
7060             return this.findParentNode(simpleSelector, maxDepth, true);
7061         },
7062
7063
7064
7065         /**
7066          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7067          * @param {String} selector The simple selector to test
7068          * @return {Boolean} True if this element matches the selector, else false
7069          */
7070         is : function(simpleSelector){
7071             return Roo.DomQuery.is(this.dom, simpleSelector);
7072         },
7073
7074         /**
7075          * Perform animation on this element.
7076          * @param {Object} args The YUI animation control args
7077          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7078          * @param {Function} onComplete (optional) Function to call when animation completes
7079          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7080          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7081          * @return {Roo.Element} this
7082          */
7083         animate : function(args, duration, onComplete, easing, animType){
7084             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7085             return this;
7086         },
7087
7088         /*
7089          * @private Internal animation call
7090          */
7091         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7092             animType = animType || 'run';
7093             opt = opt || {};
7094             var anim = Roo.lib.Anim[animType](
7095                 this.dom, args,
7096                 (opt.duration || defaultDur) || .35,
7097                 (opt.easing || defaultEase) || 'easeOut',
7098                 function(){
7099                     Roo.callback(cb, this);
7100                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7101                 },
7102                 this
7103             );
7104             opt.anim = anim;
7105             return anim;
7106         },
7107
7108         // private legacy anim prep
7109         preanim : function(a, i){
7110             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7111         },
7112
7113         /**
7114          * Removes worthless text nodes
7115          * @param {Boolean} forceReclean (optional) By default the element
7116          * keeps track if it has been cleaned already so
7117          * you can call this over and over. However, if you update the element and
7118          * need to force a reclean, you can pass true.
7119          */
7120         clean : function(forceReclean){
7121             if(this.isCleaned && forceReclean !== true){
7122                 return this;
7123             }
7124             var ns = /\S/;
7125             var d = this.dom, n = d.firstChild, ni = -1;
7126             while(n){
7127                 var nx = n.nextSibling;
7128                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7129                     d.removeChild(n);
7130                 }else{
7131                     n.nodeIndex = ++ni;
7132                 }
7133                 n = nx;
7134             }
7135             this.isCleaned = true;
7136             return this;
7137         },
7138
7139         // private
7140         calcOffsetsTo : function(el){
7141             el = Roo.get(el);
7142             var d = el.dom;
7143             var restorePos = false;
7144             if(el.getStyle('position') == 'static'){
7145                 el.position('relative');
7146                 restorePos = true;
7147             }
7148             var x = 0, y =0;
7149             var op = this.dom;
7150             while(op && op != d && op.tagName != 'HTML'){
7151                 x+= op.offsetLeft;
7152                 y+= op.offsetTop;
7153                 op = op.offsetParent;
7154             }
7155             if(restorePos){
7156                 el.position('static');
7157             }
7158             return [x, y];
7159         },
7160
7161         /**
7162          * Scrolls this element into view within the passed container.
7163          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7164          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7165          * @return {Roo.Element} this
7166          */
7167         scrollIntoView : function(container, hscroll){
7168             var c = Roo.getDom(container) || document.body;
7169             var el = this.dom;
7170
7171             var o = this.calcOffsetsTo(c),
7172                 l = o[0],
7173                 t = o[1],
7174                 b = t+el.offsetHeight,
7175                 r = l+el.offsetWidth;
7176
7177             var ch = c.clientHeight;
7178             var ct = parseInt(c.scrollTop, 10);
7179             var cl = parseInt(c.scrollLeft, 10);
7180             var cb = ct + ch;
7181             var cr = cl + c.clientWidth;
7182
7183             if(t < ct){
7184                 c.scrollTop = t;
7185             }else if(b > cb){
7186                 c.scrollTop = b-ch;
7187             }
7188
7189             if(hscroll !== false){
7190                 if(l < cl){
7191                     c.scrollLeft = l;
7192                 }else if(r > cr){
7193                     c.scrollLeft = r-c.clientWidth;
7194                 }
7195             }
7196             return this;
7197         },
7198
7199         // private
7200         scrollChildIntoView : function(child, hscroll){
7201             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7202         },
7203
7204         /**
7205          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7206          * the new height may not be available immediately.
7207          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7208          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7209          * @param {Function} onComplete (optional) Function to call when animation completes
7210          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7211          * @return {Roo.Element} this
7212          */
7213         autoHeight : function(animate, duration, onComplete, easing){
7214             var oldHeight = this.getHeight();
7215             this.clip();
7216             this.setHeight(1); // force clipping
7217             setTimeout(function(){
7218                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7219                 if(!animate){
7220                     this.setHeight(height);
7221                     this.unclip();
7222                     if(typeof onComplete == "function"){
7223                         onComplete();
7224                     }
7225                 }else{
7226                     this.setHeight(oldHeight); // restore original height
7227                     this.setHeight(height, animate, duration, function(){
7228                         this.unclip();
7229                         if(typeof onComplete == "function") onComplete();
7230                     }.createDelegate(this), easing);
7231                 }
7232             }.createDelegate(this), 0);
7233             return this;
7234         },
7235
7236         /**
7237          * Returns true if this element is an ancestor of the passed element
7238          * @param {HTMLElement/String} el The element to check
7239          * @return {Boolean} True if this element is an ancestor of el, else false
7240          */
7241         contains : function(el){
7242             if(!el){return false;}
7243             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7244         },
7245
7246         /**
7247          * Checks whether the element is currently visible using both visibility and display properties.
7248          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7249          * @return {Boolean} True if the element is currently visible, else false
7250          */
7251         isVisible : function(deep) {
7252             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7253             if(deep !== true || !vis){
7254                 return vis;
7255             }
7256             var p = this.dom.parentNode;
7257             while(p && p.tagName.toLowerCase() != "body"){
7258                 if(!Roo.fly(p, '_isVisible').isVisible()){
7259                     return false;
7260                 }
7261                 p = p.parentNode;
7262             }
7263             return true;
7264         },
7265
7266         /**
7267          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7268          * @param {String} selector The CSS selector
7269          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7270          * @return {CompositeElement/CompositeElementLite} The composite element
7271          */
7272         select : function(selector, unique){
7273             return El.select(selector, unique, this.dom);
7274         },
7275
7276         /**
7277          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7278          * @param {String} selector The CSS selector
7279          * @return {Array} An array of the matched nodes
7280          */
7281         query : function(selector, unique){
7282             return Roo.DomQuery.select(selector, this.dom);
7283         },
7284
7285         /**
7286          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7287          * @param {String} selector The CSS selector
7288          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7289          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7290          */
7291         child : function(selector, returnDom){
7292             var n = Roo.DomQuery.selectNode(selector, this.dom);
7293             return returnDom ? n : Roo.get(n);
7294         },
7295
7296         /**
7297          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7298          * @param {String} selector The CSS selector
7299          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7300          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7301          */
7302         down : function(selector, returnDom){
7303             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7304             return returnDom ? n : Roo.get(n);
7305         },
7306
7307         /**
7308          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7309          * @param {String} group The group the DD object is member of
7310          * @param {Object} config The DD config object
7311          * @param {Object} overrides An object containing methods to override/implement on the DD object
7312          * @return {Roo.dd.DD} The DD object
7313          */
7314         initDD : function(group, config, overrides){
7315             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7316             return Roo.apply(dd, overrides);
7317         },
7318
7319         /**
7320          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7321          * @param {String} group The group the DDProxy object is member of
7322          * @param {Object} config The DDProxy config object
7323          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7324          * @return {Roo.dd.DDProxy} The DDProxy object
7325          */
7326         initDDProxy : function(group, config, overrides){
7327             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7328             return Roo.apply(dd, overrides);
7329         },
7330
7331         /**
7332          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7333          * @param {String} group The group the DDTarget object is member of
7334          * @param {Object} config The DDTarget config object
7335          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7336          * @return {Roo.dd.DDTarget} The DDTarget object
7337          */
7338         initDDTarget : function(group, config, overrides){
7339             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7340             return Roo.apply(dd, overrides);
7341         },
7342
7343         /**
7344          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7345          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7346          * @param {Boolean} visible Whether the element is visible
7347          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7348          * @return {Roo.Element} this
7349          */
7350          setVisible : function(visible, animate){
7351             if(!animate || !A){
7352                 if(this.visibilityMode == El.DISPLAY){
7353                     this.setDisplayed(visible);
7354                 }else{
7355                     this.fixDisplay();
7356                     this.dom.style.visibility = visible ? "visible" : "hidden";
7357                 }
7358             }else{
7359                 // closure for composites
7360                 var dom = this.dom;
7361                 var visMode = this.visibilityMode;
7362                 if(visible){
7363                     this.setOpacity(.01);
7364                     this.setVisible(true);
7365                 }
7366                 this.anim({opacity: { to: (visible?1:0) }},
7367                       this.preanim(arguments, 1),
7368                       null, .35, 'easeIn', function(){
7369                          if(!visible){
7370                              if(visMode == El.DISPLAY){
7371                                  dom.style.display = "none";
7372                              }else{
7373                                  dom.style.visibility = "hidden";
7374                              }
7375                              Roo.get(dom).setOpacity(1);
7376                          }
7377                      });
7378             }
7379             return this;
7380         },
7381
7382         /**
7383          * Returns true if display is not "none"
7384          * @return {Boolean}
7385          */
7386         isDisplayed : function() {
7387             return this.getStyle("display") != "none";
7388         },
7389
7390         /**
7391          * Toggles the element's visibility or display, depending on visibility mode.
7392          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7393          * @return {Roo.Element} this
7394          */
7395         toggle : function(animate){
7396             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7397             return this;
7398         },
7399
7400         /**
7401          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7402          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7403          * @return {Roo.Element} this
7404          */
7405         setDisplayed : function(value) {
7406             if(typeof value == "boolean"){
7407                value = value ? this.originalDisplay : "none";
7408             }
7409             this.setStyle("display", value);
7410             return this;
7411         },
7412
7413         /**
7414          * Tries to focus the element. Any exceptions are caught and ignored.
7415          * @return {Roo.Element} this
7416          */
7417         focus : function() {
7418             try{
7419                 this.dom.focus();
7420             }catch(e){}
7421             return this;
7422         },
7423
7424         /**
7425          * Tries to blur the element. Any exceptions are caught and ignored.
7426          * @return {Roo.Element} this
7427          */
7428         blur : function() {
7429             try{
7430                 this.dom.blur();
7431             }catch(e){}
7432             return this;
7433         },
7434
7435         /**
7436          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7437          * @param {String/Array} className The CSS class to add, or an array of classes
7438          * @return {Roo.Element} this
7439          */
7440         addClass : function(className){
7441             if(className instanceof Array){
7442                 for(var i = 0, len = className.length; i < len; i++) {
7443                     this.addClass(className[i]);
7444                 }
7445             }else{
7446                 if(className && !this.hasClass(className)){
7447                     this.dom.className = this.dom.className + " " + className;
7448                 }
7449             }
7450             return this;
7451         },
7452
7453         /**
7454          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7455          * @param {String/Array} className The CSS class to add, or an array of classes
7456          * @return {Roo.Element} this
7457          */
7458         radioClass : function(className){
7459             var siblings = this.dom.parentNode.childNodes;
7460             for(var i = 0; i < siblings.length; i++) {
7461                 var s = siblings[i];
7462                 if(s.nodeType == 1){
7463                     Roo.get(s).removeClass(className);
7464                 }
7465             }
7466             this.addClass(className);
7467             return this;
7468         },
7469
7470         /**
7471          * Removes one or more CSS classes from the element.
7472          * @param {String/Array} className The CSS class to remove, or an array of classes
7473          * @return {Roo.Element} this
7474          */
7475         removeClass : function(className){
7476             if(!className || !this.dom.className){
7477                 return this;
7478             }
7479             if(className instanceof Array){
7480                 for(var i = 0, len = className.length; i < len; i++) {
7481                     this.removeClass(className[i]);
7482                 }
7483             }else{
7484                 if(this.hasClass(className)){
7485                     var re = this.classReCache[className];
7486                     if (!re) {
7487                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7488                        this.classReCache[className] = re;
7489                     }
7490                     this.dom.className =
7491                         this.dom.className.replace(re, " ");
7492                 }
7493             }
7494             return this;
7495         },
7496
7497         // private
7498         classReCache: {},
7499
7500         /**
7501          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7502          * @param {String} className The CSS class to toggle
7503          * @return {Roo.Element} this
7504          */
7505         toggleClass : function(className){
7506             if(this.hasClass(className)){
7507                 this.removeClass(className);
7508             }else{
7509                 this.addClass(className);
7510             }
7511             return this;
7512         },
7513
7514         /**
7515          * Checks if the specified CSS class exists on this element's DOM node.
7516          * @param {String} className The CSS class to check for
7517          * @return {Boolean} True if the class exists, else false
7518          */
7519         hasClass : function(className){
7520             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7521         },
7522
7523         /**
7524          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7525          * @param {String} oldClassName The CSS class to replace
7526          * @param {String} newClassName The replacement CSS class
7527          * @return {Roo.Element} this
7528          */
7529         replaceClass : function(oldClassName, newClassName){
7530             this.removeClass(oldClassName);
7531             this.addClass(newClassName);
7532             return this;
7533         },
7534
7535         /**
7536          * Returns an object with properties matching the styles requested.
7537          * For example, el.getStyles('color', 'font-size', 'width') might return
7538          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7539          * @param {String} style1 A style name
7540          * @param {String} style2 A style name
7541          * @param {String} etc.
7542          * @return {Object} The style object
7543          */
7544         getStyles : function(){
7545             var a = arguments, len = a.length, r = {};
7546             for(var i = 0; i < len; i++){
7547                 r[a[i]] = this.getStyle(a[i]);
7548             }
7549             return r;
7550         },
7551
7552         /**
7553          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7554          * @param {String} property The style property whose value is returned.
7555          * @return {String} The current value of the style property for this element.
7556          */
7557         getStyle : function(){
7558             return view && view.getComputedStyle ?
7559                 function(prop){
7560                     var el = this.dom, v, cs, camel;
7561                     if(prop == 'float'){
7562                         prop = "cssFloat";
7563                     }
7564                     if(el.style && (v = el.style[prop])){
7565                         return v;
7566                     }
7567                     if(cs = view.getComputedStyle(el, "")){
7568                         if(!(camel = propCache[prop])){
7569                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7570                         }
7571                         return cs[camel];
7572                     }
7573                     return null;
7574                 } :
7575                 function(prop){
7576                     var el = this.dom, v, cs, camel;
7577                     if(prop == 'opacity'){
7578                         if(typeof el.style.filter == 'string'){
7579                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7580                             if(m){
7581                                 var fv = parseFloat(m[1]);
7582                                 if(!isNaN(fv)){
7583                                     return fv ? fv / 100 : 0;
7584                                 }
7585                             }
7586                         }
7587                         return 1;
7588                     }else if(prop == 'float'){
7589                         prop = "styleFloat";
7590                     }
7591                     if(!(camel = propCache[prop])){
7592                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7593                     }
7594                     if(v = el.style[camel]){
7595                         return v;
7596                     }
7597                     if(cs = el.currentStyle){
7598                         return cs[camel];
7599                     }
7600                     return null;
7601                 };
7602         }(),
7603
7604         /**
7605          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7606          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7607          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7608          * @return {Roo.Element} this
7609          */
7610         setStyle : function(prop, value){
7611             if(typeof prop == "string"){
7612                 
7613                 if (prop == 'float') {
7614                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7615                     return this;
7616                 }
7617                 
7618                 var camel;
7619                 if(!(camel = propCache[prop])){
7620                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7621                 }
7622                 
7623                 if(camel == 'opacity') {
7624                     this.setOpacity(value);
7625                 }else{
7626                     this.dom.style[camel] = value;
7627                 }
7628             }else{
7629                 for(var style in prop){
7630                     if(typeof prop[style] != "function"){
7631                        this.setStyle(style, prop[style]);
7632                     }
7633                 }
7634             }
7635             return this;
7636         },
7637
7638         /**
7639          * More flexible version of {@link #setStyle} for setting style properties.
7640          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7641          * a function which returns such a specification.
7642          * @return {Roo.Element} this
7643          */
7644         applyStyles : function(style){
7645             Roo.DomHelper.applyStyles(this.dom, style);
7646             return this;
7647         },
7648
7649         /**
7650           * 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).
7651           * @return {Number} The X position of the element
7652           */
7653         getX : function(){
7654             return D.getX(this.dom);
7655         },
7656
7657         /**
7658           * 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).
7659           * @return {Number} The Y position of the element
7660           */
7661         getY : function(){
7662             return D.getY(this.dom);
7663         },
7664
7665         /**
7666           * 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).
7667           * @return {Array} The XY position of the element
7668           */
7669         getXY : function(){
7670             return D.getXY(this.dom);
7671         },
7672
7673         /**
7674          * 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).
7675          * @param {Number} The X position of the element
7676          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7677          * @return {Roo.Element} this
7678          */
7679         setX : function(x, animate){
7680             if(!animate || !A){
7681                 D.setX(this.dom, x);
7682             }else{
7683                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7684             }
7685             return this;
7686         },
7687
7688         /**
7689          * 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).
7690          * @param {Number} The Y position of the element
7691          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7692          * @return {Roo.Element} this
7693          */
7694         setY : function(y, animate){
7695             if(!animate || !A){
7696                 D.setY(this.dom, y);
7697             }else{
7698                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7699             }
7700             return this;
7701         },
7702
7703         /**
7704          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7705          * @param {String} left The left CSS property value
7706          * @return {Roo.Element} this
7707          */
7708         setLeft : function(left){
7709             this.setStyle("left", this.addUnits(left));
7710             return this;
7711         },
7712
7713         /**
7714          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7715          * @param {String} top The top CSS property value
7716          * @return {Roo.Element} this
7717          */
7718         setTop : function(top){
7719             this.setStyle("top", this.addUnits(top));
7720             return this;
7721         },
7722
7723         /**
7724          * Sets the element's CSS right style.
7725          * @param {String} right The right CSS property value
7726          * @return {Roo.Element} this
7727          */
7728         setRight : function(right){
7729             this.setStyle("right", this.addUnits(right));
7730             return this;
7731         },
7732
7733         /**
7734          * Sets the element's CSS bottom style.
7735          * @param {String} bottom The bottom CSS property value
7736          * @return {Roo.Element} this
7737          */
7738         setBottom : function(bottom){
7739             this.setStyle("bottom", this.addUnits(bottom));
7740             return this;
7741         },
7742
7743         /**
7744          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7745          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7746          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7747          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7748          * @return {Roo.Element} this
7749          */
7750         setXY : function(pos, animate){
7751             if(!animate || !A){
7752                 D.setXY(this.dom, pos);
7753             }else{
7754                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7755             }
7756             return this;
7757         },
7758
7759         /**
7760          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7761          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7762          * @param {Number} x X value for new position (coordinates are page-based)
7763          * @param {Number} y Y value for new position (coordinates are page-based)
7764          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7765          * @return {Roo.Element} this
7766          */
7767         setLocation : function(x, y, animate){
7768             this.setXY([x, y], this.preanim(arguments, 2));
7769             return this;
7770         },
7771
7772         /**
7773          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7774          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7775          * @param {Number} x X value for new position (coordinates are page-based)
7776          * @param {Number} y Y value for new position (coordinates are page-based)
7777          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7778          * @return {Roo.Element} this
7779          */
7780         moveTo : function(x, y, animate){
7781             this.setXY([x, y], this.preanim(arguments, 2));
7782             return this;
7783         },
7784
7785         /**
7786          * Returns the region of the given element.
7787          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7788          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7789          */
7790         getRegion : function(){
7791             return D.getRegion(this.dom);
7792         },
7793
7794         /**
7795          * Returns the offset height of the element
7796          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7797          * @return {Number} The element's height
7798          */
7799         getHeight : function(contentHeight){
7800             var h = this.dom.offsetHeight || 0;
7801             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7802         },
7803
7804         /**
7805          * Returns the offset width of the element
7806          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7807          * @return {Number} The element's width
7808          */
7809         getWidth : function(contentWidth){
7810             var w = this.dom.offsetWidth || 0;
7811             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7812         },
7813
7814         /**
7815          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7816          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7817          * if a height has not been set using CSS.
7818          * @return {Number}
7819          */
7820         getComputedHeight : function(){
7821             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7822             if(!h){
7823                 h = parseInt(this.getStyle('height'), 10) || 0;
7824                 if(!this.isBorderBox()){
7825                     h += this.getFrameWidth('tb');
7826                 }
7827             }
7828             return h;
7829         },
7830
7831         /**
7832          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7833          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7834          * if a width has not been set using CSS.
7835          * @return {Number}
7836          */
7837         getComputedWidth : function(){
7838             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7839             if(!w){
7840                 w = parseInt(this.getStyle('width'), 10) || 0;
7841                 if(!this.isBorderBox()){
7842                     w += this.getFrameWidth('lr');
7843                 }
7844             }
7845             return w;
7846         },
7847
7848         /**
7849          * Returns the size of the element.
7850          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7851          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7852          */
7853         getSize : function(contentSize){
7854             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7855         },
7856
7857         /**
7858          * Returns the width and height of the viewport.
7859          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7860          */
7861         getViewSize : function(){
7862             var d = this.dom, doc = document, aw = 0, ah = 0;
7863             if(d == doc || d == doc.body){
7864                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7865             }else{
7866                 return {
7867                     width : d.clientWidth,
7868                     height: d.clientHeight
7869                 };
7870             }
7871         },
7872
7873         /**
7874          * Returns the value of the "value" attribute
7875          * @param {Boolean} asNumber true to parse the value as a number
7876          * @return {String/Number}
7877          */
7878         getValue : function(asNumber){
7879             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7880         },
7881
7882         // private
7883         adjustWidth : function(width){
7884             if(typeof width == "number"){
7885                 if(this.autoBoxAdjust && !this.isBorderBox()){
7886                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7887                 }
7888                 if(width < 0){
7889                     width = 0;
7890                 }
7891             }
7892             return width;
7893         },
7894
7895         // private
7896         adjustHeight : function(height){
7897             if(typeof height == "number"){
7898                if(this.autoBoxAdjust && !this.isBorderBox()){
7899                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7900                }
7901                if(height < 0){
7902                    height = 0;
7903                }
7904             }
7905             return height;
7906         },
7907
7908         /**
7909          * Set the width of the element
7910          * @param {Number} width The new width
7911          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7912          * @return {Roo.Element} this
7913          */
7914         setWidth : function(width, animate){
7915             width = this.adjustWidth(width);
7916             if(!animate || !A){
7917                 this.dom.style.width = this.addUnits(width);
7918             }else{
7919                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7920             }
7921             return this;
7922         },
7923
7924         /**
7925          * Set the height of the element
7926          * @param {Number} height The new height
7927          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7928          * @return {Roo.Element} this
7929          */
7930          setHeight : function(height, animate){
7931             height = this.adjustHeight(height);
7932             if(!animate || !A){
7933                 this.dom.style.height = this.addUnits(height);
7934             }else{
7935                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7936             }
7937             return this;
7938         },
7939
7940         /**
7941          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7942          * @param {Number} width The new width
7943          * @param {Number} height The new height
7944          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7945          * @return {Roo.Element} this
7946          */
7947          setSize : function(width, height, animate){
7948             if(typeof width == "object"){ // in case of object from getSize()
7949                 height = width.height; width = width.width;
7950             }
7951             width = this.adjustWidth(width); height = this.adjustHeight(height);
7952             if(!animate || !A){
7953                 this.dom.style.width = this.addUnits(width);
7954                 this.dom.style.height = this.addUnits(height);
7955             }else{
7956                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7957             }
7958             return this;
7959         },
7960
7961         /**
7962          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7963          * @param {Number} x X value for new position (coordinates are page-based)
7964          * @param {Number} y Y value for new position (coordinates are page-based)
7965          * @param {Number} width The new width
7966          * @param {Number} height The new height
7967          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7968          * @return {Roo.Element} this
7969          */
7970         setBounds : function(x, y, width, height, animate){
7971             if(!animate || !A){
7972                 this.setSize(width, height);
7973                 this.setLocation(x, y);
7974             }else{
7975                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7976                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7977                               this.preanim(arguments, 4), 'motion');
7978             }
7979             return this;
7980         },
7981
7982         /**
7983          * 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.
7984          * @param {Roo.lib.Region} region The region to fill
7985          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7986          * @return {Roo.Element} this
7987          */
7988         setRegion : function(region, animate){
7989             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7990             return this;
7991         },
7992
7993         /**
7994          * Appends an event handler
7995          *
7996          * @param {String}   eventName     The type of event to append
7997          * @param {Function} fn        The method the event invokes
7998          * @param {Object} scope       (optional) The scope (this object) of the fn
7999          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8000          */
8001         addListener : function(eventName, fn, scope, options){
8002             if (this.dom) {
8003                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8004             }
8005         },
8006
8007         /**
8008          * Removes an event handler from this element
8009          * @param {String} eventName the type of event to remove
8010          * @param {Function} fn the method the event invokes
8011          * @return {Roo.Element} this
8012          */
8013         removeListener : function(eventName, fn){
8014             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8015             return this;
8016         },
8017
8018         /**
8019          * Removes all previous added listeners from this element
8020          * @return {Roo.Element} this
8021          */
8022         removeAllListeners : function(){
8023             E.purgeElement(this.dom);
8024             return this;
8025         },
8026
8027         relayEvent : function(eventName, observable){
8028             this.on(eventName, function(e){
8029                 observable.fireEvent(eventName, e);
8030             });
8031         },
8032
8033         /**
8034          * Set the opacity of the element
8035          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8036          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8037          * @return {Roo.Element} this
8038          */
8039          setOpacity : function(opacity, animate){
8040             if(!animate || !A){
8041                 var s = this.dom.style;
8042                 if(Roo.isIE){
8043                     s.zoom = 1;
8044                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8045                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8046                 }else{
8047                     s.opacity = opacity;
8048                 }
8049             }else{
8050                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8051             }
8052             return this;
8053         },
8054
8055         /**
8056          * Gets the left X coordinate
8057          * @param {Boolean} local True to get the local css position instead of page coordinate
8058          * @return {Number}
8059          */
8060         getLeft : function(local){
8061             if(!local){
8062                 return this.getX();
8063             }else{
8064                 return parseInt(this.getStyle("left"), 10) || 0;
8065             }
8066         },
8067
8068         /**
8069          * Gets the right X coordinate of the element (element X position + element width)
8070          * @param {Boolean} local True to get the local css position instead of page coordinate
8071          * @return {Number}
8072          */
8073         getRight : function(local){
8074             if(!local){
8075                 return this.getX() + this.getWidth();
8076             }else{
8077                 return (this.getLeft(true) + this.getWidth()) || 0;
8078             }
8079         },
8080
8081         /**
8082          * Gets the top Y coordinate
8083          * @param {Boolean} local True to get the local css position instead of page coordinate
8084          * @return {Number}
8085          */
8086         getTop : function(local) {
8087             if(!local){
8088                 return this.getY();
8089             }else{
8090                 return parseInt(this.getStyle("top"), 10) || 0;
8091             }
8092         },
8093
8094         /**
8095          * Gets the bottom Y coordinate of the element (element Y position + element height)
8096          * @param {Boolean} local True to get the local css position instead of page coordinate
8097          * @return {Number}
8098          */
8099         getBottom : function(local){
8100             if(!local){
8101                 return this.getY() + this.getHeight();
8102             }else{
8103                 return (this.getTop(true) + this.getHeight()) || 0;
8104             }
8105         },
8106
8107         /**
8108         * Initializes positioning on this element. If a desired position is not passed, it will make the
8109         * the element positioned relative IF it is not already positioned.
8110         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8111         * @param {Number} zIndex (optional) The zIndex to apply
8112         * @param {Number} x (optional) Set the page X position
8113         * @param {Number} y (optional) Set the page Y position
8114         */
8115         position : function(pos, zIndex, x, y){
8116             if(!pos){
8117                if(this.getStyle('position') == 'static'){
8118                    this.setStyle('position', 'relative');
8119                }
8120             }else{
8121                 this.setStyle("position", pos);
8122             }
8123             if(zIndex){
8124                 this.setStyle("z-index", zIndex);
8125             }
8126             if(x !== undefined && y !== undefined){
8127                 this.setXY([x, y]);
8128             }else if(x !== undefined){
8129                 this.setX(x);
8130             }else if(y !== undefined){
8131                 this.setY(y);
8132             }
8133         },
8134
8135         /**
8136         * Clear positioning back to the default when the document was loaded
8137         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8138         * @return {Roo.Element} this
8139          */
8140         clearPositioning : function(value){
8141             value = value ||'';
8142             this.setStyle({
8143                 "left": value,
8144                 "right": value,
8145                 "top": value,
8146                 "bottom": value,
8147                 "z-index": "",
8148                 "position" : "static"
8149             });
8150             return this;
8151         },
8152
8153         /**
8154         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8155         * snapshot before performing an update and then restoring the element.
8156         * @return {Object}
8157         */
8158         getPositioning : function(){
8159             var l = this.getStyle("left");
8160             var t = this.getStyle("top");
8161             return {
8162                 "position" : this.getStyle("position"),
8163                 "left" : l,
8164                 "right" : l ? "" : this.getStyle("right"),
8165                 "top" : t,
8166                 "bottom" : t ? "" : this.getStyle("bottom"),
8167                 "z-index" : this.getStyle("z-index")
8168             };
8169         },
8170
8171         /**
8172          * Gets the width of the border(s) for the specified side(s)
8173          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8174          * passing lr would get the border (l)eft width + the border (r)ight width.
8175          * @return {Number} The width of the sides passed added together
8176          */
8177         getBorderWidth : function(side){
8178             return this.addStyles(side, El.borders);
8179         },
8180
8181         /**
8182          * Gets the width of the padding(s) for the specified side(s)
8183          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8184          * passing lr would get the padding (l)eft + the padding (r)ight.
8185          * @return {Number} The padding of the sides passed added together
8186          */
8187         getPadding : function(side){
8188             return this.addStyles(side, El.paddings);
8189         },
8190
8191         /**
8192         * Set positioning with an object returned by getPositioning().
8193         * @param {Object} posCfg
8194         * @return {Roo.Element} this
8195          */
8196         setPositioning : function(pc){
8197             this.applyStyles(pc);
8198             if(pc.right == "auto"){
8199                 this.dom.style.right = "";
8200             }
8201             if(pc.bottom == "auto"){
8202                 this.dom.style.bottom = "";
8203             }
8204             return this;
8205         },
8206
8207         // private
8208         fixDisplay : function(){
8209             if(this.getStyle("display") == "none"){
8210                 this.setStyle("visibility", "hidden");
8211                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8212                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8213                     this.setStyle("display", "block");
8214                 }
8215             }
8216         },
8217
8218         /**
8219          * Quick set left and top adding default units
8220          * @param {String} left The left CSS property value
8221          * @param {String} top The top CSS property value
8222          * @return {Roo.Element} this
8223          */
8224          setLeftTop : function(left, top){
8225             this.dom.style.left = this.addUnits(left);
8226             this.dom.style.top = this.addUnits(top);
8227             return this;
8228         },
8229
8230         /**
8231          * Move this element relative to its current position.
8232          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8233          * @param {Number} distance How far to move the element in pixels
8234          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8235          * @return {Roo.Element} this
8236          */
8237          move : function(direction, distance, animate){
8238             var xy = this.getXY();
8239             direction = direction.toLowerCase();
8240             switch(direction){
8241                 case "l":
8242                 case "left":
8243                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8244                     break;
8245                case "r":
8246                case "right":
8247                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8248                     break;
8249                case "t":
8250                case "top":
8251                case "up":
8252                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8253                     break;
8254                case "b":
8255                case "bottom":
8256                case "down":
8257                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8258                     break;
8259             }
8260             return this;
8261         },
8262
8263         /**
8264          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8265          * @return {Roo.Element} this
8266          */
8267         clip : function(){
8268             if(!this.isClipped){
8269                this.isClipped = true;
8270                this.originalClip = {
8271                    "o": this.getStyle("overflow"),
8272                    "x": this.getStyle("overflow-x"),
8273                    "y": this.getStyle("overflow-y")
8274                };
8275                this.setStyle("overflow", "hidden");
8276                this.setStyle("overflow-x", "hidden");
8277                this.setStyle("overflow-y", "hidden");
8278             }
8279             return this;
8280         },
8281
8282         /**
8283          *  Return clipping (overflow) to original clipping before clip() was called
8284          * @return {Roo.Element} this
8285          */
8286         unclip : function(){
8287             if(this.isClipped){
8288                 this.isClipped = false;
8289                 var o = this.originalClip;
8290                 if(o.o){this.setStyle("overflow", o.o);}
8291                 if(o.x){this.setStyle("overflow-x", o.x);}
8292                 if(o.y){this.setStyle("overflow-y", o.y);}
8293             }
8294             return this;
8295         },
8296
8297
8298         /**
8299          * Gets the x,y coordinates specified by the anchor position on the element.
8300          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8301          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8302          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8303          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8304          * @return {Array} [x, y] An array containing the element's x and y coordinates
8305          */
8306         getAnchorXY : function(anchor, local, s){
8307             //Passing a different size is useful for pre-calculating anchors,
8308             //especially for anchored animations that change the el size.
8309
8310             var w, h, vp = false;
8311             if(!s){
8312                 var d = this.dom;
8313                 if(d == document.body || d == document){
8314                     vp = true;
8315                     w = D.getViewWidth(); h = D.getViewHeight();
8316                 }else{
8317                     w = this.getWidth(); h = this.getHeight();
8318                 }
8319             }else{
8320                 w = s.width;  h = s.height;
8321             }
8322             var x = 0, y = 0, r = Math.round;
8323             switch((anchor || "tl").toLowerCase()){
8324                 case "c":
8325                     x = r(w*.5);
8326                     y = r(h*.5);
8327                 break;
8328                 case "t":
8329                     x = r(w*.5);
8330                     y = 0;
8331                 break;
8332                 case "l":
8333                     x = 0;
8334                     y = r(h*.5);
8335                 break;
8336                 case "r":
8337                     x = w;
8338                     y = r(h*.5);
8339                 break;
8340                 case "b":
8341                     x = r(w*.5);
8342                     y = h;
8343                 break;
8344                 case "tl":
8345                     x = 0;
8346                     y = 0;
8347                 break;
8348                 case "bl":
8349                     x = 0;
8350                     y = h;
8351                 break;
8352                 case "br":
8353                     x = w;
8354                     y = h;
8355                 break;
8356                 case "tr":
8357                     x = w;
8358                     y = 0;
8359                 break;
8360             }
8361             if(local === true){
8362                 return [x, y];
8363             }
8364             if(vp){
8365                 var sc = this.getScroll();
8366                 return [x + sc.left, y + sc.top];
8367             }
8368             //Add the element's offset xy
8369             var o = this.getXY();
8370             return [x+o[0], y+o[1]];
8371         },
8372
8373         /**
8374          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8375          * supported position values.
8376          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8377          * @param {String} position The position to align to.
8378          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8379          * @return {Array} [x, y]
8380          */
8381         getAlignToXY : function(el, p, o){
8382             el = Roo.get(el);
8383             var d = this.dom;
8384             if(!el.dom){
8385                 throw "Element.alignTo with an element that doesn't exist";
8386             }
8387             var c = false; //constrain to viewport
8388             var p1 = "", p2 = "";
8389             o = o || [0,0];
8390
8391             if(!p){
8392                 p = "tl-bl";
8393             }else if(p == "?"){
8394                 p = "tl-bl?";
8395             }else if(p.indexOf("-") == -1){
8396                 p = "tl-" + p;
8397             }
8398             p = p.toLowerCase();
8399             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8400             if(!m){
8401                throw "Element.alignTo with an invalid alignment " + p;
8402             }
8403             p1 = m[1]; p2 = m[2]; c = !!m[3];
8404
8405             //Subtract the aligned el's internal xy from the target's offset xy
8406             //plus custom offset to get the aligned el's new offset xy
8407             var a1 = this.getAnchorXY(p1, true);
8408             var a2 = el.getAnchorXY(p2, false);
8409             var x = a2[0] - a1[0] + o[0];
8410             var y = a2[1] - a1[1] + o[1];
8411             if(c){
8412                 //constrain the aligned el to viewport if necessary
8413                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8414                 // 5px of margin for ie
8415                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8416
8417                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8418                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8419                 //otherwise swap the aligned el to the opposite border of the target.
8420                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8421                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8422                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8423                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8424
8425                var doc = document;
8426                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8427                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8428
8429                if((x+w) > dw + scrollX){
8430                     x = swapX ? r.left-w : dw+scrollX-w;
8431                 }
8432                if(x < scrollX){
8433                    x = swapX ? r.right : scrollX;
8434                }
8435                if((y+h) > dh + scrollY){
8436                     y = swapY ? r.top-h : dh+scrollY-h;
8437                 }
8438                if (y < scrollY){
8439                    y = swapY ? r.bottom : scrollY;
8440                }
8441             }
8442             return [x,y];
8443         },
8444
8445         // private
8446         getConstrainToXY : function(){
8447             var os = {top:0, left:0, bottom:0, right: 0};
8448
8449             return function(el, local, offsets, proposedXY){
8450                 el = Roo.get(el);
8451                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8452
8453                 var vw, vh, vx = 0, vy = 0;
8454                 if(el.dom == document.body || el.dom == document){
8455                     vw = Roo.lib.Dom.getViewWidth();
8456                     vh = Roo.lib.Dom.getViewHeight();
8457                 }else{
8458                     vw = el.dom.clientWidth;
8459                     vh = el.dom.clientHeight;
8460                     if(!local){
8461                         var vxy = el.getXY();
8462                         vx = vxy[0];
8463                         vy = vxy[1];
8464                     }
8465                 }
8466
8467                 var s = el.getScroll();
8468
8469                 vx += offsets.left + s.left;
8470                 vy += offsets.top + s.top;
8471
8472                 vw -= offsets.right;
8473                 vh -= offsets.bottom;
8474
8475                 var vr = vx+vw;
8476                 var vb = vy+vh;
8477
8478                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8479                 var x = xy[0], y = xy[1];
8480                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8481
8482                 // only move it if it needs it
8483                 var moved = false;
8484
8485                 // first validate right/bottom
8486                 if((x + w) > vr){
8487                     x = vr - w;
8488                     moved = true;
8489                 }
8490                 if((y + h) > vb){
8491                     y = vb - h;
8492                     moved = true;
8493                 }
8494                 // then make sure top/left isn't negative
8495                 if(x < vx){
8496                     x = vx;
8497                     moved = true;
8498                 }
8499                 if(y < vy){
8500                     y = vy;
8501                     moved = true;
8502                 }
8503                 return moved ? [x, y] : false;
8504             };
8505         }(),
8506
8507         // private
8508         adjustForConstraints : function(xy, parent, offsets){
8509             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8510         },
8511
8512         /**
8513          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8514          * document it aligns it to the viewport.
8515          * The position parameter is optional, and can be specified in any one of the following formats:
8516          * <ul>
8517          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8518          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8519          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8520          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8521          *   <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
8522          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8523          * </ul>
8524          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8525          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8526          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8527          * that specified in order to enforce the viewport constraints.
8528          * Following are all of the supported anchor positions:
8529     <pre>
8530     Value  Description
8531     -----  -----------------------------
8532     tl     The top left corner (default)
8533     t      The center of the top edge
8534     tr     The top right corner
8535     l      The center of the left edge
8536     c      In the center of the element
8537     r      The center of the right edge
8538     bl     The bottom left corner
8539     b      The center of the bottom edge
8540     br     The bottom right corner
8541     </pre>
8542     Example Usage:
8543     <pre><code>
8544     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8545     el.alignTo("other-el");
8546
8547     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8548     el.alignTo("other-el", "tr?");
8549
8550     // align the bottom right corner of el with the center left edge of other-el
8551     el.alignTo("other-el", "br-l?");
8552
8553     // align the center of el with the bottom left corner of other-el and
8554     // adjust the x position by -6 pixels (and the y position by 0)
8555     el.alignTo("other-el", "c-bl", [-6, 0]);
8556     </code></pre>
8557          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8558          * @param {String} position The position to align to.
8559          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8560          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8561          * @return {Roo.Element} this
8562          */
8563         alignTo : function(element, position, offsets, animate){
8564             var xy = this.getAlignToXY(element, position, offsets);
8565             this.setXY(xy, this.preanim(arguments, 3));
8566             return this;
8567         },
8568
8569         /**
8570          * Anchors an element to another element and realigns it when the window is resized.
8571          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8572          * @param {String} position The position to align to.
8573          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8574          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8575          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8576          * is a number, it is used as the buffer delay (defaults to 50ms).
8577          * @param {Function} callback The function to call after the animation finishes
8578          * @return {Roo.Element} this
8579          */
8580         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8581             var action = function(){
8582                 this.alignTo(el, alignment, offsets, animate);
8583                 Roo.callback(callback, this);
8584             };
8585             Roo.EventManager.onWindowResize(action, this);
8586             var tm = typeof monitorScroll;
8587             if(tm != 'undefined'){
8588                 Roo.EventManager.on(window, 'scroll', action, this,
8589                     {buffer: tm == 'number' ? monitorScroll : 50});
8590             }
8591             action.call(this); // align immediately
8592             return this;
8593         },
8594         /**
8595          * Clears any opacity settings from this element. Required in some cases for IE.
8596          * @return {Roo.Element} this
8597          */
8598         clearOpacity : function(){
8599             if (window.ActiveXObject) {
8600                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8601                     this.dom.style.filter = "";
8602                 }
8603             } else {
8604                 this.dom.style.opacity = "";
8605                 this.dom.style["-moz-opacity"] = "";
8606                 this.dom.style["-khtml-opacity"] = "";
8607             }
8608             return this;
8609         },
8610
8611         /**
8612          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8613          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8614          * @return {Roo.Element} this
8615          */
8616         hide : function(animate){
8617             this.setVisible(false, this.preanim(arguments, 0));
8618             return this;
8619         },
8620
8621         /**
8622         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8623         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8624          * @return {Roo.Element} this
8625          */
8626         show : function(animate){
8627             this.setVisible(true, this.preanim(arguments, 0));
8628             return this;
8629         },
8630
8631         /**
8632          * @private Test if size has a unit, otherwise appends the default
8633          */
8634         addUnits : function(size){
8635             return Roo.Element.addUnits(size, this.defaultUnit);
8636         },
8637
8638         /**
8639          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8640          * @return {Roo.Element} this
8641          */
8642         beginMeasure : function(){
8643             var el = this.dom;
8644             if(el.offsetWidth || el.offsetHeight){
8645                 return this; // offsets work already
8646             }
8647             var changed = [];
8648             var p = this.dom, b = document.body; // start with this element
8649             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8650                 var pe = Roo.get(p);
8651                 if(pe.getStyle('display') == 'none'){
8652                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8653                     p.style.visibility = "hidden";
8654                     p.style.display = "block";
8655                 }
8656                 p = p.parentNode;
8657             }
8658             this._measureChanged = changed;
8659             return this;
8660
8661         },
8662
8663         /**
8664          * Restores displays to before beginMeasure was called
8665          * @return {Roo.Element} this
8666          */
8667         endMeasure : function(){
8668             var changed = this._measureChanged;
8669             if(changed){
8670                 for(var i = 0, len = changed.length; i < len; i++) {
8671                     var r = changed[i];
8672                     r.el.style.visibility = r.visibility;
8673                     r.el.style.display = "none";
8674                 }
8675                 this._measureChanged = null;
8676             }
8677             return this;
8678         },
8679
8680         /**
8681         * Update the innerHTML of this element, optionally searching for and processing scripts
8682         * @param {String} html The new HTML
8683         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8684         * @param {Function} callback For async script loading you can be noticed when the update completes
8685         * @return {Roo.Element} this
8686          */
8687         update : function(html, loadScripts, callback){
8688             if(typeof html == "undefined"){
8689                 html = "";
8690             }
8691             if(loadScripts !== true){
8692                 this.dom.innerHTML = html;
8693                 if(typeof callback == "function"){
8694                     callback();
8695                 }
8696                 return this;
8697             }
8698             var id = Roo.id();
8699             var dom = this.dom;
8700
8701             html += '<span id="' + id + '"></span>';
8702
8703             E.onAvailable(id, function(){
8704                 var hd = document.getElementsByTagName("head")[0];
8705                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8706                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8707                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8708
8709                 var match;
8710                 while(match = re.exec(html)){
8711                     var attrs = match[1];
8712                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8713                     if(srcMatch && srcMatch[2]){
8714                        var s = document.createElement("script");
8715                        s.src = srcMatch[2];
8716                        var typeMatch = attrs.match(typeRe);
8717                        if(typeMatch && typeMatch[2]){
8718                            s.type = typeMatch[2];
8719                        }
8720                        hd.appendChild(s);
8721                     }else if(match[2] && match[2].length > 0){
8722                         if(window.execScript) {
8723                            window.execScript(match[2]);
8724                         } else {
8725                             /**
8726                              * eval:var:id
8727                              * eval:var:dom
8728                              * eval:var:html
8729                              * 
8730                              */
8731                            window.eval(match[2]);
8732                         }
8733                     }
8734                 }
8735                 var el = document.getElementById(id);
8736                 if(el){el.parentNode.removeChild(el);}
8737                 if(typeof callback == "function"){
8738                     callback();
8739                 }
8740             });
8741             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8742             return this;
8743         },
8744
8745         /**
8746          * Direct access to the UpdateManager update() method (takes the same parameters).
8747          * @param {String/Function} url The url for this request or a function to call to get the url
8748          * @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}
8749          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8750          * @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.
8751          * @return {Roo.Element} this
8752          */
8753         load : function(){
8754             var um = this.getUpdateManager();
8755             um.update.apply(um, arguments);
8756             return this;
8757         },
8758
8759         /**
8760         * Gets this element's UpdateManager
8761         * @return {Roo.UpdateManager} The UpdateManager
8762         */
8763         getUpdateManager : function(){
8764             if(!this.updateManager){
8765                 this.updateManager = new Roo.UpdateManager(this);
8766             }
8767             return this.updateManager;
8768         },
8769
8770         /**
8771          * Disables text selection for this element (normalized across browsers)
8772          * @return {Roo.Element} this
8773          */
8774         unselectable : function(){
8775             this.dom.unselectable = "on";
8776             this.swallowEvent("selectstart", true);
8777             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8778             this.addClass("x-unselectable");
8779             return this;
8780         },
8781
8782         /**
8783         * Calculates the x, y to center this element on the screen
8784         * @return {Array} The x, y values [x, y]
8785         */
8786         getCenterXY : function(){
8787             return this.getAlignToXY(document, 'c-c');
8788         },
8789
8790         /**
8791         * Centers the Element in either the viewport, or another Element.
8792         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8793         */
8794         center : function(centerIn){
8795             this.alignTo(centerIn || document, 'c-c');
8796             return this;
8797         },
8798
8799         /**
8800          * Tests various css rules/browsers to determine if this element uses a border box
8801          * @return {Boolean}
8802          */
8803         isBorderBox : function(){
8804             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8805         },
8806
8807         /**
8808          * Return a box {x, y, width, height} that can be used to set another elements
8809          * size/location to match this element.
8810          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8811          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8812          * @return {Object} box An object in the format {x, y, width, height}
8813          */
8814         getBox : function(contentBox, local){
8815             var xy;
8816             if(!local){
8817                 xy = this.getXY();
8818             }else{
8819                 var left = parseInt(this.getStyle("left"), 10) || 0;
8820                 var top = parseInt(this.getStyle("top"), 10) || 0;
8821                 xy = [left, top];
8822             }
8823             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8824             if(!contentBox){
8825                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8826             }else{
8827                 var l = this.getBorderWidth("l")+this.getPadding("l");
8828                 var r = this.getBorderWidth("r")+this.getPadding("r");
8829                 var t = this.getBorderWidth("t")+this.getPadding("t");
8830                 var b = this.getBorderWidth("b")+this.getPadding("b");
8831                 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)};
8832             }
8833             bx.right = bx.x + bx.width;
8834             bx.bottom = bx.y + bx.height;
8835             return bx;
8836         },
8837
8838         /**
8839          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8840          for more information about the sides.
8841          * @param {String} sides
8842          * @return {Number}
8843          */
8844         getFrameWidth : function(sides, onlyContentBox){
8845             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8846         },
8847
8848         /**
8849          * 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.
8850          * @param {Object} box The box to fill {x, y, width, height}
8851          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8852          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8853          * @return {Roo.Element} this
8854          */
8855         setBox : function(box, adjust, animate){
8856             var w = box.width, h = box.height;
8857             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8858                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8859                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8860             }
8861             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8862             return this;
8863         },
8864
8865         /**
8866          * Forces the browser to repaint this element
8867          * @return {Roo.Element} this
8868          */
8869          repaint : function(){
8870             var dom = this.dom;
8871             this.addClass("x-repaint");
8872             setTimeout(function(){
8873                 Roo.get(dom).removeClass("x-repaint");
8874             }, 1);
8875             return this;
8876         },
8877
8878         /**
8879          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8880          * then it returns the calculated width of the sides (see getPadding)
8881          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8882          * @return {Object/Number}
8883          */
8884         getMargins : function(side){
8885             if(!side){
8886                 return {
8887                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8888                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8889                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8890                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8891                 };
8892             }else{
8893                 return this.addStyles(side, El.margins);
8894              }
8895         },
8896
8897         // private
8898         addStyles : function(sides, styles){
8899             var val = 0, v, w;
8900             for(var i = 0, len = sides.length; i < len; i++){
8901                 v = this.getStyle(styles[sides.charAt(i)]);
8902                 if(v){
8903                      w = parseInt(v, 10);
8904                      if(w){ val += w; }
8905                 }
8906             }
8907             return val;
8908         },
8909
8910         /**
8911          * Creates a proxy element of this element
8912          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8913          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8914          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8915          * @return {Roo.Element} The new proxy element
8916          */
8917         createProxy : function(config, renderTo, matchBox){
8918             if(renderTo){
8919                 renderTo = Roo.getDom(renderTo);
8920             }else{
8921                 renderTo = document.body;
8922             }
8923             config = typeof config == "object" ?
8924                 config : {tag : "div", cls: config};
8925             var proxy = Roo.DomHelper.append(renderTo, config, true);
8926             if(matchBox){
8927                proxy.setBox(this.getBox());
8928             }
8929             return proxy;
8930         },
8931
8932         /**
8933          * Puts a mask over this element to disable user interaction. Requires core.css.
8934          * This method can only be applied to elements which accept child nodes.
8935          * @param {String} msg (optional) A message to display in the mask
8936          * @param {String} msgCls (optional) A css class to apply to the msg element
8937          * @return {Element} The mask  element
8938          */
8939         mask : function(msg, msgCls)
8940         {
8941             if(this.getStyle("position") == "static"){
8942                 this.setStyle("position", "relative");
8943             }
8944             if(!this._mask){
8945                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8946             }
8947             this.addClass("x-masked");
8948             this._mask.setDisplayed(true);
8949             
8950             // we wander
8951             var z = 0;
8952             var dom = this.dom
8953             while (dom && dom.style) {
8954                 if (!isNaN(parseInt(dom.style.zIndex))) {
8955                     z = Math.max(z, parseInt(dom.style.zIndex));
8956                 }
8957                 dom = dom.parentNode;
8958             }
8959             // if we are masking the body - then it hides everything..
8960             if (this.dom == document.body) {
8961                 z = 1000000;
8962                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8963                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8964             }
8965            
8966             if(typeof msg == 'string'){
8967                 if(!this._maskMsg){
8968                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8969                 }
8970                 var mm = this._maskMsg;
8971                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8972                 mm.dom.firstChild.innerHTML = msg;
8973                 mm.setDisplayed(true);
8974                 mm.center(this);
8975                 mm.setStyle('z-index', z + 102);
8976             }
8977             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8978                 this._mask.setHeight(this.getHeight());
8979             }
8980             this._mask.setStyle('z-index', z + 100);
8981             
8982             return this._mask;
8983         },
8984
8985         /**
8986          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8987          * it is cached for reuse.
8988          */
8989         unmask : function(removeEl){
8990             if(this._mask){
8991                 if(removeEl === true){
8992                     this._mask.remove();
8993                     delete this._mask;
8994                     if(this._maskMsg){
8995                         this._maskMsg.remove();
8996                         delete this._maskMsg;
8997                     }
8998                 }else{
8999                     this._mask.setDisplayed(false);
9000                     if(this._maskMsg){
9001                         this._maskMsg.setDisplayed(false);
9002                     }
9003                 }
9004             }
9005             this.removeClass("x-masked");
9006         },
9007
9008         /**
9009          * Returns true if this element is masked
9010          * @return {Boolean}
9011          */
9012         isMasked : function(){
9013             return this._mask && this._mask.isVisible();
9014         },
9015
9016         /**
9017          * Creates an iframe shim for this element to keep selects and other windowed objects from
9018          * showing through.
9019          * @return {Roo.Element} The new shim element
9020          */
9021         createShim : function(){
9022             var el = document.createElement('iframe');
9023             el.frameBorder = 'no';
9024             el.className = 'roo-shim';
9025             if(Roo.isIE && Roo.isSecure){
9026                 el.src = Roo.SSL_SECURE_URL;
9027             }
9028             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9029             shim.autoBoxAdjust = false;
9030             return shim;
9031         },
9032
9033         /**
9034          * Removes this element from the DOM and deletes it from the cache
9035          */
9036         remove : function(){
9037             if(this.dom.parentNode){
9038                 this.dom.parentNode.removeChild(this.dom);
9039             }
9040             delete El.cache[this.dom.id];
9041         },
9042
9043         /**
9044          * Sets up event handlers to add and remove a css class when the mouse is over this element
9045          * @param {String} className
9046          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9047          * mouseout events for children elements
9048          * @return {Roo.Element} this
9049          */
9050         addClassOnOver : function(className, preventFlicker){
9051             this.on("mouseover", function(){
9052                 Roo.fly(this, '_internal').addClass(className);
9053             }, this.dom);
9054             var removeFn = function(e){
9055                 if(preventFlicker !== true || !e.within(this, true)){
9056                     Roo.fly(this, '_internal').removeClass(className);
9057                 }
9058             };
9059             this.on("mouseout", removeFn, this.dom);
9060             return this;
9061         },
9062
9063         /**
9064          * Sets up event handlers to add and remove a css class when this element has the focus
9065          * @param {String} className
9066          * @return {Roo.Element} this
9067          */
9068         addClassOnFocus : function(className){
9069             this.on("focus", function(){
9070                 Roo.fly(this, '_internal').addClass(className);
9071             }, this.dom);
9072             this.on("blur", function(){
9073                 Roo.fly(this, '_internal').removeClass(className);
9074             }, this.dom);
9075             return this;
9076         },
9077         /**
9078          * 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)
9079          * @param {String} className
9080          * @return {Roo.Element} this
9081          */
9082         addClassOnClick : function(className){
9083             var dom = this.dom;
9084             this.on("mousedown", function(){
9085                 Roo.fly(dom, '_internal').addClass(className);
9086                 var d = Roo.get(document);
9087                 var fn = function(){
9088                     Roo.fly(dom, '_internal').removeClass(className);
9089                     d.removeListener("mouseup", fn);
9090                 };
9091                 d.on("mouseup", fn);
9092             });
9093             return this;
9094         },
9095
9096         /**
9097          * Stops the specified event from bubbling and optionally prevents the default action
9098          * @param {String} eventName
9099          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9100          * @return {Roo.Element} this
9101          */
9102         swallowEvent : function(eventName, preventDefault){
9103             var fn = function(e){
9104                 e.stopPropagation();
9105                 if(preventDefault){
9106                     e.preventDefault();
9107                 }
9108             };
9109             if(eventName instanceof Array){
9110                 for(var i = 0, len = eventName.length; i < len; i++){
9111                      this.on(eventName[i], fn);
9112                 }
9113                 return this;
9114             }
9115             this.on(eventName, fn);
9116             return this;
9117         },
9118
9119         /**
9120          * @private
9121          */
9122       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9123
9124         /**
9125          * Sizes this element to its parent element's dimensions performing
9126          * neccessary box adjustments.
9127          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9128          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9129          * @return {Roo.Element} this
9130          */
9131         fitToParent : function(monitorResize, targetParent) {
9132           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9133           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9134           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9135             return;
9136           }
9137           var p = Roo.get(targetParent || this.dom.parentNode);
9138           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9139           if (monitorResize === true) {
9140             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9141             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9142           }
9143           return this;
9144         },
9145
9146         /**
9147          * Gets the next sibling, skipping text nodes
9148          * @return {HTMLElement} The next sibling or null
9149          */
9150         getNextSibling : function(){
9151             var n = this.dom.nextSibling;
9152             while(n && n.nodeType != 1){
9153                 n = n.nextSibling;
9154             }
9155             return n;
9156         },
9157
9158         /**
9159          * Gets the previous sibling, skipping text nodes
9160          * @return {HTMLElement} The previous sibling or null
9161          */
9162         getPrevSibling : function(){
9163             var n = this.dom.previousSibling;
9164             while(n && n.nodeType != 1){
9165                 n = n.previousSibling;
9166             }
9167             return n;
9168         },
9169
9170
9171         /**
9172          * Appends the passed element(s) to this element
9173          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9174          * @return {Roo.Element} this
9175          */
9176         appendChild: function(el){
9177             el = Roo.get(el);
9178             el.appendTo(this);
9179             return this;
9180         },
9181
9182         /**
9183          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9184          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9185          * automatically generated with the specified attributes.
9186          * @param {HTMLElement} insertBefore (optional) a child element of this element
9187          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9188          * @return {Roo.Element} The new child element
9189          */
9190         createChild: function(config, insertBefore, returnDom){
9191             config = config || {tag:'div'};
9192             if(insertBefore){
9193                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9194             }
9195             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9196         },
9197
9198         /**
9199          * Appends this element to the passed element
9200          * @param {String/HTMLElement/Element} el The new parent element
9201          * @return {Roo.Element} this
9202          */
9203         appendTo: function(el){
9204             el = Roo.getDom(el);
9205             el.appendChild(this.dom);
9206             return this;
9207         },
9208
9209         /**
9210          * Inserts this element before the passed element in the DOM
9211          * @param {String/HTMLElement/Element} el The element to insert before
9212          * @return {Roo.Element} this
9213          */
9214         insertBefore: function(el){
9215             el = Roo.getDom(el);
9216             el.parentNode.insertBefore(this.dom, el);
9217             return this;
9218         },
9219
9220         /**
9221          * Inserts this element after the passed element in the DOM
9222          * @param {String/HTMLElement/Element} el The element to insert after
9223          * @return {Roo.Element} this
9224          */
9225         insertAfter: function(el){
9226             el = Roo.getDom(el);
9227             el.parentNode.insertBefore(this.dom, el.nextSibling);
9228             return this;
9229         },
9230
9231         /**
9232          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9233          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9234          * @return {Roo.Element} The new child
9235          */
9236         insertFirst: function(el, returnDom){
9237             el = el || {};
9238             if(typeof el == 'object' && !el.nodeType){ // dh config
9239                 return this.createChild(el, this.dom.firstChild, returnDom);
9240             }else{
9241                 el = Roo.getDom(el);
9242                 this.dom.insertBefore(el, this.dom.firstChild);
9243                 return !returnDom ? Roo.get(el) : el;
9244             }
9245         },
9246
9247         /**
9248          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9249          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9250          * @param {String} where (optional) 'before' or 'after' defaults to before
9251          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9252          * @return {Roo.Element} the inserted Element
9253          */
9254         insertSibling: function(el, where, returnDom){
9255             where = where ? where.toLowerCase() : 'before';
9256             el = el || {};
9257             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9258
9259             if(typeof el == 'object' && !el.nodeType){ // dh config
9260                 if(where == 'after' && !this.dom.nextSibling){
9261                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9262                 }else{
9263                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9264                 }
9265
9266             }else{
9267                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9268                             where == 'before' ? this.dom : this.dom.nextSibling);
9269                 if(!returnDom){
9270                     rt = Roo.get(rt);
9271                 }
9272             }
9273             return rt;
9274         },
9275
9276         /**
9277          * Creates and wraps this element with another element
9278          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9279          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9280          * @return {HTMLElement/Element} The newly created wrapper element
9281          */
9282         wrap: function(config, returnDom){
9283             if(!config){
9284                 config = {tag: "div"};
9285             }
9286             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9287             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9288             return newEl;
9289         },
9290
9291         /**
9292          * Replaces the passed element with this element
9293          * @param {String/HTMLElement/Element} el The element to replace
9294          * @return {Roo.Element} this
9295          */
9296         replace: function(el){
9297             el = Roo.get(el);
9298             this.insertBefore(el);
9299             el.remove();
9300             return this;
9301         },
9302
9303         /**
9304          * Inserts an html fragment into this element
9305          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9306          * @param {String} html The HTML fragment
9307          * @param {Boolean} returnEl True to return an Roo.Element
9308          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9309          */
9310         insertHtml : function(where, html, returnEl){
9311             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9312             return returnEl ? Roo.get(el) : el;
9313         },
9314
9315         /**
9316          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9317          * @param {Object} o The object with the attributes
9318          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9319          * @return {Roo.Element} this
9320          */
9321         set : function(o, useSet){
9322             var el = this.dom;
9323             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9324             for(var attr in o){
9325                 if(attr == "style" || typeof o[attr] == "function") continue;
9326                 if(attr=="cls"){
9327                     el.className = o["cls"];
9328                 }else{
9329                     if(useSet) el.setAttribute(attr, o[attr]);
9330                     else el[attr] = o[attr];
9331                 }
9332             }
9333             if(o.style){
9334                 Roo.DomHelper.applyStyles(el, o.style);
9335             }
9336             return this;
9337         },
9338
9339         /**
9340          * Convenience method for constructing a KeyMap
9341          * @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:
9342          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9343          * @param {Function} fn The function to call
9344          * @param {Object} scope (optional) The scope of the function
9345          * @return {Roo.KeyMap} The KeyMap created
9346          */
9347         addKeyListener : function(key, fn, scope){
9348             var config;
9349             if(typeof key != "object" || key instanceof Array){
9350                 config = {
9351                     key: key,
9352                     fn: fn,
9353                     scope: scope
9354                 };
9355             }else{
9356                 config = {
9357                     key : key.key,
9358                     shift : key.shift,
9359                     ctrl : key.ctrl,
9360                     alt : key.alt,
9361                     fn: fn,
9362                     scope: scope
9363                 };
9364             }
9365             return new Roo.KeyMap(this, config);
9366         },
9367
9368         /**
9369          * Creates a KeyMap for this element
9370          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9371          * @return {Roo.KeyMap} The KeyMap created
9372          */
9373         addKeyMap : function(config){
9374             return new Roo.KeyMap(this, config);
9375         },
9376
9377         /**
9378          * Returns true if this element is scrollable.
9379          * @return {Boolean}
9380          */
9381          isScrollable : function(){
9382             var dom = this.dom;
9383             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9384         },
9385
9386         /**
9387          * 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().
9388          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9389          * @param {Number} value The new scroll value
9390          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9391          * @return {Element} this
9392          */
9393
9394         scrollTo : function(side, value, animate){
9395             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9396             if(!animate || !A){
9397                 this.dom[prop] = value;
9398             }else{
9399                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9400                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9401             }
9402             return this;
9403         },
9404
9405         /**
9406          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9407          * within this element's scrollable range.
9408          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9409          * @param {Number} distance How far to scroll the element in pixels
9410          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9411          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9412          * was scrolled as far as it could go.
9413          */
9414          scroll : function(direction, distance, animate){
9415              if(!this.isScrollable()){
9416                  return;
9417              }
9418              var el = this.dom;
9419              var l = el.scrollLeft, t = el.scrollTop;
9420              var w = el.scrollWidth, h = el.scrollHeight;
9421              var cw = el.clientWidth, ch = el.clientHeight;
9422              direction = direction.toLowerCase();
9423              var scrolled = false;
9424              var a = this.preanim(arguments, 2);
9425              switch(direction){
9426                  case "l":
9427                  case "left":
9428                      if(w - l > cw){
9429                          var v = Math.min(l + distance, w-cw);
9430                          this.scrollTo("left", v, a);
9431                          scrolled = true;
9432                      }
9433                      break;
9434                 case "r":
9435                 case "right":
9436                      if(l > 0){
9437                          var v = Math.max(l - distance, 0);
9438                          this.scrollTo("left", v, a);
9439                          scrolled = true;
9440                      }
9441                      break;
9442                 case "t":
9443                 case "top":
9444                 case "up":
9445                      if(t > 0){
9446                          var v = Math.max(t - distance, 0);
9447                          this.scrollTo("top", v, a);
9448                          scrolled = true;
9449                      }
9450                      break;
9451                 case "b":
9452                 case "bottom":
9453                 case "down":
9454                      if(h - t > ch){
9455                          var v = Math.min(t + distance, h-ch);
9456                          this.scrollTo("top", v, a);
9457                          scrolled = true;
9458                      }
9459                      break;
9460              }
9461              return scrolled;
9462         },
9463
9464         /**
9465          * Translates the passed page coordinates into left/top css values for this element
9466          * @param {Number/Array} x The page x or an array containing [x, y]
9467          * @param {Number} y The page y
9468          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9469          */
9470         translatePoints : function(x, y){
9471             if(typeof x == 'object' || x instanceof Array){
9472                 y = x[1]; x = x[0];
9473             }
9474             var p = this.getStyle('position');
9475             var o = this.getXY();
9476
9477             var l = parseInt(this.getStyle('left'), 10);
9478             var t = parseInt(this.getStyle('top'), 10);
9479
9480             if(isNaN(l)){
9481                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9482             }
9483             if(isNaN(t)){
9484                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9485             }
9486
9487             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9488         },
9489
9490         /**
9491          * Returns the current scroll position of the element.
9492          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9493          */
9494         getScroll : function(){
9495             var d = this.dom, doc = document;
9496             if(d == doc || d == doc.body){
9497                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9498                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9499                 return {left: l, top: t};
9500             }else{
9501                 return {left: d.scrollLeft, top: d.scrollTop};
9502             }
9503         },
9504
9505         /**
9506          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9507          * are convert to standard 6 digit hex color.
9508          * @param {String} attr The css attribute
9509          * @param {String} defaultValue The default value to use when a valid color isn't found
9510          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9511          * YUI color anims.
9512          */
9513         getColor : function(attr, defaultValue, prefix){
9514             var v = this.getStyle(attr);
9515             if(!v || v == "transparent" || v == "inherit") {
9516                 return defaultValue;
9517             }
9518             var color = typeof prefix == "undefined" ? "#" : prefix;
9519             if(v.substr(0, 4) == "rgb("){
9520                 var rvs = v.slice(4, v.length -1).split(",");
9521                 for(var i = 0; i < 3; i++){
9522                     var h = parseInt(rvs[i]).toString(16);
9523                     if(h < 16){
9524                         h = "0" + h;
9525                     }
9526                     color += h;
9527                 }
9528             } else {
9529                 if(v.substr(0, 1) == "#"){
9530                     if(v.length == 4) {
9531                         for(var i = 1; i < 4; i++){
9532                             var c = v.charAt(i);
9533                             color +=  c + c;
9534                         }
9535                     }else if(v.length == 7){
9536                         color += v.substr(1);
9537                     }
9538                 }
9539             }
9540             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9541         },
9542
9543         /**
9544          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9545          * gradient background, rounded corners and a 4-way shadow.
9546          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9547          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9548          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9549          * @return {Roo.Element} this
9550          */
9551         boxWrap : function(cls){
9552             cls = cls || 'x-box';
9553             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9554             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9555             return el;
9556         },
9557
9558         /**
9559          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9560          * @param {String} namespace The namespace in which to look for the attribute
9561          * @param {String} name The attribute name
9562          * @return {String} The attribute value
9563          */
9564         getAttributeNS : Roo.isIE ? function(ns, name){
9565             var d = this.dom;
9566             var type = typeof d[ns+":"+name];
9567             if(type != 'undefined' && type != 'unknown'){
9568                 return d[ns+":"+name];
9569             }
9570             return d[name];
9571         } : function(ns, name){
9572             var d = this.dom;
9573             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9574         },
9575         
9576         
9577         /**
9578          * Sets or Returns the value the dom attribute value
9579          * @param {String} name The attribute name
9580          * @param {String} value (optional) The value to set the attribute to
9581          * @return {String} The attribute value
9582          */
9583         attr : function(name){
9584             if (arguments.length > 1) {
9585                 this.dom.setAttribute(name, arguments[1]);
9586                 return arguments[1];
9587             }
9588             if (!this.dom.hasAttribute(name)) {
9589                 return undefined;
9590             }
9591             return this.dom.getAttribute(name);
9592         }
9593         
9594         
9595         
9596     };
9597
9598     var ep = El.prototype;
9599
9600     /**
9601      * Appends an event handler (Shorthand for addListener)
9602      * @param {String}   eventName     The type of event to append
9603      * @param {Function} fn        The method the event invokes
9604      * @param {Object} scope       (optional) The scope (this object) of the fn
9605      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9606      * @method
9607      */
9608     ep.on = ep.addListener;
9609         // backwards compat
9610     ep.mon = ep.addListener;
9611
9612     /**
9613      * Removes an event handler from this element (shorthand for removeListener)
9614      * @param {String} eventName the type of event to remove
9615      * @param {Function} fn the method the event invokes
9616      * @return {Roo.Element} this
9617      * @method
9618      */
9619     ep.un = ep.removeListener;
9620
9621     /**
9622      * true to automatically adjust width and height settings for box-model issues (default to true)
9623      */
9624     ep.autoBoxAdjust = true;
9625
9626     // private
9627     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9628
9629     // private
9630     El.addUnits = function(v, defaultUnit){
9631         if(v === "" || v == "auto"){
9632             return v;
9633         }
9634         if(v === undefined){
9635             return '';
9636         }
9637         if(typeof v == "number" || !El.unitPattern.test(v)){
9638             return v + (defaultUnit || 'px');
9639         }
9640         return v;
9641     };
9642
9643     // special markup used throughout Roo when box wrapping elements
9644     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>';
9645     /**
9646      * Visibility mode constant - Use visibility to hide element
9647      * @static
9648      * @type Number
9649      */
9650     El.VISIBILITY = 1;
9651     /**
9652      * Visibility mode constant - Use display to hide element
9653      * @static
9654      * @type Number
9655      */
9656     El.DISPLAY = 2;
9657
9658     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9659     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9660     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9661
9662
9663
9664     /**
9665      * @private
9666      */
9667     El.cache = {};
9668
9669     var docEl;
9670
9671     /**
9672      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9673      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9674      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9675      * @return {Element} The Element object
9676      * @static
9677      */
9678     El.get = function(el){
9679         var ex, elm, id;
9680         if(!el){ return null; }
9681         if(typeof el == "string"){ // element id
9682             if(!(elm = document.getElementById(el))){
9683                 return null;
9684             }
9685             if(ex = El.cache[el]){
9686                 ex.dom = elm;
9687             }else{
9688                 ex = El.cache[el] = new El(elm);
9689             }
9690             return ex;
9691         }else if(el.tagName){ // dom element
9692             if(!(id = el.id)){
9693                 id = Roo.id(el);
9694             }
9695             if(ex = El.cache[id]){
9696                 ex.dom = el;
9697             }else{
9698                 ex = El.cache[id] = new El(el);
9699             }
9700             return ex;
9701         }else if(el instanceof El){
9702             if(el != docEl){
9703                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9704                                                               // catch case where it hasn't been appended
9705                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9706             }
9707             return el;
9708         }else if(el.isComposite){
9709             return el;
9710         }else if(el instanceof Array){
9711             return El.select(el);
9712         }else if(el == document){
9713             // create a bogus element object representing the document object
9714             if(!docEl){
9715                 var f = function(){};
9716                 f.prototype = El.prototype;
9717                 docEl = new f();
9718                 docEl.dom = document;
9719             }
9720             return docEl;
9721         }
9722         return null;
9723     };
9724
9725     // private
9726     El.uncache = function(el){
9727         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9728             if(a[i]){
9729                 delete El.cache[a[i].id || a[i]];
9730             }
9731         }
9732     };
9733
9734     // private
9735     // Garbage collection - uncache elements/purge listeners on orphaned elements
9736     // so we don't hold a reference and cause the browser to retain them
9737     El.garbageCollect = function(){
9738         if(!Roo.enableGarbageCollector){
9739             clearInterval(El.collectorThread);
9740             return;
9741         }
9742         for(var eid in El.cache){
9743             var el = El.cache[eid], d = el.dom;
9744             // -------------------------------------------------------
9745             // Determining what is garbage:
9746             // -------------------------------------------------------
9747             // !d
9748             // dom node is null, definitely garbage
9749             // -------------------------------------------------------
9750             // !d.parentNode
9751             // no parentNode == direct orphan, definitely garbage
9752             // -------------------------------------------------------
9753             // !d.offsetParent && !document.getElementById(eid)
9754             // display none elements have no offsetParent so we will
9755             // also try to look it up by it's id. However, check
9756             // offsetParent first so we don't do unneeded lookups.
9757             // This enables collection of elements that are not orphans
9758             // directly, but somewhere up the line they have an orphan
9759             // parent.
9760             // -------------------------------------------------------
9761             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9762                 delete El.cache[eid];
9763                 if(d && Roo.enableListenerCollection){
9764                     E.purgeElement(d);
9765                 }
9766             }
9767         }
9768     }
9769     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9770
9771
9772     // dom is optional
9773     El.Flyweight = function(dom){
9774         this.dom = dom;
9775     };
9776     El.Flyweight.prototype = El.prototype;
9777
9778     El._flyweights = {};
9779     /**
9780      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9781      * the dom node can be overwritten by other code.
9782      * @param {String/HTMLElement} el The dom node or id
9783      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9784      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9785      * @static
9786      * @return {Element} The shared Element object
9787      */
9788     El.fly = function(el, named){
9789         named = named || '_global';
9790         el = Roo.getDom(el);
9791         if(!el){
9792             return null;
9793         }
9794         if(!El._flyweights[named]){
9795             El._flyweights[named] = new El.Flyweight();
9796         }
9797         El._flyweights[named].dom = el;
9798         return El._flyweights[named];
9799     };
9800
9801     /**
9802      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9803      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9804      * Shorthand of {@link Roo.Element#get}
9805      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9806      * @return {Element} The Element object
9807      * @member Roo
9808      * @method get
9809      */
9810     Roo.get = El.get;
9811     /**
9812      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9813      * the dom node can be overwritten by other code.
9814      * Shorthand of {@link Roo.Element#fly}
9815      * @param {String/HTMLElement} el The dom node or id
9816      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9817      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9818      * @static
9819      * @return {Element} The shared Element object
9820      * @member Roo
9821      * @method fly
9822      */
9823     Roo.fly = El.fly;
9824
9825     // speedy lookup for elements never to box adjust
9826     var noBoxAdjust = Roo.isStrict ? {
9827         select:1
9828     } : {
9829         input:1, select:1, textarea:1
9830     };
9831     if(Roo.isIE || Roo.isGecko){
9832         noBoxAdjust['button'] = 1;
9833     }
9834
9835
9836     Roo.EventManager.on(window, 'unload', function(){
9837         delete El.cache;
9838         delete El._flyweights;
9839     });
9840 })();
9841
9842
9843
9844
9845 if(Roo.DomQuery){
9846     Roo.Element.selectorFunction = Roo.DomQuery.select;
9847 }
9848
9849 Roo.Element.select = function(selector, unique, root){
9850     var els;
9851     if(typeof selector == "string"){
9852         els = Roo.Element.selectorFunction(selector, root);
9853     }else if(selector.length !== undefined){
9854         els = selector;
9855     }else{
9856         throw "Invalid selector";
9857     }
9858     if(unique === true){
9859         return new Roo.CompositeElement(els);
9860     }else{
9861         return new Roo.CompositeElementLite(els);
9862     }
9863 };
9864 /**
9865  * Selects elements based on the passed CSS selector to enable working on them as 1.
9866  * @param {String/Array} selector The CSS selector or an array of elements
9867  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9868  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9869  * @return {CompositeElementLite/CompositeElement}
9870  * @member Roo
9871  * @method select
9872  */
9873 Roo.select = Roo.Element.select;
9874
9875
9876
9877
9878
9879
9880
9881
9882
9883
9884
9885
9886
9887
9888 /*
9889  * Based on:
9890  * Ext JS Library 1.1.1
9891  * Copyright(c) 2006-2007, Ext JS, LLC.
9892  *
9893  * Originally Released Under LGPL - original licence link has changed is not relivant.
9894  *
9895  * Fork - LGPL
9896  * <script type="text/javascript">
9897  */
9898
9899
9900
9901 //Notifies Element that fx methods are available
9902 Roo.enableFx = true;
9903
9904 /**
9905  * @class Roo.Fx
9906  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9907  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9908  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9909  * Element effects to work.</p><br/>
9910  *
9911  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9912  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9913  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9914  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9915  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9916  * expected results and should be done with care.</p><br/>
9917  *
9918  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9919  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9920 <pre>
9921 Value  Description
9922 -----  -----------------------------
9923 tl     The top left corner
9924 t      The center of the top edge
9925 tr     The top right corner
9926 l      The center of the left edge
9927 r      The center of the right edge
9928 bl     The bottom left corner
9929 b      The center of the bottom edge
9930 br     The bottom right corner
9931 </pre>
9932  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9933  * below are common options that can be passed to any Fx method.</b>
9934  * @cfg {Function} callback A function called when the effect is finished
9935  * @cfg {Object} scope The scope of the effect function
9936  * @cfg {String} easing A valid Easing value for the effect
9937  * @cfg {String} afterCls A css class to apply after the effect
9938  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9939  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9940  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9941  * effects that end with the element being visually hidden, ignored otherwise)
9942  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9943  * a function which returns such a specification that will be applied to the Element after the effect finishes
9944  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9945  * @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
9946  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9947  */
9948 Roo.Fx = {
9949         /**
9950          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9951          * origin for the slide effect.  This function automatically handles wrapping the element with
9952          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9953          * Usage:
9954          *<pre><code>
9955 // default: slide the element in from the top
9956 el.slideIn();
9957
9958 // custom: slide the element in from the right with a 2-second duration
9959 el.slideIn('r', { duration: 2 });
9960
9961 // common config options shown with default values
9962 el.slideIn('t', {
9963     easing: 'easeOut',
9964     duration: .5
9965 });
9966 </code></pre>
9967          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9968          * @param {Object} options (optional) Object literal with any of the Fx config options
9969          * @return {Roo.Element} The Element
9970          */
9971     slideIn : function(anchor, o){
9972         var el = this.getFxEl();
9973         o = o || {};
9974
9975         el.queueFx(o, function(){
9976
9977             anchor = anchor || "t";
9978
9979             // fix display to visibility
9980             this.fixDisplay();
9981
9982             // restore values after effect
9983             var r = this.getFxRestore();
9984             var b = this.getBox();
9985             // fixed size for slide
9986             this.setSize(b);
9987
9988             // wrap if needed
9989             var wrap = this.fxWrap(r.pos, o, "hidden");
9990
9991             var st = this.dom.style;
9992             st.visibility = "visible";
9993             st.position = "absolute";
9994
9995             // clear out temp styles after slide and unwrap
9996             var after = function(){
9997                 el.fxUnwrap(wrap, r.pos, o);
9998                 st.width = r.width;
9999                 st.height = r.height;
10000                 el.afterFx(o);
10001             };
10002             // time to calc the positions
10003             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10004
10005             switch(anchor.toLowerCase()){
10006                 case "t":
10007                     wrap.setSize(b.width, 0);
10008                     st.left = st.bottom = "0";
10009                     a = {height: bh};
10010                 break;
10011                 case "l":
10012                     wrap.setSize(0, b.height);
10013                     st.right = st.top = "0";
10014                     a = {width: bw};
10015                 break;
10016                 case "r":
10017                     wrap.setSize(0, b.height);
10018                     wrap.setX(b.right);
10019                     st.left = st.top = "0";
10020                     a = {width: bw, points: pt};
10021                 break;
10022                 case "b":
10023                     wrap.setSize(b.width, 0);
10024                     wrap.setY(b.bottom);
10025                     st.left = st.top = "0";
10026                     a = {height: bh, points: pt};
10027                 break;
10028                 case "tl":
10029                     wrap.setSize(0, 0);
10030                     st.right = st.bottom = "0";
10031                     a = {width: bw, height: bh};
10032                 break;
10033                 case "bl":
10034                     wrap.setSize(0, 0);
10035                     wrap.setY(b.y+b.height);
10036                     st.right = st.top = "0";
10037                     a = {width: bw, height: bh, points: pt};
10038                 break;
10039                 case "br":
10040                     wrap.setSize(0, 0);
10041                     wrap.setXY([b.right, b.bottom]);
10042                     st.left = st.top = "0";
10043                     a = {width: bw, height: bh, points: pt};
10044                 break;
10045                 case "tr":
10046                     wrap.setSize(0, 0);
10047                     wrap.setX(b.x+b.width);
10048                     st.left = st.bottom = "0";
10049                     a = {width: bw, height: bh, points: pt};
10050                 break;
10051             }
10052             this.dom.style.visibility = "visible";
10053             wrap.show();
10054
10055             arguments.callee.anim = wrap.fxanim(a,
10056                 o,
10057                 'motion',
10058                 .5,
10059                 'easeOut', after);
10060         });
10061         return this;
10062     },
10063     
10064         /**
10065          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10066          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10067          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10068          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10069          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10070          * Usage:
10071          *<pre><code>
10072 // default: slide the element out to the top
10073 el.slideOut();
10074
10075 // custom: slide the element out to the right with a 2-second duration
10076 el.slideOut('r', { duration: 2 });
10077
10078 // common config options shown with default values
10079 el.slideOut('t', {
10080     easing: 'easeOut',
10081     duration: .5,
10082     remove: false,
10083     useDisplay: false
10084 });
10085 </code></pre>
10086          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10087          * @param {Object} options (optional) Object literal with any of the Fx config options
10088          * @return {Roo.Element} The Element
10089          */
10090     slideOut : function(anchor, o){
10091         var el = this.getFxEl();
10092         o = o || {};
10093
10094         el.queueFx(o, function(){
10095
10096             anchor = anchor || "t";
10097
10098             // restore values after effect
10099             var r = this.getFxRestore();
10100             
10101             var b = this.getBox();
10102             // fixed size for slide
10103             this.setSize(b);
10104
10105             // wrap if needed
10106             var wrap = this.fxWrap(r.pos, o, "visible");
10107
10108             var st = this.dom.style;
10109             st.visibility = "visible";
10110             st.position = "absolute";
10111
10112             wrap.setSize(b);
10113
10114             var after = function(){
10115                 if(o.useDisplay){
10116                     el.setDisplayed(false);
10117                 }else{
10118                     el.hide();
10119                 }
10120
10121                 el.fxUnwrap(wrap, r.pos, o);
10122
10123                 st.width = r.width;
10124                 st.height = r.height;
10125
10126                 el.afterFx(o);
10127             };
10128
10129             var a, zero = {to: 0};
10130             switch(anchor.toLowerCase()){
10131                 case "t":
10132                     st.left = st.bottom = "0";
10133                     a = {height: zero};
10134                 break;
10135                 case "l":
10136                     st.right = st.top = "0";
10137                     a = {width: zero};
10138                 break;
10139                 case "r":
10140                     st.left = st.top = "0";
10141                     a = {width: zero, points: {to:[b.right, b.y]}};
10142                 break;
10143                 case "b":
10144                     st.left = st.top = "0";
10145                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10146                 break;
10147                 case "tl":
10148                     st.right = st.bottom = "0";
10149                     a = {width: zero, height: zero};
10150                 break;
10151                 case "bl":
10152                     st.right = st.top = "0";
10153                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10154                 break;
10155                 case "br":
10156                     st.left = st.top = "0";
10157                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10158                 break;
10159                 case "tr":
10160                     st.left = st.bottom = "0";
10161                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10162                 break;
10163             }
10164
10165             arguments.callee.anim = wrap.fxanim(a,
10166                 o,
10167                 'motion',
10168                 .5,
10169                 "easeOut", after);
10170         });
10171         return this;
10172     },
10173
10174         /**
10175          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10176          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10177          * The element must be removed from the DOM using the 'remove' config option if desired.
10178          * Usage:
10179          *<pre><code>
10180 // default
10181 el.puff();
10182
10183 // common config options shown with default values
10184 el.puff({
10185     easing: 'easeOut',
10186     duration: .5,
10187     remove: false,
10188     useDisplay: false
10189 });
10190 </code></pre>
10191          * @param {Object} options (optional) Object literal with any of the Fx config options
10192          * @return {Roo.Element} The Element
10193          */
10194     puff : function(o){
10195         var el = this.getFxEl();
10196         o = o || {};
10197
10198         el.queueFx(o, function(){
10199             this.clearOpacity();
10200             this.show();
10201
10202             // restore values after effect
10203             var r = this.getFxRestore();
10204             var st = this.dom.style;
10205
10206             var after = function(){
10207                 if(o.useDisplay){
10208                     el.setDisplayed(false);
10209                 }else{
10210                     el.hide();
10211                 }
10212
10213                 el.clearOpacity();
10214
10215                 el.setPositioning(r.pos);
10216                 st.width = r.width;
10217                 st.height = r.height;
10218                 st.fontSize = '';
10219                 el.afterFx(o);
10220             };
10221
10222             var width = this.getWidth();
10223             var height = this.getHeight();
10224
10225             arguments.callee.anim = this.fxanim({
10226                     width : {to: this.adjustWidth(width * 2)},
10227                     height : {to: this.adjustHeight(height * 2)},
10228                     points : {by: [-(width * .5), -(height * .5)]},
10229                     opacity : {to: 0},
10230                     fontSize: {to:200, unit: "%"}
10231                 },
10232                 o,
10233                 'motion',
10234                 .5,
10235                 "easeOut", after);
10236         });
10237         return this;
10238     },
10239
10240         /**
10241          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10242          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10243          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10244          * Usage:
10245          *<pre><code>
10246 // default
10247 el.switchOff();
10248
10249 // all config options shown with default values
10250 el.switchOff({
10251     easing: 'easeIn',
10252     duration: .3,
10253     remove: false,
10254     useDisplay: false
10255 });
10256 </code></pre>
10257          * @param {Object} options (optional) Object literal with any of the Fx config options
10258          * @return {Roo.Element} The Element
10259          */
10260     switchOff : function(o){
10261         var el = this.getFxEl();
10262         o = o || {};
10263
10264         el.queueFx(o, function(){
10265             this.clearOpacity();
10266             this.clip();
10267
10268             // restore values after effect
10269             var r = this.getFxRestore();
10270             var st = this.dom.style;
10271
10272             var after = function(){
10273                 if(o.useDisplay){
10274                     el.setDisplayed(false);
10275                 }else{
10276                     el.hide();
10277                 }
10278
10279                 el.clearOpacity();
10280                 el.setPositioning(r.pos);
10281                 st.width = r.width;
10282                 st.height = r.height;
10283
10284                 el.afterFx(o);
10285             };
10286
10287             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10288                 this.clearOpacity();
10289                 (function(){
10290                     this.fxanim({
10291                         height:{to:1},
10292                         points:{by:[0, this.getHeight() * .5]}
10293                     }, o, 'motion', 0.3, 'easeIn', after);
10294                 }).defer(100, this);
10295             });
10296         });
10297         return this;
10298     },
10299
10300     /**
10301      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10302      * changed using the "attr" config option) and then fading back to the original color. If no original
10303      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10304      * Usage:
10305 <pre><code>
10306 // default: highlight background to yellow
10307 el.highlight();
10308
10309 // custom: highlight foreground text to blue for 2 seconds
10310 el.highlight("0000ff", { attr: 'color', duration: 2 });
10311
10312 // common config options shown with default values
10313 el.highlight("ffff9c", {
10314     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10315     endColor: (current color) or "ffffff",
10316     easing: 'easeIn',
10317     duration: 1
10318 });
10319 </code></pre>
10320      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10321      * @param {Object} options (optional) Object literal with any of the Fx config options
10322      * @return {Roo.Element} The Element
10323      */ 
10324     highlight : function(color, o){
10325         var el = this.getFxEl();
10326         o = o || {};
10327
10328         el.queueFx(o, function(){
10329             color = color || "ffff9c";
10330             attr = o.attr || "backgroundColor";
10331
10332             this.clearOpacity();
10333             this.show();
10334
10335             var origColor = this.getColor(attr);
10336             var restoreColor = this.dom.style[attr];
10337             endColor = (o.endColor || origColor) || "ffffff";
10338
10339             var after = function(){
10340                 el.dom.style[attr] = restoreColor;
10341                 el.afterFx(o);
10342             };
10343
10344             var a = {};
10345             a[attr] = {from: color, to: endColor};
10346             arguments.callee.anim = this.fxanim(a,
10347                 o,
10348                 'color',
10349                 1,
10350                 'easeIn', after);
10351         });
10352         return this;
10353     },
10354
10355    /**
10356     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10357     * Usage:
10358 <pre><code>
10359 // default: a single light blue ripple
10360 el.frame();
10361
10362 // custom: 3 red ripples lasting 3 seconds total
10363 el.frame("ff0000", 3, { duration: 3 });
10364
10365 // common config options shown with default values
10366 el.frame("C3DAF9", 1, {
10367     duration: 1 //duration of entire animation (not each individual ripple)
10368     // Note: Easing is not configurable and will be ignored if included
10369 });
10370 </code></pre>
10371     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10372     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10373     * @param {Object} options (optional) Object literal with any of the Fx config options
10374     * @return {Roo.Element} The Element
10375     */
10376     frame : function(color, count, o){
10377         var el = this.getFxEl();
10378         o = o || {};
10379
10380         el.queueFx(o, function(){
10381             color = color || "#C3DAF9";
10382             if(color.length == 6){
10383                 color = "#" + color;
10384             }
10385             count = count || 1;
10386             duration = o.duration || 1;
10387             this.show();
10388
10389             var b = this.getBox();
10390             var animFn = function(){
10391                 var proxy = this.createProxy({
10392
10393                      style:{
10394                         visbility:"hidden",
10395                         position:"absolute",
10396                         "z-index":"35000", // yee haw
10397                         border:"0px solid " + color
10398                      }
10399                   });
10400                 var scale = Roo.isBorderBox ? 2 : 1;
10401                 proxy.animate({
10402                     top:{from:b.y, to:b.y - 20},
10403                     left:{from:b.x, to:b.x - 20},
10404                     borderWidth:{from:0, to:10},
10405                     opacity:{from:1, to:0},
10406                     height:{from:b.height, to:(b.height + (20*scale))},
10407                     width:{from:b.width, to:(b.width + (20*scale))}
10408                 }, duration, function(){
10409                     proxy.remove();
10410                 });
10411                 if(--count > 0){
10412                      animFn.defer((duration/2)*1000, this);
10413                 }else{
10414                     el.afterFx(o);
10415                 }
10416             };
10417             animFn.call(this);
10418         });
10419         return this;
10420     },
10421
10422    /**
10423     * Creates a pause before any subsequent queued effects begin.  If there are
10424     * no effects queued after the pause it will have no effect.
10425     * Usage:
10426 <pre><code>
10427 el.pause(1);
10428 </code></pre>
10429     * @param {Number} seconds The length of time to pause (in seconds)
10430     * @return {Roo.Element} The Element
10431     */
10432     pause : function(seconds){
10433         var el = this.getFxEl();
10434         var o = {};
10435
10436         el.queueFx(o, function(){
10437             setTimeout(function(){
10438                 el.afterFx(o);
10439             }, seconds * 1000);
10440         });
10441         return this;
10442     },
10443
10444    /**
10445     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10446     * using the "endOpacity" config option.
10447     * Usage:
10448 <pre><code>
10449 // default: fade in from opacity 0 to 100%
10450 el.fadeIn();
10451
10452 // custom: fade in from opacity 0 to 75% over 2 seconds
10453 el.fadeIn({ endOpacity: .75, duration: 2});
10454
10455 // common config options shown with default values
10456 el.fadeIn({
10457     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10458     easing: 'easeOut',
10459     duration: .5
10460 });
10461 </code></pre>
10462     * @param {Object} options (optional) Object literal with any of the Fx config options
10463     * @return {Roo.Element} The Element
10464     */
10465     fadeIn : function(o){
10466         var el = this.getFxEl();
10467         o = o || {};
10468         el.queueFx(o, function(){
10469             this.setOpacity(0);
10470             this.fixDisplay();
10471             this.dom.style.visibility = 'visible';
10472             var to = o.endOpacity || 1;
10473             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10474                 o, null, .5, "easeOut", function(){
10475                 if(to == 1){
10476                     this.clearOpacity();
10477                 }
10478                 el.afterFx(o);
10479             });
10480         });
10481         return this;
10482     },
10483
10484    /**
10485     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10486     * using the "endOpacity" config option.
10487     * Usage:
10488 <pre><code>
10489 // default: fade out from the element's current opacity to 0
10490 el.fadeOut();
10491
10492 // custom: fade out from the element's current opacity to 25% over 2 seconds
10493 el.fadeOut({ endOpacity: .25, duration: 2});
10494
10495 // common config options shown with default values
10496 el.fadeOut({
10497     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10498     easing: 'easeOut',
10499     duration: .5
10500     remove: false,
10501     useDisplay: false
10502 });
10503 </code></pre>
10504     * @param {Object} options (optional) Object literal with any of the Fx config options
10505     * @return {Roo.Element} The Element
10506     */
10507     fadeOut : function(o){
10508         var el = this.getFxEl();
10509         o = o || {};
10510         el.queueFx(o, function(){
10511             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10512                 o, null, .5, "easeOut", function(){
10513                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10514                      this.dom.style.display = "none";
10515                 }else{
10516                      this.dom.style.visibility = "hidden";
10517                 }
10518                 this.clearOpacity();
10519                 el.afterFx(o);
10520             });
10521         });
10522         return this;
10523     },
10524
10525    /**
10526     * Animates the transition of an element's dimensions from a starting height/width
10527     * to an ending height/width.
10528     * Usage:
10529 <pre><code>
10530 // change height and width to 100x100 pixels
10531 el.scale(100, 100);
10532
10533 // common config options shown with default values.  The height and width will default to
10534 // the element's existing values if passed as null.
10535 el.scale(
10536     [element's width],
10537     [element's height], {
10538     easing: 'easeOut',
10539     duration: .35
10540 });
10541 </code></pre>
10542     * @param {Number} width  The new width (pass undefined to keep the original width)
10543     * @param {Number} height  The new height (pass undefined to keep the original height)
10544     * @param {Object} options (optional) Object literal with any of the Fx config options
10545     * @return {Roo.Element} The Element
10546     */
10547     scale : function(w, h, o){
10548         this.shift(Roo.apply({}, o, {
10549             width: w,
10550             height: h
10551         }));
10552         return this;
10553     },
10554
10555    /**
10556     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10557     * Any of these properties not specified in the config object will not be changed.  This effect 
10558     * requires that at least one new dimension, position or opacity setting must be passed in on
10559     * the config object in order for the function to have any effect.
10560     * Usage:
10561 <pre><code>
10562 // slide the element horizontally to x position 200 while changing the height and opacity
10563 el.shift({ x: 200, height: 50, opacity: .8 });
10564
10565 // common config options shown with default values.
10566 el.shift({
10567     width: [element's width],
10568     height: [element's height],
10569     x: [element's x position],
10570     y: [element's y position],
10571     opacity: [element's opacity],
10572     easing: 'easeOut',
10573     duration: .35
10574 });
10575 </code></pre>
10576     * @param {Object} options  Object literal with any of the Fx config options
10577     * @return {Roo.Element} The Element
10578     */
10579     shift : function(o){
10580         var el = this.getFxEl();
10581         o = o || {};
10582         el.queueFx(o, function(){
10583             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10584             if(w !== undefined){
10585                 a.width = {to: this.adjustWidth(w)};
10586             }
10587             if(h !== undefined){
10588                 a.height = {to: this.adjustHeight(h)};
10589             }
10590             if(x !== undefined || y !== undefined){
10591                 a.points = {to: [
10592                     x !== undefined ? x : this.getX(),
10593                     y !== undefined ? y : this.getY()
10594                 ]};
10595             }
10596             if(op !== undefined){
10597                 a.opacity = {to: op};
10598             }
10599             if(o.xy !== undefined){
10600                 a.points = {to: o.xy};
10601             }
10602             arguments.callee.anim = this.fxanim(a,
10603                 o, 'motion', .35, "easeOut", function(){
10604                 el.afterFx(o);
10605             });
10606         });
10607         return this;
10608     },
10609
10610         /**
10611          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10612          * ending point of the effect.
10613          * Usage:
10614          *<pre><code>
10615 // default: slide the element downward while fading out
10616 el.ghost();
10617
10618 // custom: slide the element out to the right with a 2-second duration
10619 el.ghost('r', { duration: 2 });
10620
10621 // common config options shown with default values
10622 el.ghost('b', {
10623     easing: 'easeOut',
10624     duration: .5
10625     remove: false,
10626     useDisplay: false
10627 });
10628 </code></pre>
10629          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10630          * @param {Object} options (optional) Object literal with any of the Fx config options
10631          * @return {Roo.Element} The Element
10632          */
10633     ghost : function(anchor, o){
10634         var el = this.getFxEl();
10635         o = o || {};
10636
10637         el.queueFx(o, function(){
10638             anchor = anchor || "b";
10639
10640             // restore values after effect
10641             var r = this.getFxRestore();
10642             var w = this.getWidth(),
10643                 h = this.getHeight();
10644
10645             var st = this.dom.style;
10646
10647             var after = function(){
10648                 if(o.useDisplay){
10649                     el.setDisplayed(false);
10650                 }else{
10651                     el.hide();
10652                 }
10653
10654                 el.clearOpacity();
10655                 el.setPositioning(r.pos);
10656                 st.width = r.width;
10657                 st.height = r.height;
10658
10659                 el.afterFx(o);
10660             };
10661
10662             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10663             switch(anchor.toLowerCase()){
10664                 case "t":
10665                     pt.by = [0, -h];
10666                 break;
10667                 case "l":
10668                     pt.by = [-w, 0];
10669                 break;
10670                 case "r":
10671                     pt.by = [w, 0];
10672                 break;
10673                 case "b":
10674                     pt.by = [0, h];
10675                 break;
10676                 case "tl":
10677                     pt.by = [-w, -h];
10678                 break;
10679                 case "bl":
10680                     pt.by = [-w, h];
10681                 break;
10682                 case "br":
10683                     pt.by = [w, h];
10684                 break;
10685                 case "tr":
10686                     pt.by = [w, -h];
10687                 break;
10688             }
10689
10690             arguments.callee.anim = this.fxanim(a,
10691                 o,
10692                 'motion',
10693                 .5,
10694                 "easeOut", after);
10695         });
10696         return this;
10697     },
10698
10699         /**
10700          * Ensures that all effects queued after syncFx is called on the element are
10701          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10702          * @return {Roo.Element} The Element
10703          */
10704     syncFx : function(){
10705         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10706             block : false,
10707             concurrent : true,
10708             stopFx : false
10709         });
10710         return this;
10711     },
10712
10713         /**
10714          * Ensures that all effects queued after sequenceFx is called on the element are
10715          * run in sequence.  This is the opposite of {@link #syncFx}.
10716          * @return {Roo.Element} The Element
10717          */
10718     sequenceFx : function(){
10719         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10720             block : false,
10721             concurrent : false,
10722             stopFx : false
10723         });
10724         return this;
10725     },
10726
10727         /* @private */
10728     nextFx : function(){
10729         var ef = this.fxQueue[0];
10730         if(ef){
10731             ef.call(this);
10732         }
10733     },
10734
10735         /**
10736          * Returns true if the element has any effects actively running or queued, else returns false.
10737          * @return {Boolean} True if element has active effects, else false
10738          */
10739     hasActiveFx : function(){
10740         return this.fxQueue && this.fxQueue[0];
10741     },
10742
10743         /**
10744          * Stops any running effects and clears the element's internal effects queue if it contains
10745          * any additional effects that haven't started yet.
10746          * @return {Roo.Element} The Element
10747          */
10748     stopFx : function(){
10749         if(this.hasActiveFx()){
10750             var cur = this.fxQueue[0];
10751             if(cur && cur.anim && cur.anim.isAnimated()){
10752                 this.fxQueue = [cur]; // clear out others
10753                 cur.anim.stop(true);
10754             }
10755         }
10756         return this;
10757     },
10758
10759         /* @private */
10760     beforeFx : function(o){
10761         if(this.hasActiveFx() && !o.concurrent){
10762            if(o.stopFx){
10763                this.stopFx();
10764                return true;
10765            }
10766            return false;
10767         }
10768         return true;
10769     },
10770
10771         /**
10772          * Returns true if the element is currently blocking so that no other effect can be queued
10773          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10774          * used to ensure that an effect initiated by a user action runs to completion prior to the
10775          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10776          * @return {Boolean} True if blocking, else false
10777          */
10778     hasFxBlock : function(){
10779         var q = this.fxQueue;
10780         return q && q[0] && q[0].block;
10781     },
10782
10783         /* @private */
10784     queueFx : function(o, fn){
10785         if(!this.fxQueue){
10786             this.fxQueue = [];
10787         }
10788         if(!this.hasFxBlock()){
10789             Roo.applyIf(o, this.fxDefaults);
10790             if(!o.concurrent){
10791                 var run = this.beforeFx(o);
10792                 fn.block = o.block;
10793                 this.fxQueue.push(fn);
10794                 if(run){
10795                     this.nextFx();
10796                 }
10797             }else{
10798                 fn.call(this);
10799             }
10800         }
10801         return this;
10802     },
10803
10804         /* @private */
10805     fxWrap : function(pos, o, vis){
10806         var wrap;
10807         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10808             var wrapXY;
10809             if(o.fixPosition){
10810                 wrapXY = this.getXY();
10811             }
10812             var div = document.createElement("div");
10813             div.style.visibility = vis;
10814             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10815             wrap.setPositioning(pos);
10816             if(wrap.getStyle("position") == "static"){
10817                 wrap.position("relative");
10818             }
10819             this.clearPositioning('auto');
10820             wrap.clip();
10821             wrap.dom.appendChild(this.dom);
10822             if(wrapXY){
10823                 wrap.setXY(wrapXY);
10824             }
10825         }
10826         return wrap;
10827     },
10828
10829         /* @private */
10830     fxUnwrap : function(wrap, pos, o){
10831         this.clearPositioning();
10832         this.setPositioning(pos);
10833         if(!o.wrap){
10834             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10835             wrap.remove();
10836         }
10837     },
10838
10839         /* @private */
10840     getFxRestore : function(){
10841         var st = this.dom.style;
10842         return {pos: this.getPositioning(), width: st.width, height : st.height};
10843     },
10844
10845         /* @private */
10846     afterFx : function(o){
10847         if(o.afterStyle){
10848             this.applyStyles(o.afterStyle);
10849         }
10850         if(o.afterCls){
10851             this.addClass(o.afterCls);
10852         }
10853         if(o.remove === true){
10854             this.remove();
10855         }
10856         Roo.callback(o.callback, o.scope, [this]);
10857         if(!o.concurrent){
10858             this.fxQueue.shift();
10859             this.nextFx();
10860         }
10861     },
10862
10863         /* @private */
10864     getFxEl : function(){ // support for composite element fx
10865         return Roo.get(this.dom);
10866     },
10867
10868         /* @private */
10869     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10870         animType = animType || 'run';
10871         opt = opt || {};
10872         var anim = Roo.lib.Anim[animType](
10873             this.dom, args,
10874             (opt.duration || defaultDur) || .35,
10875             (opt.easing || defaultEase) || 'easeOut',
10876             function(){
10877                 Roo.callback(cb, this);
10878             },
10879             this
10880         );
10881         opt.anim = anim;
10882         return anim;
10883     }
10884 };
10885
10886 // backwords compat
10887 Roo.Fx.resize = Roo.Fx.scale;
10888
10889 //When included, Roo.Fx is automatically applied to Element so that all basic
10890 //effects are available directly via the Element API
10891 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10892  * Based on:
10893  * Ext JS Library 1.1.1
10894  * Copyright(c) 2006-2007, Ext JS, LLC.
10895  *
10896  * Originally Released Under LGPL - original licence link has changed is not relivant.
10897  *
10898  * Fork - LGPL
10899  * <script type="text/javascript">
10900  */
10901
10902
10903 /**
10904  * @class Roo.CompositeElement
10905  * Standard composite class. Creates a Roo.Element for every element in the collection.
10906  * <br><br>
10907  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10908  * actions will be performed on all the elements in this collection.</b>
10909  * <br><br>
10910  * All methods return <i>this</i> and can be chained.
10911  <pre><code>
10912  var els = Roo.select("#some-el div.some-class", true);
10913  // or select directly from an existing element
10914  var el = Roo.get('some-el');
10915  el.select('div.some-class', true);
10916
10917  els.setWidth(100); // all elements become 100 width
10918  els.hide(true); // all elements fade out and hide
10919  // or
10920  els.setWidth(100).hide(true);
10921  </code></pre>
10922  */
10923 Roo.CompositeElement = function(els){
10924     this.elements = [];
10925     this.addElements(els);
10926 };
10927 Roo.CompositeElement.prototype = {
10928     isComposite: true,
10929     addElements : function(els){
10930         if(!els) return this;
10931         if(typeof els == "string"){
10932             els = Roo.Element.selectorFunction(els);
10933         }
10934         var yels = this.elements;
10935         var index = yels.length-1;
10936         for(var i = 0, len = els.length; i < len; i++) {
10937                 yels[++index] = Roo.get(els[i]);
10938         }
10939         return this;
10940     },
10941
10942     /**
10943     * Clears this composite and adds the elements returned by the passed selector.
10944     * @param {String/Array} els A string CSS selector, an array of elements or an element
10945     * @return {CompositeElement} this
10946     */
10947     fill : function(els){
10948         this.elements = [];
10949         this.add(els);
10950         return this;
10951     },
10952
10953     /**
10954     * Filters this composite to only elements that match the passed selector.
10955     * @param {String} selector A string CSS selector
10956     * @return {CompositeElement} this
10957     */
10958     filter : function(selector){
10959         var els = [];
10960         this.each(function(el){
10961             if(el.is(selector)){
10962                 els[els.length] = el.dom;
10963             }
10964         });
10965         this.fill(els);
10966         return this;
10967     },
10968
10969     invoke : function(fn, args){
10970         var els = this.elements;
10971         for(var i = 0, len = els.length; i < len; i++) {
10972                 Roo.Element.prototype[fn].apply(els[i], args);
10973         }
10974         return this;
10975     },
10976     /**
10977     * Adds elements to this composite.
10978     * @param {String/Array} els A string CSS selector, an array of elements or an element
10979     * @return {CompositeElement} this
10980     */
10981     add : function(els){
10982         if(typeof els == "string"){
10983             this.addElements(Roo.Element.selectorFunction(els));
10984         }else if(els.length !== undefined){
10985             this.addElements(els);
10986         }else{
10987             this.addElements([els]);
10988         }
10989         return this;
10990     },
10991     /**
10992     * Calls the passed function passing (el, this, index) for each element in this composite.
10993     * @param {Function} fn The function to call
10994     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
10995     * @return {CompositeElement} this
10996     */
10997     each : function(fn, scope){
10998         var els = this.elements;
10999         for(var i = 0, len = els.length; i < len; i++){
11000             if(fn.call(scope || els[i], els[i], this, i) === false) {
11001                 break;
11002             }
11003         }
11004         return this;
11005     },
11006
11007     /**
11008      * Returns the Element object at the specified index
11009      * @param {Number} index
11010      * @return {Roo.Element}
11011      */
11012     item : function(index){
11013         return this.elements[index] || null;
11014     },
11015
11016     /**
11017      * Returns the first Element
11018      * @return {Roo.Element}
11019      */
11020     first : function(){
11021         return this.item(0);
11022     },
11023
11024     /**
11025      * Returns the last Element
11026      * @return {Roo.Element}
11027      */
11028     last : function(){
11029         return this.item(this.elements.length-1);
11030     },
11031
11032     /**
11033      * Returns the number of elements in this composite
11034      * @return Number
11035      */
11036     getCount : function(){
11037         return this.elements.length;
11038     },
11039
11040     /**
11041      * Returns true if this composite contains the passed element
11042      * @return Boolean
11043      */
11044     contains : function(el){
11045         return this.indexOf(el) !== -1;
11046     },
11047
11048     /**
11049      * Returns true if this composite contains the passed element
11050      * @return Boolean
11051      */
11052     indexOf : function(el){
11053         return this.elements.indexOf(Roo.get(el));
11054     },
11055
11056
11057     /**
11058     * Removes the specified element(s).
11059     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11060     * or an array of any of those.
11061     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11062     * @return {CompositeElement} this
11063     */
11064     removeElement : function(el, removeDom){
11065         if(el instanceof Array){
11066             for(var i = 0, len = el.length; i < len; i++){
11067                 this.removeElement(el[i]);
11068             }
11069             return this;
11070         }
11071         var index = typeof el == 'number' ? el : this.indexOf(el);
11072         if(index !== -1){
11073             if(removeDom){
11074                 var d = this.elements[index];
11075                 if(d.dom){
11076                     d.remove();
11077                 }else{
11078                     d.parentNode.removeChild(d);
11079                 }
11080             }
11081             this.elements.splice(index, 1);
11082         }
11083         return this;
11084     },
11085
11086     /**
11087     * Replaces the specified element with the passed element.
11088     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11089     * to replace.
11090     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11091     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11092     * @return {CompositeElement} this
11093     */
11094     replaceElement : function(el, replacement, domReplace){
11095         var index = typeof el == 'number' ? el : this.indexOf(el);
11096         if(index !== -1){
11097             if(domReplace){
11098                 this.elements[index].replaceWith(replacement);
11099             }else{
11100                 this.elements.splice(index, 1, Roo.get(replacement))
11101             }
11102         }
11103         return this;
11104     },
11105
11106     /**
11107      * Removes all elements.
11108      */
11109     clear : function(){
11110         this.elements = [];
11111     }
11112 };
11113 (function(){
11114     Roo.CompositeElement.createCall = function(proto, fnName){
11115         if(!proto[fnName]){
11116             proto[fnName] = function(){
11117                 return this.invoke(fnName, arguments);
11118             };
11119         }
11120     };
11121     for(var fnName in Roo.Element.prototype){
11122         if(typeof Roo.Element.prototype[fnName] == "function"){
11123             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11124         }
11125     };
11126 })();
11127 /*
11128  * Based on:
11129  * Ext JS Library 1.1.1
11130  * Copyright(c) 2006-2007, Ext JS, LLC.
11131  *
11132  * Originally Released Under LGPL - original licence link has changed is not relivant.
11133  *
11134  * Fork - LGPL
11135  * <script type="text/javascript">
11136  */
11137
11138 /**
11139  * @class Roo.CompositeElementLite
11140  * @extends Roo.CompositeElement
11141  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11142  <pre><code>
11143  var els = Roo.select("#some-el div.some-class");
11144  // or select directly from an existing element
11145  var el = Roo.get('some-el');
11146  el.select('div.some-class');
11147
11148  els.setWidth(100); // all elements become 100 width
11149  els.hide(true); // all elements fade out and hide
11150  // or
11151  els.setWidth(100).hide(true);
11152  </code></pre><br><br>
11153  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11154  * actions will be performed on all the elements in this collection.</b>
11155  */
11156 Roo.CompositeElementLite = function(els){
11157     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11158     this.el = new Roo.Element.Flyweight();
11159 };
11160 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11161     addElements : function(els){
11162         if(els){
11163             if(els instanceof Array){
11164                 this.elements = this.elements.concat(els);
11165             }else{
11166                 var yels = this.elements;
11167                 var index = yels.length-1;
11168                 for(var i = 0, len = els.length; i < len; i++) {
11169                     yels[++index] = els[i];
11170                 }
11171             }
11172         }
11173         return this;
11174     },
11175     invoke : function(fn, args){
11176         var els = this.elements;
11177         var el = this.el;
11178         for(var i = 0, len = els.length; i < len; i++) {
11179             el.dom = els[i];
11180                 Roo.Element.prototype[fn].apply(el, args);
11181         }
11182         return this;
11183     },
11184     /**
11185      * Returns a flyweight Element of the dom element object at the specified index
11186      * @param {Number} index
11187      * @return {Roo.Element}
11188      */
11189     item : function(index){
11190         if(!this.elements[index]){
11191             return null;
11192         }
11193         this.el.dom = this.elements[index];
11194         return this.el;
11195     },
11196
11197     // fixes scope with flyweight
11198     addListener : function(eventName, handler, scope, opt){
11199         var els = this.elements;
11200         for(var i = 0, len = els.length; i < len; i++) {
11201             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11202         }
11203         return this;
11204     },
11205
11206     /**
11207     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11208     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11209     * a reference to the dom node, use el.dom.</b>
11210     * @param {Function} fn The function to call
11211     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11212     * @return {CompositeElement} this
11213     */
11214     each : function(fn, scope){
11215         var els = this.elements;
11216         var el = this.el;
11217         for(var i = 0, len = els.length; i < len; i++){
11218             el.dom = els[i];
11219                 if(fn.call(scope || el, el, this, i) === false){
11220                 break;
11221             }
11222         }
11223         return this;
11224     },
11225
11226     indexOf : function(el){
11227         return this.elements.indexOf(Roo.getDom(el));
11228     },
11229
11230     replaceElement : function(el, replacement, domReplace){
11231         var index = typeof el == 'number' ? el : this.indexOf(el);
11232         if(index !== -1){
11233             replacement = Roo.getDom(replacement);
11234             if(domReplace){
11235                 var d = this.elements[index];
11236                 d.parentNode.insertBefore(replacement, d);
11237                 d.parentNode.removeChild(d);
11238             }
11239             this.elements.splice(index, 1, replacement);
11240         }
11241         return this;
11242     }
11243 });
11244 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11245
11246 /*
11247  * Based on:
11248  * Ext JS Library 1.1.1
11249  * Copyright(c) 2006-2007, Ext JS, LLC.
11250  *
11251  * Originally Released Under LGPL - original licence link has changed is not relivant.
11252  *
11253  * Fork - LGPL
11254  * <script type="text/javascript">
11255  */
11256
11257  
11258
11259 /**
11260  * @class Roo.data.Connection
11261  * @extends Roo.util.Observable
11262  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11263  * either to a configured URL, or to a URL specified at request time.<br><br>
11264  * <p>
11265  * Requests made by this class are asynchronous, and will return immediately. No data from
11266  * the server will be available to the statement immediately following the {@link #request} call.
11267  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11268  * <p>
11269  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11270  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11271  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11272  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11273  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11274  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11275  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11276  * standard DOM methods.
11277  * @constructor
11278  * @param {Object} config a configuration object.
11279  */
11280 Roo.data.Connection = function(config){
11281     Roo.apply(this, config);
11282     this.addEvents({
11283         /**
11284          * @event beforerequest
11285          * Fires before a network request is made to retrieve a data object.
11286          * @param {Connection} conn This Connection object.
11287          * @param {Object} options The options config object passed to the {@link #request} method.
11288          */
11289         "beforerequest" : true,
11290         /**
11291          * @event requestcomplete
11292          * Fires if the request was successfully completed.
11293          * @param {Connection} conn This Connection object.
11294          * @param {Object} response The XHR object containing the response data.
11295          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11296          * @param {Object} options The options config object passed to the {@link #request} method.
11297          */
11298         "requestcomplete" : true,
11299         /**
11300          * @event requestexception
11301          * Fires if an error HTTP status was returned from the server.
11302          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11303          * @param {Connection} conn This Connection object.
11304          * @param {Object} response The XHR object containing the response data.
11305          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11306          * @param {Object} options The options config object passed to the {@link #request} method.
11307          */
11308         "requestexception" : true
11309     });
11310     Roo.data.Connection.superclass.constructor.call(this);
11311 };
11312
11313 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11314     /**
11315      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11316      */
11317     /**
11318      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11319      * extra parameters to each request made by this object. (defaults to undefined)
11320      */
11321     /**
11322      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11323      *  to each request made by this object. (defaults to undefined)
11324      */
11325     /**
11326      * @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)
11327      */
11328     /**
11329      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11330      */
11331     timeout : 30000,
11332     /**
11333      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11334      * @type Boolean
11335      */
11336     autoAbort:false,
11337
11338     /**
11339      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11340      * @type Boolean
11341      */
11342     disableCaching: true,
11343
11344     /**
11345      * Sends an HTTP request to a remote server.
11346      * @param {Object} options An object which may contain the following properties:<ul>
11347      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11348      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11349      * request, a url encoded string or a function to call to get either.</li>
11350      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11351      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11352      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11353      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11354      * <li>options {Object} The parameter to the request call.</li>
11355      * <li>success {Boolean} True if the request succeeded.</li>
11356      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11357      * </ul></li>
11358      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11359      * The callback is passed the following parameters:<ul>
11360      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11361      * <li>options {Object} The parameter to the request call.</li>
11362      * </ul></li>
11363      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11364      * The callback is passed the following parameters:<ul>
11365      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11366      * <li>options {Object} The parameter to the request call.</li>
11367      * </ul></li>
11368      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11369      * for the callback function. Defaults to the browser window.</li>
11370      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11371      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11372      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11373      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11374      * params for the post data. Any params will be appended to the URL.</li>
11375      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11376      * </ul>
11377      * @return {Number} transactionId
11378      */
11379     request : function(o){
11380         if(this.fireEvent("beforerequest", this, o) !== false){
11381             var p = o.params;
11382
11383             if(typeof p == "function"){
11384                 p = p.call(o.scope||window, o);
11385             }
11386             if(typeof p == "object"){
11387                 p = Roo.urlEncode(o.params);
11388             }
11389             if(this.extraParams){
11390                 var extras = Roo.urlEncode(this.extraParams);
11391                 p = p ? (p + '&' + extras) : extras;
11392             }
11393
11394             var url = o.url || this.url;
11395             if(typeof url == 'function'){
11396                 url = url.call(o.scope||window, o);
11397             }
11398
11399             if(o.form){
11400                 var form = Roo.getDom(o.form);
11401                 url = url || form.action;
11402
11403                 var enctype = form.getAttribute("enctype");
11404                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11405                     return this.doFormUpload(o, p, url);
11406                 }
11407                 var f = Roo.lib.Ajax.serializeForm(form);
11408                 p = p ? (p + '&' + f) : f;
11409             }
11410
11411             var hs = o.headers;
11412             if(this.defaultHeaders){
11413                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11414                 if(!o.headers){
11415                     o.headers = hs;
11416                 }
11417             }
11418
11419             var cb = {
11420                 success: this.handleResponse,
11421                 failure: this.handleFailure,
11422                 scope: this,
11423                 argument: {options: o},
11424                 timeout : o.timeout || this.timeout
11425             };
11426
11427             var method = o.method||this.method||(p ? "POST" : "GET");
11428
11429             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11430                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11431             }
11432
11433             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11434                 if(o.autoAbort){
11435                     this.abort();
11436                 }
11437             }else if(this.autoAbort !== false){
11438                 this.abort();
11439             }
11440
11441             if((method == 'GET' && p) || o.xmlData){
11442                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11443                 p = '';
11444             }
11445             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11446             return this.transId;
11447         }else{
11448             Roo.callback(o.callback, o.scope, [o, null, null]);
11449             return null;
11450         }
11451     },
11452
11453     /**
11454      * Determine whether this object has a request outstanding.
11455      * @param {Number} transactionId (Optional) defaults to the last transaction
11456      * @return {Boolean} True if there is an outstanding request.
11457      */
11458     isLoading : function(transId){
11459         if(transId){
11460             return Roo.lib.Ajax.isCallInProgress(transId);
11461         }else{
11462             return this.transId ? true : false;
11463         }
11464     },
11465
11466     /**
11467      * Aborts any outstanding request.
11468      * @param {Number} transactionId (Optional) defaults to the last transaction
11469      */
11470     abort : function(transId){
11471         if(transId || this.isLoading()){
11472             Roo.lib.Ajax.abort(transId || this.transId);
11473         }
11474     },
11475
11476     // private
11477     handleResponse : function(response){
11478         this.transId = false;
11479         var options = response.argument.options;
11480         response.argument = options ? options.argument : null;
11481         this.fireEvent("requestcomplete", this, response, options);
11482         Roo.callback(options.success, options.scope, [response, options]);
11483         Roo.callback(options.callback, options.scope, [options, true, response]);
11484     },
11485
11486     // private
11487     handleFailure : function(response, e){
11488         this.transId = false;
11489         var options = response.argument.options;
11490         response.argument = options ? options.argument : null;
11491         this.fireEvent("requestexception", this, response, options, e);
11492         Roo.callback(options.failure, options.scope, [response, options]);
11493         Roo.callback(options.callback, options.scope, [options, false, response]);
11494     },
11495
11496     // private
11497     doFormUpload : function(o, ps, url){
11498         var id = Roo.id();
11499         var frame = document.createElement('iframe');
11500         frame.id = id;
11501         frame.name = id;
11502         frame.className = 'x-hidden';
11503         if(Roo.isIE){
11504             frame.src = Roo.SSL_SECURE_URL;
11505         }
11506         document.body.appendChild(frame);
11507
11508         if(Roo.isIE){
11509            document.frames[id].name = id;
11510         }
11511
11512         var form = Roo.getDom(o.form);
11513         form.target = id;
11514         form.method = 'POST';
11515         form.enctype = form.encoding = 'multipart/form-data';
11516         if(url){
11517             form.action = url;
11518         }
11519
11520         var hiddens, hd;
11521         if(ps){ // add dynamic params
11522             hiddens = [];
11523             ps = Roo.urlDecode(ps, false);
11524             for(var k in ps){
11525                 if(ps.hasOwnProperty(k)){
11526                     hd = document.createElement('input');
11527                     hd.type = 'hidden';
11528                     hd.name = k;
11529                     hd.value = ps[k];
11530                     form.appendChild(hd);
11531                     hiddens.push(hd);
11532                 }
11533             }
11534         }
11535
11536         function cb(){
11537             var r = {  // bogus response object
11538                 responseText : '',
11539                 responseXML : null
11540             };
11541
11542             r.argument = o ? o.argument : null;
11543
11544             try { //
11545                 var doc;
11546                 if(Roo.isIE){
11547                     doc = frame.contentWindow.document;
11548                 }else {
11549                     doc = (frame.contentDocument || window.frames[id].document);
11550                 }
11551                 if(doc && doc.body){
11552                     r.responseText = doc.body.innerHTML;
11553                 }
11554                 if(doc && doc.XMLDocument){
11555                     r.responseXML = doc.XMLDocument;
11556                 }else {
11557                     r.responseXML = doc;
11558                 }
11559             }
11560             catch(e) {
11561                 // ignore
11562             }
11563
11564             Roo.EventManager.removeListener(frame, 'load', cb, this);
11565
11566             this.fireEvent("requestcomplete", this, r, o);
11567             Roo.callback(o.success, o.scope, [r, o]);
11568             Roo.callback(o.callback, o.scope, [o, true, r]);
11569
11570             setTimeout(function(){document.body.removeChild(frame);}, 100);
11571         }
11572
11573         Roo.EventManager.on(frame, 'load', cb, this);
11574         form.submit();
11575
11576         if(hiddens){ // remove dynamic params
11577             for(var i = 0, len = hiddens.length; i < len; i++){
11578                 form.removeChild(hiddens[i]);
11579             }
11580         }
11581     }
11582 });
11583 /*
11584  * Based on:
11585  * Ext JS Library 1.1.1
11586  * Copyright(c) 2006-2007, Ext JS, LLC.
11587  *
11588  * Originally Released Under LGPL - original licence link has changed is not relivant.
11589  *
11590  * Fork - LGPL
11591  * <script type="text/javascript">
11592  */
11593  
11594 /**
11595  * Global Ajax request class.
11596  * 
11597  * @class Roo.Ajax
11598  * @extends Roo.data.Connection
11599  * @static
11600  * 
11601  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11602  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11603  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11604  * @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)
11605  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11606  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11607  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11608  */
11609 Roo.Ajax = new Roo.data.Connection({
11610     // fix up the docs
11611     /**
11612      * @scope Roo.Ajax
11613      * @type {Boolear} 
11614      */
11615     autoAbort : false,
11616
11617     /**
11618      * Serialize the passed form into a url encoded string
11619      * @scope Roo.Ajax
11620      * @param {String/HTMLElement} form
11621      * @return {String}
11622      */
11623     serializeForm : function(form){
11624         return Roo.lib.Ajax.serializeForm(form);
11625     }
11626 });/*
11627  * Based on:
11628  * Ext JS Library 1.1.1
11629  * Copyright(c) 2006-2007, Ext JS, LLC.
11630  *
11631  * Originally Released Under LGPL - original licence link has changed is not relivant.
11632  *
11633  * Fork - LGPL
11634  * <script type="text/javascript">
11635  */
11636
11637  
11638 /**
11639  * @class Roo.UpdateManager
11640  * @extends Roo.util.Observable
11641  * Provides AJAX-style update for Element object.<br><br>
11642  * Usage:<br>
11643  * <pre><code>
11644  * // Get it from a Roo.Element object
11645  * var el = Roo.get("foo");
11646  * var mgr = el.getUpdateManager();
11647  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11648  * ...
11649  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11650  * <br>
11651  * // or directly (returns the same UpdateManager instance)
11652  * var mgr = new Roo.UpdateManager("myElementId");
11653  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11654  * mgr.on("update", myFcnNeedsToKnow);
11655  * <br>
11656    // short handed call directly from the element object
11657    Roo.get("foo").load({
11658         url: "bar.php",
11659         scripts:true,
11660         params: "for=bar",
11661         text: "Loading Foo..."
11662    });
11663  * </code></pre>
11664  * @constructor
11665  * Create new UpdateManager directly.
11666  * @param {String/HTMLElement/Roo.Element} el The element to update
11667  * @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).
11668  */
11669 Roo.UpdateManager = function(el, forceNew){
11670     el = Roo.get(el);
11671     if(!forceNew && el.updateManager){
11672         return el.updateManager;
11673     }
11674     /**
11675      * The Element object
11676      * @type Roo.Element
11677      */
11678     this.el = el;
11679     /**
11680      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11681      * @type String
11682      */
11683     this.defaultUrl = null;
11684
11685     this.addEvents({
11686         /**
11687          * @event beforeupdate
11688          * Fired before an update is made, return false from your handler and the update is cancelled.
11689          * @param {Roo.Element} el
11690          * @param {String/Object/Function} url
11691          * @param {String/Object} params
11692          */
11693         "beforeupdate": true,
11694         /**
11695          * @event update
11696          * Fired after successful update is made.
11697          * @param {Roo.Element} el
11698          * @param {Object} oResponseObject The response Object
11699          */
11700         "update": true,
11701         /**
11702          * @event failure
11703          * Fired on update failure.
11704          * @param {Roo.Element} el
11705          * @param {Object} oResponseObject The response Object
11706          */
11707         "failure": true
11708     });
11709     var d = Roo.UpdateManager.defaults;
11710     /**
11711      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11712      * @type String
11713      */
11714     this.sslBlankUrl = d.sslBlankUrl;
11715     /**
11716      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11717      * @type Boolean
11718      */
11719     this.disableCaching = d.disableCaching;
11720     /**
11721      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11722      * @type String
11723      */
11724     this.indicatorText = d.indicatorText;
11725     /**
11726      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11727      * @type String
11728      */
11729     this.showLoadIndicator = d.showLoadIndicator;
11730     /**
11731      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11732      * @type Number
11733      */
11734     this.timeout = d.timeout;
11735
11736     /**
11737      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11738      * @type Boolean
11739      */
11740     this.loadScripts = d.loadScripts;
11741
11742     /**
11743      * Transaction object of current executing transaction
11744      */
11745     this.transaction = null;
11746
11747     /**
11748      * @private
11749      */
11750     this.autoRefreshProcId = null;
11751     /**
11752      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11753      * @type Function
11754      */
11755     this.refreshDelegate = this.refresh.createDelegate(this);
11756     /**
11757      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11758      * @type Function
11759      */
11760     this.updateDelegate = this.update.createDelegate(this);
11761     /**
11762      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11763      * @type Function
11764      */
11765     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11766     /**
11767      * @private
11768      */
11769     this.successDelegate = this.processSuccess.createDelegate(this);
11770     /**
11771      * @private
11772      */
11773     this.failureDelegate = this.processFailure.createDelegate(this);
11774
11775     if(!this.renderer){
11776      /**
11777       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11778       */
11779     this.renderer = new Roo.UpdateManager.BasicRenderer();
11780     }
11781     
11782     Roo.UpdateManager.superclass.constructor.call(this);
11783 };
11784
11785 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11786     /**
11787      * Get the Element this UpdateManager is bound to
11788      * @return {Roo.Element} The element
11789      */
11790     getEl : function(){
11791         return this.el;
11792     },
11793     /**
11794      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11795      * @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:
11796 <pre><code>
11797 um.update({<br/>
11798     url: "your-url.php",<br/>
11799     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11800     callback: yourFunction,<br/>
11801     scope: yourObject, //(optional scope)  <br/>
11802     discardUrl: false, <br/>
11803     nocache: false,<br/>
11804     text: "Loading...",<br/>
11805     timeout: 30,<br/>
11806     scripts: false<br/>
11807 });
11808 </code></pre>
11809      * The only required property is url. The optional properties nocache, text and scripts
11810      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11811      * @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}
11812      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11813      * @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.
11814      */
11815     update : function(url, params, callback, discardUrl){
11816         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11817             var method = this.method,
11818                 cfg;
11819             if(typeof url == "object"){ // must be config object
11820                 cfg = url;
11821                 url = cfg.url;
11822                 params = params || cfg.params;
11823                 callback = callback || cfg.callback;
11824                 discardUrl = discardUrl || cfg.discardUrl;
11825                 if(callback && cfg.scope){
11826                     callback = callback.createDelegate(cfg.scope);
11827                 }
11828                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11829                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11830                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11831                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11832                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11833             }
11834             this.showLoading();
11835             if(!discardUrl){
11836                 this.defaultUrl = url;
11837             }
11838             if(typeof url == "function"){
11839                 url = url.call(this);
11840             }
11841
11842             method = method || (params ? "POST" : "GET");
11843             if(method == "GET"){
11844                 url = this.prepareUrl(url);
11845             }
11846
11847             var o = Roo.apply(cfg ||{}, {
11848                 url : url,
11849                 params: params,
11850                 success: this.successDelegate,
11851                 failure: this.failureDelegate,
11852                 callback: undefined,
11853                 timeout: (this.timeout*1000),
11854                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11855             });
11856             Roo.log("updated manager called with timeout of " + o.timeout);
11857             this.transaction = Roo.Ajax.request(o);
11858         }
11859     },
11860
11861     /**
11862      * 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.
11863      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11864      * @param {String/HTMLElement} form The form Id or form element
11865      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11866      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11867      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11868      */
11869     formUpdate : function(form, url, reset, callback){
11870         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11871             if(typeof url == "function"){
11872                 url = url.call(this);
11873             }
11874             form = Roo.getDom(form);
11875             this.transaction = Roo.Ajax.request({
11876                 form: form,
11877                 url:url,
11878                 success: this.successDelegate,
11879                 failure: this.failureDelegate,
11880                 timeout: (this.timeout*1000),
11881                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11882             });
11883             this.showLoading.defer(1, this);
11884         }
11885     },
11886
11887     /**
11888      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11889      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11890      */
11891     refresh : function(callback){
11892         if(this.defaultUrl == null){
11893             return;
11894         }
11895         this.update(this.defaultUrl, null, callback, true);
11896     },
11897
11898     /**
11899      * Set this element to auto refresh.
11900      * @param {Number} interval How often to update (in seconds).
11901      * @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)
11902      * @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}
11903      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11904      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11905      */
11906     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11907         if(refreshNow){
11908             this.update(url || this.defaultUrl, params, callback, true);
11909         }
11910         if(this.autoRefreshProcId){
11911             clearInterval(this.autoRefreshProcId);
11912         }
11913         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11914     },
11915
11916     /**
11917      * Stop auto refresh on this element.
11918      */
11919      stopAutoRefresh : function(){
11920         if(this.autoRefreshProcId){
11921             clearInterval(this.autoRefreshProcId);
11922             delete this.autoRefreshProcId;
11923         }
11924     },
11925
11926     isAutoRefreshing : function(){
11927        return this.autoRefreshProcId ? true : false;
11928     },
11929     /**
11930      * Called to update the element to "Loading" state. Override to perform custom action.
11931      */
11932     showLoading : function(){
11933         if(this.showLoadIndicator){
11934             this.el.update(this.indicatorText);
11935         }
11936     },
11937
11938     /**
11939      * Adds unique parameter to query string if disableCaching = true
11940      * @private
11941      */
11942     prepareUrl : function(url){
11943         if(this.disableCaching){
11944             var append = "_dc=" + (new Date().getTime());
11945             if(url.indexOf("?") !== -1){
11946                 url += "&" + append;
11947             }else{
11948                 url += "?" + append;
11949             }
11950         }
11951         return url;
11952     },
11953
11954     /**
11955      * @private
11956      */
11957     processSuccess : function(response){
11958         this.transaction = null;
11959         if(response.argument.form && response.argument.reset){
11960             try{ // put in try/catch since some older FF releases had problems with this
11961                 response.argument.form.reset();
11962             }catch(e){}
11963         }
11964         if(this.loadScripts){
11965             this.renderer.render(this.el, response, this,
11966                 this.updateComplete.createDelegate(this, [response]));
11967         }else{
11968             this.renderer.render(this.el, response, this);
11969             this.updateComplete(response);
11970         }
11971     },
11972
11973     updateComplete : function(response){
11974         this.fireEvent("update", this.el, response);
11975         if(typeof response.argument.callback == "function"){
11976             response.argument.callback(this.el, true, response);
11977         }
11978     },
11979
11980     /**
11981      * @private
11982      */
11983     processFailure : function(response){
11984         this.transaction = null;
11985         this.fireEvent("failure", this.el, response);
11986         if(typeof response.argument.callback == "function"){
11987             response.argument.callback(this.el, false, response);
11988         }
11989     },
11990
11991     /**
11992      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
11993      * @param {Object} renderer The object implementing the render() method
11994      */
11995     setRenderer : function(renderer){
11996         this.renderer = renderer;
11997     },
11998
11999     getRenderer : function(){
12000        return this.renderer;
12001     },
12002
12003     /**
12004      * Set the defaultUrl used for updates
12005      * @param {String/Function} defaultUrl The url or a function to call to get the url
12006      */
12007     setDefaultUrl : function(defaultUrl){
12008         this.defaultUrl = defaultUrl;
12009     },
12010
12011     /**
12012      * Aborts the executing transaction
12013      */
12014     abort : function(){
12015         if(this.transaction){
12016             Roo.Ajax.abort(this.transaction);
12017         }
12018     },
12019
12020     /**
12021      * Returns true if an update is in progress
12022      * @return {Boolean}
12023      */
12024     isUpdating : function(){
12025         if(this.transaction){
12026             return Roo.Ajax.isLoading(this.transaction);
12027         }
12028         return false;
12029     }
12030 });
12031
12032 /**
12033  * @class Roo.UpdateManager.defaults
12034  * @static (not really - but it helps the doc tool)
12035  * The defaults collection enables customizing the default properties of UpdateManager
12036  */
12037    Roo.UpdateManager.defaults = {
12038        /**
12039          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12040          * @type Number
12041          */
12042          timeout : 30,
12043
12044          /**
12045          * True to process scripts by default (Defaults to false).
12046          * @type Boolean
12047          */
12048         loadScripts : false,
12049
12050         /**
12051         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12052         * @type String
12053         */
12054         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12055         /**
12056          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12057          * @type Boolean
12058          */
12059         disableCaching : false,
12060         /**
12061          * Whether to show indicatorText when loading (Defaults to true).
12062          * @type Boolean
12063          */
12064         showLoadIndicator : true,
12065         /**
12066          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12067          * @type String
12068          */
12069         indicatorText : '<div class="loading-indicator">Loading...</div>'
12070    };
12071
12072 /**
12073  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12074  *Usage:
12075  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12076  * @param {String/HTMLElement/Roo.Element} el The element to update
12077  * @param {String} url The url
12078  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12079  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12080  * @static
12081  * @deprecated
12082  * @member Roo.UpdateManager
12083  */
12084 Roo.UpdateManager.updateElement = function(el, url, params, options){
12085     var um = Roo.get(el, true).getUpdateManager();
12086     Roo.apply(um, options);
12087     um.update(url, params, options ? options.callback : null);
12088 };
12089 // alias for backwards compat
12090 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12091 /**
12092  * @class Roo.UpdateManager.BasicRenderer
12093  * Default Content renderer. Updates the elements innerHTML with the responseText.
12094  */
12095 Roo.UpdateManager.BasicRenderer = function(){};
12096
12097 Roo.UpdateManager.BasicRenderer.prototype = {
12098     /**
12099      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12100      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12101      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12102      * @param {Roo.Element} el The element being rendered
12103      * @param {Object} response The YUI Connect response object
12104      * @param {UpdateManager} updateManager The calling update manager
12105      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12106      */
12107      render : function(el, response, updateManager, callback){
12108         el.update(response.responseText, updateManager.loadScripts, callback);
12109     }
12110 };
12111 /*
12112  * Based on:
12113  * Roo JS
12114  * (c)) Alan Knowles
12115  * Licence : LGPL
12116  */
12117
12118
12119 /**
12120  * @class Roo.DomTemplate
12121  * @extends Roo.Template
12122  * An effort at a dom based template engine..
12123  *
12124  * Similar to XTemplate, except it uses dom parsing to create the template..
12125  *
12126  * Supported features:
12127  *
12128  *  Tags:
12129
12130 <pre><code>
12131       {a_variable} - output encoded.
12132       {a_variable.format:("Y-m-d")} - call a method on the variable
12133       {a_variable:raw} - unencoded output
12134       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12135       {a_variable:this.method_on_template(...)} - call a method on the template object.
12136  
12137 </code></pre>
12138  *  The tpl tag:
12139 <pre><code>
12140         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12141         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12142         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12143         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12144   
12145 </code></pre>
12146  *      
12147  */
12148 Roo.DomTemplate = function()
12149 {
12150      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12151      if (this.html) {
12152         this.compile();
12153      }
12154 };
12155
12156
12157 Roo.extend(Roo.DomTemplate, Roo.Template, {
12158     /**
12159      * id counter for sub templates.
12160      */
12161     id : 0,
12162     /**
12163      * flag to indicate if dom parser is inside a pre,
12164      * it will strip whitespace if not.
12165      */
12166     inPre : false,
12167     
12168     /**
12169      * The various sub templates
12170      */
12171     tpls : false,
12172     
12173     
12174     
12175     /**
12176      *
12177      * basic tag replacing syntax
12178      * WORD:WORD()
12179      *
12180      * // you can fake an object call by doing this
12181      *  x.t:(test,tesT) 
12182      * 
12183      */
12184     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12185     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12186     
12187     iterChild : function (node, method) {
12188         
12189         var oldPre = this.inPre;
12190         if (node.tagName == 'PRE') {
12191             this.inPre = true;
12192         }
12193         for( var i = 0; i < node.childNodes.length; i++) {
12194             method.call(this, node.childNodes[i]);
12195         }
12196         this.inPre = oldPre;
12197     },
12198     
12199     
12200     
12201     /**
12202      * compile the template
12203      *
12204      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12205      *
12206      */
12207     compile: function()
12208     {
12209         var s = this.html;
12210         
12211         // covert the html into DOM...
12212         var doc = false;
12213         var div =false;
12214         try {
12215             doc = document.implementation.createHTMLDocument("");
12216             doc.documentElement.innerHTML =   this.html  ;
12217             div = doc.documentElement;
12218         } catch (e) {
12219             // old IE... - nasty -- it causes all sorts of issues.. with
12220             // images getting pulled from server..
12221             div = document.createElement('div');
12222             div.innerHTML = this.html;
12223         }
12224         //doc.documentElement.innerHTML = htmlBody
12225          
12226         
12227         
12228         this.tpls = [];
12229         var _t = this;
12230         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12231         
12232         var tpls = this.tpls;
12233         
12234         // create a top level template from the snippet..
12235         
12236         //Roo.log(div.innerHTML);
12237         
12238         var tpl = {
12239             uid : 'master',
12240             id : this.id++,
12241             attr : false,
12242             value : false,
12243             body : div.innerHTML,
12244             
12245             forCall : false,
12246             execCall : false,
12247             dom : div,
12248             isTop : true
12249             
12250         };
12251         tpls.unshift(tpl);
12252         
12253         
12254         // compile them...
12255         this.tpls = [];
12256         Roo.each(tpls, function(tp){
12257             this.compileTpl(tp);
12258             this.tpls[tp.id] = tp;
12259         }, this);
12260         
12261         this.master = tpls[0];
12262         return this;
12263         
12264         
12265     },
12266     
12267     compileNode : function(node, istop) {
12268         // test for
12269         //Roo.log(node);
12270         
12271         
12272         // skip anything not a tag..
12273         if (node.nodeType != 1) {
12274             if (node.nodeType == 3 && !this.inPre) {
12275                 // reduce white space..
12276                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12277                 
12278             }
12279             return;
12280         }
12281         
12282         var tpl = {
12283             uid : false,
12284             id : false,
12285             attr : false,
12286             value : false,
12287             body : '',
12288             
12289             forCall : false,
12290             execCall : false,
12291             dom : false,
12292             isTop : istop
12293             
12294             
12295         };
12296         
12297         
12298         switch(true) {
12299             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12300             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12301             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12302             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12303             // no default..
12304         }
12305         
12306         
12307         if (!tpl.attr) {
12308             // just itterate children..
12309             this.iterChild(node,this.compileNode);
12310             return;
12311         }
12312         tpl.uid = this.id++;
12313         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12314         node.removeAttribute('roo-'+ tpl.attr);
12315         if (tpl.attr != 'name') {
12316             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12317             node.parentNode.replaceChild(placeholder,  node);
12318         } else {
12319             
12320             var placeholder =  document.createElement('span');
12321             placeholder.className = 'roo-tpl-' + tpl.value;
12322             node.parentNode.replaceChild(placeholder,  node);
12323         }
12324         
12325         // parent now sees '{domtplXXXX}
12326         this.iterChild(node,this.compileNode);
12327         
12328         // we should now have node body...
12329         var div = document.createElement('div');
12330         div.appendChild(node);
12331         tpl.dom = node;
12332         // this has the unfortunate side effect of converting tagged attributes
12333         // eg. href="{...}" into %7C...%7D
12334         // this has been fixed by searching for those combo's although it's a bit hacky..
12335         
12336         
12337         tpl.body = div.innerHTML;
12338         
12339         
12340          
12341         tpl.id = tpl.uid;
12342         switch(tpl.attr) {
12343             case 'for' :
12344                 switch (tpl.value) {
12345                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12346                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12347                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12348                 }
12349                 break;
12350             
12351             case 'exec':
12352                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12353                 break;
12354             
12355             case 'if':     
12356                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12357                 break;
12358             
12359             case 'name':
12360                 tpl.id  = tpl.value; // replace non characters???
12361                 break;
12362             
12363         }
12364         
12365         
12366         this.tpls.push(tpl);
12367         
12368         
12369         
12370     },
12371     
12372     
12373     
12374     
12375     /**
12376      * Compile a segment of the template into a 'sub-template'
12377      *
12378      * 
12379      * 
12380      *
12381      */
12382     compileTpl : function(tpl)
12383     {
12384         var fm = Roo.util.Format;
12385         var useF = this.disableFormats !== true;
12386         
12387         var sep = Roo.isGecko ? "+\n" : ",\n";
12388         
12389         var undef = function(str) {
12390             Roo.debug && Roo.log("Property not found :"  + str);
12391             return '';
12392         };
12393           
12394         //Roo.log(tpl.body);
12395         
12396         
12397         
12398         var fn = function(m, lbrace, name, format, args)
12399         {
12400             //Roo.log("ARGS");
12401             //Roo.log(arguments);
12402             args = args ? args.replace(/\\'/g,"'") : args;
12403             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12404             if (typeof(format) == 'undefined') {
12405                 format =  'htmlEncode'; 
12406             }
12407             if (format == 'raw' ) {
12408                 format = false;
12409             }
12410             
12411             if(name.substr(0, 6) == 'domtpl'){
12412                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12413             }
12414             
12415             // build an array of options to determine if value is undefined..
12416             
12417             // basically get 'xxxx.yyyy' then do
12418             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12419             //    (function () { Roo.log("Property not found"); return ''; })() :
12420             //    ......
12421             
12422             var udef_ar = [];
12423             var lookfor = '';
12424             Roo.each(name.split('.'), function(st) {
12425                 lookfor += (lookfor.length ? '.': '') + st;
12426                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12427             });
12428             
12429             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12430             
12431             
12432             if(format && useF){
12433                 
12434                 args = args ? ',' + args : "";
12435                  
12436                 if(format.substr(0, 5) != "this."){
12437                     format = "fm." + format + '(';
12438                 }else{
12439                     format = 'this.call("'+ format.substr(5) + '", ';
12440                     args = ", values";
12441                 }
12442                 
12443                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12444             }
12445              
12446             if (args && args.length) {
12447                 // called with xxyx.yuu:(test,test)
12448                 // change to ()
12449                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12450             }
12451             // raw.. - :raw modifier..
12452             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12453             
12454         };
12455         var body;
12456         // branched to use + in gecko and [].join() in others
12457         if(Roo.isGecko){
12458             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12459                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12460                     "';};};";
12461         }else{
12462             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12463             body.push(tpl.body.replace(/(\r\n|\n)/g,
12464                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12465             body.push("'].join('');};};");
12466             body = body.join('');
12467         }
12468         
12469         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12470        
12471         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12472         eval(body);
12473         
12474         return this;
12475     },
12476      
12477     /**
12478      * same as applyTemplate, except it's done to one of the subTemplates
12479      * when using named templates, you can do:
12480      *
12481      * var str = pl.applySubTemplate('your-name', values);
12482      *
12483      * 
12484      * @param {Number} id of the template
12485      * @param {Object} values to apply to template
12486      * @param {Object} parent (normaly the instance of this object)
12487      */
12488     applySubTemplate : function(id, values, parent)
12489     {
12490         
12491         
12492         var t = this.tpls[id];
12493         
12494         
12495         try { 
12496             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12497                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12498                 return '';
12499             }
12500         } catch(e) {
12501             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12502             Roo.log(values);
12503           
12504             return '';
12505         }
12506         try { 
12507             
12508             if(t.execCall && t.execCall.call(this, values, parent)){
12509                 return '';
12510             }
12511         } catch(e) {
12512             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12513             Roo.log(values);
12514             return '';
12515         }
12516         
12517         try {
12518             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12519             parent = t.target ? values : parent;
12520             if(t.forCall && vs instanceof Array){
12521                 var buf = [];
12522                 for(var i = 0, len = vs.length; i < len; i++){
12523                     try {
12524                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12525                     } catch (e) {
12526                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12527                         Roo.log(e.body);
12528                         //Roo.log(t.compiled);
12529                         Roo.log(vs[i]);
12530                     }   
12531                 }
12532                 return buf.join('');
12533             }
12534         } catch (e) {
12535             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12536             Roo.log(values);
12537             return '';
12538         }
12539         try {
12540             return t.compiled.call(this, vs, parent);
12541         } catch (e) {
12542             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12543             Roo.log(e.body);
12544             //Roo.log(t.compiled);
12545             Roo.log(values);
12546             return '';
12547         }
12548     },
12549
12550    
12551
12552     applyTemplate : function(values){
12553         return this.master.compiled.call(this, values, {});
12554         //var s = this.subs;
12555     },
12556
12557     apply : function(){
12558         return this.applyTemplate.apply(this, arguments);
12559     }
12560
12561  });
12562
12563 Roo.DomTemplate.from = function(el){
12564     el = Roo.getDom(el);
12565     return new Roo.Domtemplate(el.value || el.innerHTML);
12566 };/*
12567  * Based on:
12568  * Ext JS Library 1.1.1
12569  * Copyright(c) 2006-2007, Ext JS, LLC.
12570  *
12571  * Originally Released Under LGPL - original licence link has changed is not relivant.
12572  *
12573  * Fork - LGPL
12574  * <script type="text/javascript">
12575  */
12576
12577 /**
12578  * @class Roo.util.DelayedTask
12579  * Provides a convenient method of performing setTimeout where a new
12580  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12581  * You can use this class to buffer
12582  * the keypress events for a certain number of milliseconds, and perform only if they stop
12583  * for that amount of time.
12584  * @constructor The parameters to this constructor serve as defaults and are not required.
12585  * @param {Function} fn (optional) The default function to timeout
12586  * @param {Object} scope (optional) The default scope of that timeout
12587  * @param {Array} args (optional) The default Array of arguments
12588  */
12589 Roo.util.DelayedTask = function(fn, scope, args){
12590     var id = null, d, t;
12591
12592     var call = function(){
12593         var now = new Date().getTime();
12594         if(now - t >= d){
12595             clearInterval(id);
12596             id = null;
12597             fn.apply(scope, args || []);
12598         }
12599     };
12600     /**
12601      * Cancels any pending timeout and queues a new one
12602      * @param {Number} delay The milliseconds to delay
12603      * @param {Function} newFn (optional) Overrides function passed to constructor
12604      * @param {Object} newScope (optional) Overrides scope passed to constructor
12605      * @param {Array} newArgs (optional) Overrides args passed to constructor
12606      */
12607     this.delay = function(delay, newFn, newScope, newArgs){
12608         if(id && delay != d){
12609             this.cancel();
12610         }
12611         d = delay;
12612         t = new Date().getTime();
12613         fn = newFn || fn;
12614         scope = newScope || scope;
12615         args = newArgs || args;
12616         if(!id){
12617             id = setInterval(call, d);
12618         }
12619     };
12620
12621     /**
12622      * Cancel the last queued timeout
12623      */
12624     this.cancel = function(){
12625         if(id){
12626             clearInterval(id);
12627             id = null;
12628         }
12629     };
12630 };/*
12631  * Based on:
12632  * Ext JS Library 1.1.1
12633  * Copyright(c) 2006-2007, Ext JS, LLC.
12634  *
12635  * Originally Released Under LGPL - original licence link has changed is not relivant.
12636  *
12637  * Fork - LGPL
12638  * <script type="text/javascript">
12639  */
12640  
12641  
12642 Roo.util.TaskRunner = function(interval){
12643     interval = interval || 10;
12644     var tasks = [], removeQueue = [];
12645     var id = 0;
12646     var running = false;
12647
12648     var stopThread = function(){
12649         running = false;
12650         clearInterval(id);
12651         id = 0;
12652     };
12653
12654     var startThread = function(){
12655         if(!running){
12656             running = true;
12657             id = setInterval(runTasks, interval);
12658         }
12659     };
12660
12661     var removeTask = function(task){
12662         removeQueue.push(task);
12663         if(task.onStop){
12664             task.onStop();
12665         }
12666     };
12667
12668     var runTasks = function(){
12669         if(removeQueue.length > 0){
12670             for(var i = 0, len = removeQueue.length; i < len; i++){
12671                 tasks.remove(removeQueue[i]);
12672             }
12673             removeQueue = [];
12674             if(tasks.length < 1){
12675                 stopThread();
12676                 return;
12677             }
12678         }
12679         var now = new Date().getTime();
12680         for(var i = 0, len = tasks.length; i < len; ++i){
12681             var t = tasks[i];
12682             var itime = now - t.taskRunTime;
12683             if(t.interval <= itime){
12684                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12685                 t.taskRunTime = now;
12686                 if(rt === false || t.taskRunCount === t.repeat){
12687                     removeTask(t);
12688                     return;
12689                 }
12690             }
12691             if(t.duration && t.duration <= (now - t.taskStartTime)){
12692                 removeTask(t);
12693             }
12694         }
12695     };
12696
12697     /**
12698      * Queues a new task.
12699      * @param {Object} task
12700      */
12701     this.start = function(task){
12702         tasks.push(task);
12703         task.taskStartTime = new Date().getTime();
12704         task.taskRunTime = 0;
12705         task.taskRunCount = 0;
12706         startThread();
12707         return task;
12708     };
12709
12710     this.stop = function(task){
12711         removeTask(task);
12712         return task;
12713     };
12714
12715     this.stopAll = function(){
12716         stopThread();
12717         for(var i = 0, len = tasks.length; i < len; i++){
12718             if(tasks[i].onStop){
12719                 tasks[i].onStop();
12720             }
12721         }
12722         tasks = [];
12723         removeQueue = [];
12724     };
12725 };
12726
12727 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12728  * Based on:
12729  * Ext JS Library 1.1.1
12730  * Copyright(c) 2006-2007, Ext JS, LLC.
12731  *
12732  * Originally Released Under LGPL - original licence link has changed is not relivant.
12733  *
12734  * Fork - LGPL
12735  * <script type="text/javascript">
12736  */
12737
12738  
12739 /**
12740  * @class Roo.util.MixedCollection
12741  * @extends Roo.util.Observable
12742  * A Collection class that maintains both numeric indexes and keys and exposes events.
12743  * @constructor
12744  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12745  * collection (defaults to false)
12746  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12747  * and return the key value for that item.  This is used when available to look up the key on items that
12748  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12749  * equivalent to providing an implementation for the {@link #getKey} method.
12750  */
12751 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12752     this.items = [];
12753     this.map = {};
12754     this.keys = [];
12755     this.length = 0;
12756     this.addEvents({
12757         /**
12758          * @event clear
12759          * Fires when the collection is cleared.
12760          */
12761         "clear" : true,
12762         /**
12763          * @event add
12764          * Fires when an item is added to the collection.
12765          * @param {Number} index The index at which the item was added.
12766          * @param {Object} o The item added.
12767          * @param {String} key The key associated with the added item.
12768          */
12769         "add" : true,
12770         /**
12771          * @event replace
12772          * Fires when an item is replaced in the collection.
12773          * @param {String} key he key associated with the new added.
12774          * @param {Object} old The item being replaced.
12775          * @param {Object} new The new item.
12776          */
12777         "replace" : true,
12778         /**
12779          * @event remove
12780          * Fires when an item is removed from the collection.
12781          * @param {Object} o The item being removed.
12782          * @param {String} key (optional) The key associated with the removed item.
12783          */
12784         "remove" : true,
12785         "sort" : true
12786     });
12787     this.allowFunctions = allowFunctions === true;
12788     if(keyFn){
12789         this.getKey = keyFn;
12790     }
12791     Roo.util.MixedCollection.superclass.constructor.call(this);
12792 };
12793
12794 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12795     allowFunctions : false,
12796     
12797 /**
12798  * Adds an item to the collection.
12799  * @param {String} key The key to associate with the item
12800  * @param {Object} o The item to add.
12801  * @return {Object} The item added.
12802  */
12803     add : function(key, o){
12804         if(arguments.length == 1){
12805             o = arguments[0];
12806             key = this.getKey(o);
12807         }
12808         if(typeof key == "undefined" || key === null){
12809             this.length++;
12810             this.items.push(o);
12811             this.keys.push(null);
12812         }else{
12813             var old = this.map[key];
12814             if(old){
12815                 return this.replace(key, o);
12816             }
12817             this.length++;
12818             this.items.push(o);
12819             this.map[key] = o;
12820             this.keys.push(key);
12821         }
12822         this.fireEvent("add", this.length-1, o, key);
12823         return o;
12824     },
12825        
12826 /**
12827   * MixedCollection has a generic way to fetch keys if you implement getKey.
12828 <pre><code>
12829 // normal way
12830 var mc = new Roo.util.MixedCollection();
12831 mc.add(someEl.dom.id, someEl);
12832 mc.add(otherEl.dom.id, otherEl);
12833 //and so on
12834
12835 // using getKey
12836 var mc = new Roo.util.MixedCollection();
12837 mc.getKey = function(el){
12838    return el.dom.id;
12839 };
12840 mc.add(someEl);
12841 mc.add(otherEl);
12842
12843 // or via the constructor
12844 var mc = new Roo.util.MixedCollection(false, function(el){
12845    return el.dom.id;
12846 });
12847 mc.add(someEl);
12848 mc.add(otherEl);
12849 </code></pre>
12850  * @param o {Object} The item for which to find the key.
12851  * @return {Object} The key for the passed item.
12852  */
12853     getKey : function(o){
12854          return o.id; 
12855     },
12856    
12857 /**
12858  * Replaces an item in the collection.
12859  * @param {String} key The key associated with the item to replace, or the item to replace.
12860  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12861  * @return {Object}  The new item.
12862  */
12863     replace : function(key, o){
12864         if(arguments.length == 1){
12865             o = arguments[0];
12866             key = this.getKey(o);
12867         }
12868         var old = this.item(key);
12869         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12870              return this.add(key, o);
12871         }
12872         var index = this.indexOfKey(key);
12873         this.items[index] = o;
12874         this.map[key] = o;
12875         this.fireEvent("replace", key, old, o);
12876         return o;
12877     },
12878    
12879 /**
12880  * Adds all elements of an Array or an Object to the collection.
12881  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12882  * an Array of values, each of which are added to the collection.
12883  */
12884     addAll : function(objs){
12885         if(arguments.length > 1 || objs instanceof Array){
12886             var args = arguments.length > 1 ? arguments : objs;
12887             for(var i = 0, len = args.length; i < len; i++){
12888                 this.add(args[i]);
12889             }
12890         }else{
12891             for(var key in objs){
12892                 if(this.allowFunctions || typeof objs[key] != "function"){
12893                     this.add(key, objs[key]);
12894                 }
12895             }
12896         }
12897     },
12898    
12899 /**
12900  * Executes the specified function once for every item in the collection, passing each
12901  * item as the first and only parameter. returning false from the function will stop the iteration.
12902  * @param {Function} fn The function to execute for each item.
12903  * @param {Object} scope (optional) The scope in which to execute the function.
12904  */
12905     each : function(fn, scope){
12906         var items = [].concat(this.items); // each safe for removal
12907         for(var i = 0, len = items.length; i < len; i++){
12908             if(fn.call(scope || items[i], items[i], i, len) === false){
12909                 break;
12910             }
12911         }
12912     },
12913    
12914 /**
12915  * Executes the specified function once for every key in the collection, passing each
12916  * key, and its associated item as the first two parameters.
12917  * @param {Function} fn The function to execute for each item.
12918  * @param {Object} scope (optional) The scope in which to execute the function.
12919  */
12920     eachKey : function(fn, scope){
12921         for(var i = 0, len = this.keys.length; i < len; i++){
12922             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12923         }
12924     },
12925    
12926 /**
12927  * Returns the first item in the collection which elicits a true return value from the
12928  * passed selection function.
12929  * @param {Function} fn The selection function to execute for each item.
12930  * @param {Object} scope (optional) The scope in which to execute the function.
12931  * @return {Object} The first item in the collection which returned true from the selection function.
12932  */
12933     find : function(fn, scope){
12934         for(var i = 0, len = this.items.length; i < len; i++){
12935             if(fn.call(scope || window, this.items[i], this.keys[i])){
12936                 return this.items[i];
12937             }
12938         }
12939         return null;
12940     },
12941    
12942 /**
12943  * Inserts an item at the specified index in the collection.
12944  * @param {Number} index The index to insert the item at.
12945  * @param {String} key The key to associate with the new item, or the item itself.
12946  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12947  * @return {Object} The item inserted.
12948  */
12949     insert : function(index, key, o){
12950         if(arguments.length == 2){
12951             o = arguments[1];
12952             key = this.getKey(o);
12953         }
12954         if(index >= this.length){
12955             return this.add(key, o);
12956         }
12957         this.length++;
12958         this.items.splice(index, 0, o);
12959         if(typeof key != "undefined" && key != null){
12960             this.map[key] = o;
12961         }
12962         this.keys.splice(index, 0, key);
12963         this.fireEvent("add", index, o, key);
12964         return o;
12965     },
12966    
12967 /**
12968  * Removed an item from the collection.
12969  * @param {Object} o The item to remove.
12970  * @return {Object} The item removed.
12971  */
12972     remove : function(o){
12973         return this.removeAt(this.indexOf(o));
12974     },
12975    
12976 /**
12977  * Remove an item from a specified index in the collection.
12978  * @param {Number} index The index within the collection of the item to remove.
12979  */
12980     removeAt : function(index){
12981         if(index < this.length && index >= 0){
12982             this.length--;
12983             var o = this.items[index];
12984             this.items.splice(index, 1);
12985             var key = this.keys[index];
12986             if(typeof key != "undefined"){
12987                 delete this.map[key];
12988             }
12989             this.keys.splice(index, 1);
12990             this.fireEvent("remove", o, key);
12991         }
12992     },
12993    
12994 /**
12995  * Removed an item associated with the passed key fom the collection.
12996  * @param {String} key The key of the item to remove.
12997  */
12998     removeKey : function(key){
12999         return this.removeAt(this.indexOfKey(key));
13000     },
13001    
13002 /**
13003  * Returns the number of items in the collection.
13004  * @return {Number} the number of items in the collection.
13005  */
13006     getCount : function(){
13007         return this.length; 
13008     },
13009    
13010 /**
13011  * Returns index within the collection of the passed Object.
13012  * @param {Object} o The item to find the index of.
13013  * @return {Number} index of the item.
13014  */
13015     indexOf : function(o){
13016         if(!this.items.indexOf){
13017             for(var i = 0, len = this.items.length; i < len; i++){
13018                 if(this.items[i] == o) return i;
13019             }
13020             return -1;
13021         }else{
13022             return this.items.indexOf(o);
13023         }
13024     },
13025    
13026 /**
13027  * Returns index within the collection of the passed key.
13028  * @param {String} key The key to find the index of.
13029  * @return {Number} index of the key.
13030  */
13031     indexOfKey : function(key){
13032         if(!this.keys.indexOf){
13033             for(var i = 0, len = this.keys.length; i < len; i++){
13034                 if(this.keys[i] == key) return i;
13035             }
13036             return -1;
13037         }else{
13038             return this.keys.indexOf(key);
13039         }
13040     },
13041    
13042 /**
13043  * Returns the item associated with the passed key OR index. Key has priority over index.
13044  * @param {String/Number} key The key or index of the item.
13045  * @return {Object} The item associated with the passed key.
13046  */
13047     item : function(key){
13048         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13049         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13050     },
13051     
13052 /**
13053  * Returns the item at the specified index.
13054  * @param {Number} index The index of the item.
13055  * @return {Object}
13056  */
13057     itemAt : function(index){
13058         return this.items[index];
13059     },
13060     
13061 /**
13062  * Returns the item associated with the passed key.
13063  * @param {String/Number} key The key of the item.
13064  * @return {Object} The item associated with the passed key.
13065  */
13066     key : function(key){
13067         return this.map[key];
13068     },
13069    
13070 /**
13071  * Returns true if the collection contains the passed Object as an item.
13072  * @param {Object} o  The Object to look for in the collection.
13073  * @return {Boolean} True if the collection contains the Object as an item.
13074  */
13075     contains : function(o){
13076         return this.indexOf(o) != -1;
13077     },
13078    
13079 /**
13080  * Returns true if the collection contains the passed Object as a key.
13081  * @param {String} key The key to look for in the collection.
13082  * @return {Boolean} True if the collection contains the Object as a key.
13083  */
13084     containsKey : function(key){
13085         return typeof this.map[key] != "undefined";
13086     },
13087    
13088 /**
13089  * Removes all items from the collection.
13090  */
13091     clear : function(){
13092         this.length = 0;
13093         this.items = [];
13094         this.keys = [];
13095         this.map = {};
13096         this.fireEvent("clear");
13097     },
13098    
13099 /**
13100  * Returns the first item in the collection.
13101  * @return {Object} the first item in the collection..
13102  */
13103     first : function(){
13104         return this.items[0]; 
13105     },
13106    
13107 /**
13108  * Returns the last item in the collection.
13109  * @return {Object} the last item in the collection..
13110  */
13111     last : function(){
13112         return this.items[this.length-1];   
13113     },
13114     
13115     _sort : function(property, dir, fn){
13116         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13117         fn = fn || function(a, b){
13118             return a-b;
13119         };
13120         var c = [], k = this.keys, items = this.items;
13121         for(var i = 0, len = items.length; i < len; i++){
13122             c[c.length] = {key: k[i], value: items[i], index: i};
13123         }
13124         c.sort(function(a, b){
13125             var v = fn(a[property], b[property]) * dsc;
13126             if(v == 0){
13127                 v = (a.index < b.index ? -1 : 1);
13128             }
13129             return v;
13130         });
13131         for(var i = 0, len = c.length; i < len; i++){
13132             items[i] = c[i].value;
13133             k[i] = c[i].key;
13134         }
13135         this.fireEvent("sort", this);
13136     },
13137     
13138     /**
13139      * Sorts this collection with the passed comparison function
13140      * @param {String} direction (optional) "ASC" or "DESC"
13141      * @param {Function} fn (optional) comparison function
13142      */
13143     sort : function(dir, fn){
13144         this._sort("value", dir, fn);
13145     },
13146     
13147     /**
13148      * Sorts this collection by keys
13149      * @param {String} direction (optional) "ASC" or "DESC"
13150      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13151      */
13152     keySort : function(dir, fn){
13153         this._sort("key", dir, fn || function(a, b){
13154             return String(a).toUpperCase()-String(b).toUpperCase();
13155         });
13156     },
13157     
13158     /**
13159      * Returns a range of items in this collection
13160      * @param {Number} startIndex (optional) defaults to 0
13161      * @param {Number} endIndex (optional) default to the last item
13162      * @return {Array} An array of items
13163      */
13164     getRange : function(start, end){
13165         var items = this.items;
13166         if(items.length < 1){
13167             return [];
13168         }
13169         start = start || 0;
13170         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13171         var r = [];
13172         if(start <= end){
13173             for(var i = start; i <= end; i++) {
13174                     r[r.length] = items[i];
13175             }
13176         }else{
13177             for(var i = start; i >= end; i--) {
13178                     r[r.length] = items[i];
13179             }
13180         }
13181         return r;
13182     },
13183         
13184     /**
13185      * Filter the <i>objects</i> in this collection by a specific property. 
13186      * Returns a new collection that has been filtered.
13187      * @param {String} property A property on your objects
13188      * @param {String/RegExp} value Either string that the property values 
13189      * should start with or a RegExp to test against the property
13190      * @return {MixedCollection} The new filtered collection
13191      */
13192     filter : function(property, value){
13193         if(!value.exec){ // not a regex
13194             value = String(value);
13195             if(value.length == 0){
13196                 return this.clone();
13197             }
13198             value = new RegExp("^" + Roo.escapeRe(value), "i");
13199         }
13200         return this.filterBy(function(o){
13201             return o && value.test(o[property]);
13202         });
13203         },
13204     
13205     /**
13206      * Filter by a function. * Returns a new collection that has been filtered.
13207      * The passed function will be called with each 
13208      * object in the collection. If the function returns true, the value is included 
13209      * otherwise it is filtered.
13210      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13211      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13212      * @return {MixedCollection} The new filtered collection
13213      */
13214     filterBy : function(fn, scope){
13215         var r = new Roo.util.MixedCollection();
13216         r.getKey = this.getKey;
13217         var k = this.keys, it = this.items;
13218         for(var i = 0, len = it.length; i < len; i++){
13219             if(fn.call(scope||this, it[i], k[i])){
13220                                 r.add(k[i], it[i]);
13221                         }
13222         }
13223         return r;
13224     },
13225     
13226     /**
13227      * Creates a duplicate of this collection
13228      * @return {MixedCollection}
13229      */
13230     clone : function(){
13231         var r = new Roo.util.MixedCollection();
13232         var k = this.keys, it = this.items;
13233         for(var i = 0, len = it.length; i < len; i++){
13234             r.add(k[i], it[i]);
13235         }
13236         r.getKey = this.getKey;
13237         return r;
13238     }
13239 });
13240 /**
13241  * Returns the item associated with the passed key or index.
13242  * @method
13243  * @param {String/Number} key The key or index of the item.
13244  * @return {Object} The item associated with the passed key.
13245  */
13246 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13247  * Based on:
13248  * Ext JS Library 1.1.1
13249  * Copyright(c) 2006-2007, Ext JS, LLC.
13250  *
13251  * Originally Released Under LGPL - original licence link has changed is not relivant.
13252  *
13253  * Fork - LGPL
13254  * <script type="text/javascript">
13255  */
13256 /**
13257  * @class Roo.util.JSON
13258  * Modified version of Douglas Crockford"s json.js that doesn"t
13259  * mess with the Object prototype 
13260  * http://www.json.org/js.html
13261  * @singleton
13262  */
13263 Roo.util.JSON = new (function(){
13264     var useHasOwn = {}.hasOwnProperty ? true : false;
13265     
13266     // crashes Safari in some instances
13267     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13268     
13269     var pad = function(n) {
13270         return n < 10 ? "0" + n : n;
13271     };
13272     
13273     var m = {
13274         "\b": '\\b',
13275         "\t": '\\t',
13276         "\n": '\\n',
13277         "\f": '\\f',
13278         "\r": '\\r',
13279         '"' : '\\"',
13280         "\\": '\\\\'
13281     };
13282
13283     var encodeString = function(s){
13284         if (/["\\\x00-\x1f]/.test(s)) {
13285             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13286                 var c = m[b];
13287                 if(c){
13288                     return c;
13289                 }
13290                 c = b.charCodeAt();
13291                 return "\\u00" +
13292                     Math.floor(c / 16).toString(16) +
13293                     (c % 16).toString(16);
13294             }) + '"';
13295         }
13296         return '"' + s + '"';
13297     };
13298     
13299     var encodeArray = function(o){
13300         var a = ["["], b, i, l = o.length, v;
13301             for (i = 0; i < l; i += 1) {
13302                 v = o[i];
13303                 switch (typeof v) {
13304                     case "undefined":
13305                     case "function":
13306                     case "unknown":
13307                         break;
13308                     default:
13309                         if (b) {
13310                             a.push(',');
13311                         }
13312                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13313                         b = true;
13314                 }
13315             }
13316             a.push("]");
13317             return a.join("");
13318     };
13319     
13320     var encodeDate = function(o){
13321         return '"' + o.getFullYear() + "-" +
13322                 pad(o.getMonth() + 1) + "-" +
13323                 pad(o.getDate()) + "T" +
13324                 pad(o.getHours()) + ":" +
13325                 pad(o.getMinutes()) + ":" +
13326                 pad(o.getSeconds()) + '"';
13327     };
13328     
13329     /**
13330      * Encodes an Object, Array or other value
13331      * @param {Mixed} o The variable to encode
13332      * @return {String} The JSON string
13333      */
13334     this.encode = function(o)
13335     {
13336         // should this be extended to fully wrap stringify..
13337         
13338         if(typeof o == "undefined" || o === null){
13339             return "null";
13340         }else if(o instanceof Array){
13341             return encodeArray(o);
13342         }else if(o instanceof Date){
13343             return encodeDate(o);
13344         }else if(typeof o == "string"){
13345             return encodeString(o);
13346         }else if(typeof o == "number"){
13347             return isFinite(o) ? String(o) : "null";
13348         }else if(typeof o == "boolean"){
13349             return String(o);
13350         }else {
13351             var a = ["{"], b, i, v;
13352             for (i in o) {
13353                 if(!useHasOwn || o.hasOwnProperty(i)) {
13354                     v = o[i];
13355                     switch (typeof v) {
13356                     case "undefined":
13357                     case "function":
13358                     case "unknown":
13359                         break;
13360                     default:
13361                         if(b){
13362                             a.push(',');
13363                         }
13364                         a.push(this.encode(i), ":",
13365                                 v === null ? "null" : this.encode(v));
13366                         b = true;
13367                     }
13368                 }
13369             }
13370             a.push("}");
13371             return a.join("");
13372         }
13373     };
13374     
13375     /**
13376      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13377      * @param {String} json The JSON string
13378      * @return {Object} The resulting object
13379      */
13380     this.decode = function(json){
13381         
13382         return  /** eval:var:json */ eval("(" + json + ')');
13383     };
13384 })();
13385 /** 
13386  * Shorthand for {@link Roo.util.JSON#encode}
13387  * @member Roo encode 
13388  * @method */
13389 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13390 /** 
13391  * Shorthand for {@link Roo.util.JSON#decode}
13392  * @member Roo decode 
13393  * @method */
13394 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13395 /*
13396  * Based on:
13397  * Ext JS Library 1.1.1
13398  * Copyright(c) 2006-2007, Ext JS, LLC.
13399  *
13400  * Originally Released Under LGPL - original licence link has changed is not relivant.
13401  *
13402  * Fork - LGPL
13403  * <script type="text/javascript">
13404  */
13405  
13406 /**
13407  * @class Roo.util.Format
13408  * Reusable data formatting functions
13409  * @singleton
13410  */
13411 Roo.util.Format = function(){
13412     var trimRe = /^\s+|\s+$/g;
13413     return {
13414         /**
13415          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13416          * @param {String} value The string to truncate
13417          * @param {Number} length The maximum length to allow before truncating
13418          * @return {String} The converted text
13419          */
13420         ellipsis : function(value, len){
13421             if(value && value.length > len){
13422                 return value.substr(0, len-3)+"...";
13423             }
13424             return value;
13425         },
13426
13427         /**
13428          * Checks a reference and converts it to empty string if it is undefined
13429          * @param {Mixed} value Reference to check
13430          * @return {Mixed} Empty string if converted, otherwise the original value
13431          */
13432         undef : function(value){
13433             return typeof value != "undefined" ? value : "";
13434         },
13435
13436         /**
13437          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13438          * @param {String} value The string to encode
13439          * @return {String} The encoded text
13440          */
13441         htmlEncode : function(value){
13442             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13443         },
13444
13445         /**
13446          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13447          * @param {String} value The string to decode
13448          * @return {String} The decoded text
13449          */
13450         htmlDecode : function(value){
13451             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13452         },
13453
13454         /**
13455          * Trims any whitespace from either side of a string
13456          * @param {String} value The text to trim
13457          * @return {String} The trimmed text
13458          */
13459         trim : function(value){
13460             return String(value).replace(trimRe, "");
13461         },
13462
13463         /**
13464          * Returns a substring from within an original string
13465          * @param {String} value The original text
13466          * @param {Number} start The start index of the substring
13467          * @param {Number} length The length of the substring
13468          * @return {String} The substring
13469          */
13470         substr : function(value, start, length){
13471             return String(value).substr(start, length);
13472         },
13473
13474         /**
13475          * Converts a string to all lower case letters
13476          * @param {String} value The text to convert
13477          * @return {String} The converted text
13478          */
13479         lowercase : function(value){
13480             return String(value).toLowerCase();
13481         },
13482
13483         /**
13484          * Converts a string to all upper case letters
13485          * @param {String} value The text to convert
13486          * @return {String} The converted text
13487          */
13488         uppercase : function(value){
13489             return String(value).toUpperCase();
13490         },
13491
13492         /**
13493          * Converts the first character only of a string to upper case
13494          * @param {String} value The text to convert
13495          * @return {String} The converted text
13496          */
13497         capitalize : function(value){
13498             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13499         },
13500
13501         // private
13502         call : function(value, fn){
13503             if(arguments.length > 2){
13504                 var args = Array.prototype.slice.call(arguments, 2);
13505                 args.unshift(value);
13506                  
13507                 return /** eval:var:value */  eval(fn).apply(window, args);
13508             }else{
13509                 /** eval:var:value */
13510                 return /** eval:var:value */ eval(fn).call(window, value);
13511             }
13512         },
13513
13514        
13515         /**
13516          * safer version of Math.toFixed..??/
13517          * @param {Number/String} value The numeric value to format
13518          * @param {Number/String} value Decimal places 
13519          * @return {String} The formatted currency string
13520          */
13521         toFixed : function(v, n)
13522         {
13523             // why not use to fixed - precision is buggered???
13524             if (!n) {
13525                 return Math.round(v-0);
13526             }
13527             var fact = Math.pow(10,n+1);
13528             v = (Math.round((v-0)*fact))/fact;
13529             var z = (''+fact).substring(2);
13530             if (v == Math.floor(v)) {
13531                 return Math.floor(v) + '.' + z;
13532             }
13533             
13534             // now just padd decimals..
13535             var ps = String(v).split('.');
13536             var fd = (ps[1] + z);
13537             var r = fd.substring(0,n); 
13538             var rm = fd.substring(n); 
13539             if (rm < 5) {
13540                 return ps[0] + '.' + r;
13541             }
13542             r*=1; // turn it into a number;
13543             r++;
13544             if (String(r).length != n) {
13545                 ps[0]*=1;
13546                 ps[0]++;
13547                 r = String(r).substring(1); // chop the end off.
13548             }
13549             
13550             return ps[0] + '.' + r;
13551              
13552         },
13553         
13554         /**
13555          * Format a number as US currency
13556          * @param {Number/String} value The numeric value to format
13557          * @return {String} The formatted currency string
13558          */
13559         usMoney : function(v){
13560             return '$' + Roo.util.Format.number(v);
13561         },
13562         
13563         /**
13564          * Format a number
13565          * eventually this should probably emulate php's number_format
13566          * @param {Number/String} value The numeric value to format
13567          * @param {Number} decimals number of decimal places
13568          * @return {String} The formatted currency string
13569          */
13570         number : function(v,decimals)
13571         {
13572             // multiply and round.
13573             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13574             var mul = Math.pow(10, decimals);
13575             var zero = String(mul).substring(1);
13576             v = (Math.round((v-0)*mul))/mul;
13577             
13578             // if it's '0' number.. then
13579             
13580             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13581             v = String(v);
13582             var ps = v.split('.');
13583             var whole = ps[0];
13584             
13585             
13586             var r = /(\d+)(\d{3})/;
13587             // add comma's
13588             while (r.test(whole)) {
13589                 whole = whole.replace(r, '$1' + ',' + '$2');
13590             }
13591             
13592             
13593             var sub = ps[1] ?
13594                     // has decimals..
13595                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13596                     // does not have decimals
13597                     (decimals ? ('.' + zero) : '');
13598             
13599             
13600             return whole + sub ;
13601         },
13602         
13603         /**
13604          * Parse a value into a formatted date using the specified format pattern.
13605          * @param {Mixed} value The value to format
13606          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13607          * @return {String} The formatted date string
13608          */
13609         date : function(v, format){
13610             if(!v){
13611                 return "";
13612             }
13613             if(!(v instanceof Date)){
13614                 v = new Date(Date.parse(v));
13615             }
13616             return v.dateFormat(format || Roo.util.Format.defaults.date);
13617         },
13618
13619         /**
13620          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13621          * @param {String} format Any valid date format string
13622          * @return {Function} The date formatting function
13623          */
13624         dateRenderer : function(format){
13625             return function(v){
13626                 return Roo.util.Format.date(v, format);  
13627             };
13628         },
13629
13630         // private
13631         stripTagsRE : /<\/?[^>]+>/gi,
13632         
13633         /**
13634          * Strips all HTML tags
13635          * @param {Mixed} value The text from which to strip tags
13636          * @return {String} The stripped text
13637          */
13638         stripTags : function(v){
13639             return !v ? v : String(v).replace(this.stripTagsRE, "");
13640         }
13641     };
13642 }();
13643 Roo.util.Format.defaults = {
13644     date : 'd/M/Y'
13645 };/*
13646  * Based on:
13647  * Ext JS Library 1.1.1
13648  * Copyright(c) 2006-2007, Ext JS, LLC.
13649  *
13650  * Originally Released Under LGPL - original licence link has changed is not relivant.
13651  *
13652  * Fork - LGPL
13653  * <script type="text/javascript">
13654  */
13655
13656
13657  
13658
13659 /**
13660  * @class Roo.MasterTemplate
13661  * @extends Roo.Template
13662  * Provides a template that can have child templates. The syntax is:
13663 <pre><code>
13664 var t = new Roo.MasterTemplate(
13665         '&lt;select name="{name}"&gt;',
13666                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13667         '&lt;/select&gt;'
13668 );
13669 t.add('options', {value: 'foo', text: 'bar'});
13670 // or you can add multiple child elements in one shot
13671 t.addAll('options', [
13672     {value: 'foo', text: 'bar'},
13673     {value: 'foo2', text: 'bar2'},
13674     {value: 'foo3', text: 'bar3'}
13675 ]);
13676 // then append, applying the master template values
13677 t.append('my-form', {name: 'my-select'});
13678 </code></pre>
13679 * A name attribute for the child template is not required if you have only one child
13680 * template or you want to refer to them by index.
13681  */
13682 Roo.MasterTemplate = function(){
13683     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13684     this.originalHtml = this.html;
13685     var st = {};
13686     var m, re = this.subTemplateRe;
13687     re.lastIndex = 0;
13688     var subIndex = 0;
13689     while(m = re.exec(this.html)){
13690         var name = m[1], content = m[2];
13691         st[subIndex] = {
13692             name: name,
13693             index: subIndex,
13694             buffer: [],
13695             tpl : new Roo.Template(content)
13696         };
13697         if(name){
13698             st[name] = st[subIndex];
13699         }
13700         st[subIndex].tpl.compile();
13701         st[subIndex].tpl.call = this.call.createDelegate(this);
13702         subIndex++;
13703     }
13704     this.subCount = subIndex;
13705     this.subs = st;
13706 };
13707 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13708     /**
13709     * The regular expression used to match sub templates
13710     * @type RegExp
13711     * @property
13712     */
13713     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13714
13715     /**
13716      * Applies the passed values to a child template.
13717      * @param {String/Number} name (optional) The name or index of the child template
13718      * @param {Array/Object} values The values to be applied to the template
13719      * @return {MasterTemplate} this
13720      */
13721      add : function(name, values){
13722         if(arguments.length == 1){
13723             values = arguments[0];
13724             name = 0;
13725         }
13726         var s = this.subs[name];
13727         s.buffer[s.buffer.length] = s.tpl.apply(values);
13728         return this;
13729     },
13730
13731     /**
13732      * Applies all the passed values to a child template.
13733      * @param {String/Number} name (optional) The name or index of the child template
13734      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13735      * @param {Boolean} reset (optional) True to reset the template first
13736      * @return {MasterTemplate} this
13737      */
13738     fill : function(name, values, reset){
13739         var a = arguments;
13740         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13741             values = a[0];
13742             name = 0;
13743             reset = a[1];
13744         }
13745         if(reset){
13746             this.reset();
13747         }
13748         for(var i = 0, len = values.length; i < len; i++){
13749             this.add(name, values[i]);
13750         }
13751         return this;
13752     },
13753
13754     /**
13755      * Resets the template for reuse
13756      * @return {MasterTemplate} this
13757      */
13758      reset : function(){
13759         var s = this.subs;
13760         for(var i = 0; i < this.subCount; i++){
13761             s[i].buffer = [];
13762         }
13763         return this;
13764     },
13765
13766     applyTemplate : function(values){
13767         var s = this.subs;
13768         var replaceIndex = -1;
13769         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13770             return s[++replaceIndex].buffer.join("");
13771         });
13772         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13773     },
13774
13775     apply : function(){
13776         return this.applyTemplate.apply(this, arguments);
13777     },
13778
13779     compile : function(){return this;}
13780 });
13781
13782 /**
13783  * Alias for fill().
13784  * @method
13785  */
13786 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13787  /**
13788  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13789  * var tpl = Roo.MasterTemplate.from('element-id');
13790  * @param {String/HTMLElement} el
13791  * @param {Object} config
13792  * @static
13793  */
13794 Roo.MasterTemplate.from = function(el, config){
13795     el = Roo.getDom(el);
13796     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13797 };/*
13798  * Based on:
13799  * Ext JS Library 1.1.1
13800  * Copyright(c) 2006-2007, Ext JS, LLC.
13801  *
13802  * Originally Released Under LGPL - original licence link has changed is not relivant.
13803  *
13804  * Fork - LGPL
13805  * <script type="text/javascript">
13806  */
13807
13808  
13809 /**
13810  * @class Roo.util.CSS
13811  * Utility class for manipulating CSS rules
13812  * @singleton
13813  */
13814 Roo.util.CSS = function(){
13815         var rules = null;
13816         var doc = document;
13817
13818     var camelRe = /(-[a-z])/gi;
13819     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13820
13821    return {
13822    /**
13823     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13824     * tag and appended to the HEAD of the document.
13825     * @param {String|Object} cssText The text containing the css rules
13826     * @param {String} id An id to add to the stylesheet for later removal
13827     * @return {StyleSheet}
13828     */
13829     createStyleSheet : function(cssText, id){
13830         var ss;
13831         var head = doc.getElementsByTagName("head")[0];
13832         var nrules = doc.createElement("style");
13833         nrules.setAttribute("type", "text/css");
13834         if(id){
13835             nrules.setAttribute("id", id);
13836         }
13837         if (typeof(cssText) != 'string') {
13838             // support object maps..
13839             // not sure if this a good idea.. 
13840             // perhaps it should be merged with the general css handling
13841             // and handle js style props.
13842             var cssTextNew = [];
13843             for(var n in cssText) {
13844                 var citems = [];
13845                 for(var k in cssText[n]) {
13846                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13847                 }
13848                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13849                 
13850             }
13851             cssText = cssTextNew.join("\n");
13852             
13853         }
13854        
13855        
13856        if(Roo.isIE){
13857            head.appendChild(nrules);
13858            ss = nrules.styleSheet;
13859            ss.cssText = cssText;
13860        }else{
13861            try{
13862                 nrules.appendChild(doc.createTextNode(cssText));
13863            }catch(e){
13864                nrules.cssText = cssText; 
13865            }
13866            head.appendChild(nrules);
13867            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13868        }
13869        this.cacheStyleSheet(ss);
13870        return ss;
13871    },
13872
13873    /**
13874     * Removes a style or link tag by id
13875     * @param {String} id The id of the tag
13876     */
13877    removeStyleSheet : function(id){
13878        var existing = doc.getElementById(id);
13879        if(existing){
13880            existing.parentNode.removeChild(existing);
13881        }
13882    },
13883
13884    /**
13885     * Dynamically swaps an existing stylesheet reference for a new one
13886     * @param {String} id The id of an existing link tag to remove
13887     * @param {String} url The href of the new stylesheet to include
13888     */
13889    swapStyleSheet : function(id, url){
13890        this.removeStyleSheet(id);
13891        var ss = doc.createElement("link");
13892        ss.setAttribute("rel", "stylesheet");
13893        ss.setAttribute("type", "text/css");
13894        ss.setAttribute("id", id);
13895        ss.setAttribute("href", url);
13896        doc.getElementsByTagName("head")[0].appendChild(ss);
13897    },
13898    
13899    /**
13900     * Refresh the rule cache if you have dynamically added stylesheets
13901     * @return {Object} An object (hash) of rules indexed by selector
13902     */
13903    refreshCache : function(){
13904        return this.getRules(true);
13905    },
13906
13907    // private
13908    cacheStyleSheet : function(stylesheet){
13909        if(!rules){
13910            rules = {};
13911        }
13912        try{// try catch for cross domain access issue
13913            var ssRules = stylesheet.cssRules || stylesheet.rules;
13914            for(var j = ssRules.length-1; j >= 0; --j){
13915                rules[ssRules[j].selectorText] = ssRules[j];
13916            }
13917        }catch(e){}
13918    },
13919    
13920    /**
13921     * Gets all css rules for the document
13922     * @param {Boolean} refreshCache true to refresh the internal cache
13923     * @return {Object} An object (hash) of rules indexed by selector
13924     */
13925    getRules : function(refreshCache){
13926                 if(rules == null || refreshCache){
13927                         rules = {};
13928                         var ds = doc.styleSheets;
13929                         for(var i =0, len = ds.length; i < len; i++){
13930                             try{
13931                         this.cacheStyleSheet(ds[i]);
13932                     }catch(e){} 
13933                 }
13934                 }
13935                 return rules;
13936         },
13937         
13938         /**
13939     * Gets an an individual CSS rule by selector(s)
13940     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13941     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13942     * @return {CSSRule} The CSS rule or null if one is not found
13943     */
13944    getRule : function(selector, refreshCache){
13945                 var rs = this.getRules(refreshCache);
13946                 if(!(selector instanceof Array)){
13947                     return rs[selector];
13948                 }
13949                 for(var i = 0; i < selector.length; i++){
13950                         if(rs[selector[i]]){
13951                                 return rs[selector[i]];
13952                         }
13953                 }
13954                 return null;
13955         },
13956         
13957         
13958         /**
13959     * Updates a rule property
13960     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13961     * @param {String} property The css property
13962     * @param {String} value The new value for the property
13963     * @return {Boolean} true If a rule was found and updated
13964     */
13965    updateRule : function(selector, property, value){
13966                 if(!(selector instanceof Array)){
13967                         var rule = this.getRule(selector);
13968                         if(rule){
13969                                 rule.style[property.replace(camelRe, camelFn)] = value;
13970                                 return true;
13971                         }
13972                 }else{
13973                         for(var i = 0; i < selector.length; i++){
13974                                 if(this.updateRule(selector[i], property, value)){
13975                                         return true;
13976                                 }
13977                         }
13978                 }
13979                 return false;
13980         }
13981    };   
13982 }();/*
13983  * Based on:
13984  * Ext JS Library 1.1.1
13985  * Copyright(c) 2006-2007, Ext JS, LLC.
13986  *
13987  * Originally Released Under LGPL - original licence link has changed is not relivant.
13988  *
13989  * Fork - LGPL
13990  * <script type="text/javascript">
13991  */
13992
13993  
13994
13995 /**
13996  * @class Roo.util.ClickRepeater
13997  * @extends Roo.util.Observable
13998  * 
13999  * A wrapper class which can be applied to any element. Fires a "click" event while the
14000  * mouse is pressed. The interval between firings may be specified in the config but
14001  * defaults to 10 milliseconds.
14002  * 
14003  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14004  * 
14005  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14006  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14007  * Similar to an autorepeat key delay.
14008  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14009  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14010  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14011  *           "interval" and "delay" are ignored. "immediate" is honored.
14012  * @cfg {Boolean} preventDefault True to prevent the default click event
14013  * @cfg {Boolean} stopDefault True to stop the default click event
14014  * 
14015  * @history
14016  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14017  *     2007-02-02 jvs Renamed to ClickRepeater
14018  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14019  *
14020  *  @constructor
14021  * @param {String/HTMLElement/Element} el The element to listen on
14022  * @param {Object} config
14023  **/
14024 Roo.util.ClickRepeater = function(el, config)
14025 {
14026     this.el = Roo.get(el);
14027     this.el.unselectable();
14028
14029     Roo.apply(this, config);
14030
14031     this.addEvents({
14032     /**
14033      * @event mousedown
14034      * Fires when the mouse button is depressed.
14035      * @param {Roo.util.ClickRepeater} this
14036      */
14037         "mousedown" : true,
14038     /**
14039      * @event click
14040      * Fires on a specified interval during the time the element is pressed.
14041      * @param {Roo.util.ClickRepeater} this
14042      */
14043         "click" : true,
14044     /**
14045      * @event mouseup
14046      * Fires when the mouse key is released.
14047      * @param {Roo.util.ClickRepeater} this
14048      */
14049         "mouseup" : true
14050     });
14051
14052     this.el.on("mousedown", this.handleMouseDown, this);
14053     if(this.preventDefault || this.stopDefault){
14054         this.el.on("click", function(e){
14055             if(this.preventDefault){
14056                 e.preventDefault();
14057             }
14058             if(this.stopDefault){
14059                 e.stopEvent();
14060             }
14061         }, this);
14062     }
14063
14064     // allow inline handler
14065     if(this.handler){
14066         this.on("click", this.handler,  this.scope || this);
14067     }
14068
14069     Roo.util.ClickRepeater.superclass.constructor.call(this);
14070 };
14071
14072 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14073     interval : 20,
14074     delay: 250,
14075     preventDefault : true,
14076     stopDefault : false,
14077     timer : 0,
14078
14079     // private
14080     handleMouseDown : function(){
14081         clearTimeout(this.timer);
14082         this.el.blur();
14083         if(this.pressClass){
14084             this.el.addClass(this.pressClass);
14085         }
14086         this.mousedownTime = new Date();
14087
14088         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14089         this.el.on("mouseout", this.handleMouseOut, this);
14090
14091         this.fireEvent("mousedown", this);
14092         this.fireEvent("click", this);
14093         
14094         this.timer = this.click.defer(this.delay || this.interval, this);
14095     },
14096
14097     // private
14098     click : function(){
14099         this.fireEvent("click", this);
14100         this.timer = this.click.defer(this.getInterval(), this);
14101     },
14102
14103     // private
14104     getInterval: function(){
14105         if(!this.accelerate){
14106             return this.interval;
14107         }
14108         var pressTime = this.mousedownTime.getElapsed();
14109         if(pressTime < 500){
14110             return 400;
14111         }else if(pressTime < 1700){
14112             return 320;
14113         }else if(pressTime < 2600){
14114             return 250;
14115         }else if(pressTime < 3500){
14116             return 180;
14117         }else if(pressTime < 4400){
14118             return 140;
14119         }else if(pressTime < 5300){
14120             return 80;
14121         }else if(pressTime < 6200){
14122             return 50;
14123         }else{
14124             return 10;
14125         }
14126     },
14127
14128     // private
14129     handleMouseOut : function(){
14130         clearTimeout(this.timer);
14131         if(this.pressClass){
14132             this.el.removeClass(this.pressClass);
14133         }
14134         this.el.on("mouseover", this.handleMouseReturn, this);
14135     },
14136
14137     // private
14138     handleMouseReturn : function(){
14139         this.el.un("mouseover", this.handleMouseReturn);
14140         if(this.pressClass){
14141             this.el.addClass(this.pressClass);
14142         }
14143         this.click();
14144     },
14145
14146     // private
14147     handleMouseUp : function(){
14148         clearTimeout(this.timer);
14149         this.el.un("mouseover", this.handleMouseReturn);
14150         this.el.un("mouseout", this.handleMouseOut);
14151         Roo.get(document).un("mouseup", this.handleMouseUp);
14152         this.el.removeClass(this.pressClass);
14153         this.fireEvent("mouseup", this);
14154     }
14155 });/*
14156  * Based on:
14157  * Ext JS Library 1.1.1
14158  * Copyright(c) 2006-2007, Ext JS, LLC.
14159  *
14160  * Originally Released Under LGPL - original licence link has changed is not relivant.
14161  *
14162  * Fork - LGPL
14163  * <script type="text/javascript">
14164  */
14165
14166  
14167 /**
14168  * @class Roo.KeyNav
14169  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14170  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14171  * way to implement custom navigation schemes for any UI component.</p>
14172  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14173  * pageUp, pageDown, del, home, end.  Usage:</p>
14174  <pre><code>
14175 var nav = new Roo.KeyNav("my-element", {
14176     "left" : function(e){
14177         this.moveLeft(e.ctrlKey);
14178     },
14179     "right" : function(e){
14180         this.moveRight(e.ctrlKey);
14181     },
14182     "enter" : function(e){
14183         this.save();
14184     },
14185     scope : this
14186 });
14187 </code></pre>
14188  * @constructor
14189  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14190  * @param {Object} config The config
14191  */
14192 Roo.KeyNav = function(el, config){
14193     this.el = Roo.get(el);
14194     Roo.apply(this, config);
14195     if(!this.disabled){
14196         this.disabled = true;
14197         this.enable();
14198     }
14199 };
14200
14201 Roo.KeyNav.prototype = {
14202     /**
14203      * @cfg {Boolean} disabled
14204      * True to disable this KeyNav instance (defaults to false)
14205      */
14206     disabled : false,
14207     /**
14208      * @cfg {String} defaultEventAction
14209      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14210      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14211      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14212      */
14213     defaultEventAction: "stopEvent",
14214     /**
14215      * @cfg {Boolean} forceKeyDown
14216      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14217      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14218      * handle keydown instead of keypress.
14219      */
14220     forceKeyDown : false,
14221
14222     // private
14223     prepareEvent : function(e){
14224         var k = e.getKey();
14225         var h = this.keyToHandler[k];
14226         //if(h && this[h]){
14227         //    e.stopPropagation();
14228         //}
14229         if(Roo.isSafari && h && k >= 37 && k <= 40){
14230             e.stopEvent();
14231         }
14232     },
14233
14234     // private
14235     relay : function(e){
14236         var k = e.getKey();
14237         var h = this.keyToHandler[k];
14238         if(h && this[h]){
14239             if(this.doRelay(e, this[h], h) !== true){
14240                 e[this.defaultEventAction]();
14241             }
14242         }
14243     },
14244
14245     // private
14246     doRelay : function(e, h, hname){
14247         return h.call(this.scope || this, e);
14248     },
14249
14250     // possible handlers
14251     enter : false,
14252     left : false,
14253     right : false,
14254     up : false,
14255     down : false,
14256     tab : false,
14257     esc : false,
14258     pageUp : false,
14259     pageDown : false,
14260     del : false,
14261     home : false,
14262     end : false,
14263
14264     // quick lookup hash
14265     keyToHandler : {
14266         37 : "left",
14267         39 : "right",
14268         38 : "up",
14269         40 : "down",
14270         33 : "pageUp",
14271         34 : "pageDown",
14272         46 : "del",
14273         36 : "home",
14274         35 : "end",
14275         13 : "enter",
14276         27 : "esc",
14277         9  : "tab"
14278     },
14279
14280         /**
14281          * Enable this KeyNav
14282          */
14283         enable: function(){
14284                 if(this.disabled){
14285             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14286             // the EventObject will normalize Safari automatically
14287             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14288                 this.el.on("keydown", this.relay,  this);
14289             }else{
14290                 this.el.on("keydown", this.prepareEvent,  this);
14291                 this.el.on("keypress", this.relay,  this);
14292             }
14293                     this.disabled = false;
14294                 }
14295         },
14296
14297         /**
14298          * Disable this KeyNav
14299          */
14300         disable: function(){
14301                 if(!this.disabled){
14302                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14303                 this.el.un("keydown", this.relay);
14304             }else{
14305                 this.el.un("keydown", this.prepareEvent);
14306                 this.el.un("keypress", this.relay);
14307             }
14308                     this.disabled = true;
14309                 }
14310         }
14311 };/*
14312  * Based on:
14313  * Ext JS Library 1.1.1
14314  * Copyright(c) 2006-2007, Ext JS, LLC.
14315  *
14316  * Originally Released Under LGPL - original licence link has changed is not relivant.
14317  *
14318  * Fork - LGPL
14319  * <script type="text/javascript">
14320  */
14321
14322  
14323 /**
14324  * @class Roo.KeyMap
14325  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14326  * The constructor accepts the same config object as defined by {@link #addBinding}.
14327  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14328  * combination it will call the function with this signature (if the match is a multi-key
14329  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14330  * A KeyMap can also handle a string representation of keys.<br />
14331  * Usage:
14332  <pre><code>
14333 // map one key by key code
14334 var map = new Roo.KeyMap("my-element", {
14335     key: 13, // or Roo.EventObject.ENTER
14336     fn: myHandler,
14337     scope: myObject
14338 });
14339
14340 // map multiple keys to one action by string
14341 var map = new Roo.KeyMap("my-element", {
14342     key: "a\r\n\t",
14343     fn: myHandler,
14344     scope: myObject
14345 });
14346
14347 // map multiple keys to multiple actions by strings and array of codes
14348 var map = new Roo.KeyMap("my-element", [
14349     {
14350         key: [10,13],
14351         fn: function(){ alert("Return was pressed"); }
14352     }, {
14353         key: "abc",
14354         fn: function(){ alert('a, b or c was pressed'); }
14355     }, {
14356         key: "\t",
14357         ctrl:true,
14358         shift:true,
14359         fn: function(){ alert('Control + shift + tab was pressed.'); }
14360     }
14361 ]);
14362 </code></pre>
14363  * <b>Note: A KeyMap starts enabled</b>
14364  * @constructor
14365  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14366  * @param {Object} config The config (see {@link #addBinding})
14367  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14368  */
14369 Roo.KeyMap = function(el, config, eventName){
14370     this.el  = Roo.get(el);
14371     this.eventName = eventName || "keydown";
14372     this.bindings = [];
14373     if(config){
14374         this.addBinding(config);
14375     }
14376     this.enable();
14377 };
14378
14379 Roo.KeyMap.prototype = {
14380     /**
14381      * True to stop the event from bubbling and prevent the default browser action if the
14382      * key was handled by the KeyMap (defaults to false)
14383      * @type Boolean
14384      */
14385     stopEvent : false,
14386
14387     /**
14388      * Add a new binding to this KeyMap. The following config object properties are supported:
14389      * <pre>
14390 Property    Type             Description
14391 ----------  ---------------  ----------------------------------------------------------------------
14392 key         String/Array     A single keycode or an array of keycodes to handle
14393 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14394 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14395 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14396 fn          Function         The function to call when KeyMap finds the expected key combination
14397 scope       Object           The scope of the callback function
14398 </pre>
14399      *
14400      * Usage:
14401      * <pre><code>
14402 // Create a KeyMap
14403 var map = new Roo.KeyMap(document, {
14404     key: Roo.EventObject.ENTER,
14405     fn: handleKey,
14406     scope: this
14407 });
14408
14409 //Add a new binding to the existing KeyMap later
14410 map.addBinding({
14411     key: 'abc',
14412     shift: true,
14413     fn: handleKey,
14414     scope: this
14415 });
14416 </code></pre>
14417      * @param {Object/Array} config A single KeyMap config or an array of configs
14418      */
14419         addBinding : function(config){
14420         if(config instanceof Array){
14421             for(var i = 0, len = config.length; i < len; i++){
14422                 this.addBinding(config[i]);
14423             }
14424             return;
14425         }
14426         var keyCode = config.key,
14427             shift = config.shift, 
14428             ctrl = config.ctrl, 
14429             alt = config.alt,
14430             fn = config.fn,
14431             scope = config.scope;
14432         if(typeof keyCode == "string"){
14433             var ks = [];
14434             var keyString = keyCode.toUpperCase();
14435             for(var j = 0, len = keyString.length; j < len; j++){
14436                 ks.push(keyString.charCodeAt(j));
14437             }
14438             keyCode = ks;
14439         }
14440         var keyArray = keyCode instanceof Array;
14441         var handler = function(e){
14442             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14443                 var k = e.getKey();
14444                 if(keyArray){
14445                     for(var i = 0, len = keyCode.length; i < len; i++){
14446                         if(keyCode[i] == k){
14447                           if(this.stopEvent){
14448                               e.stopEvent();
14449                           }
14450                           fn.call(scope || window, k, e);
14451                           return;
14452                         }
14453                     }
14454                 }else{
14455                     if(k == keyCode){
14456                         if(this.stopEvent){
14457                            e.stopEvent();
14458                         }
14459                         fn.call(scope || window, k, e);
14460                     }
14461                 }
14462             }
14463         };
14464         this.bindings.push(handler);  
14465         },
14466
14467     /**
14468      * Shorthand for adding a single key listener
14469      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14470      * following options:
14471      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14472      * @param {Function} fn The function to call
14473      * @param {Object} scope (optional) The scope of the function
14474      */
14475     on : function(key, fn, scope){
14476         var keyCode, shift, ctrl, alt;
14477         if(typeof key == "object" && !(key instanceof Array)){
14478             keyCode = key.key;
14479             shift = key.shift;
14480             ctrl = key.ctrl;
14481             alt = key.alt;
14482         }else{
14483             keyCode = key;
14484         }
14485         this.addBinding({
14486             key: keyCode,
14487             shift: shift,
14488             ctrl: ctrl,
14489             alt: alt,
14490             fn: fn,
14491             scope: scope
14492         })
14493     },
14494
14495     // private
14496     handleKeyDown : function(e){
14497             if(this.enabled){ //just in case
14498             var b = this.bindings;
14499             for(var i = 0, len = b.length; i < len; i++){
14500                 b[i].call(this, e);
14501             }
14502             }
14503         },
14504         
14505         /**
14506          * Returns true if this KeyMap is enabled
14507          * @return {Boolean} 
14508          */
14509         isEnabled : function(){
14510             return this.enabled;  
14511         },
14512         
14513         /**
14514          * Enables this KeyMap
14515          */
14516         enable: function(){
14517                 if(!this.enabled){
14518                     this.el.on(this.eventName, this.handleKeyDown, this);
14519                     this.enabled = true;
14520                 }
14521         },
14522
14523         /**
14524          * Disable this KeyMap
14525          */
14526         disable: function(){
14527                 if(this.enabled){
14528                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14529                     this.enabled = false;
14530                 }
14531         }
14532 };/*
14533  * Based on:
14534  * Ext JS Library 1.1.1
14535  * Copyright(c) 2006-2007, Ext JS, LLC.
14536  *
14537  * Originally Released Under LGPL - original licence link has changed is not relivant.
14538  *
14539  * Fork - LGPL
14540  * <script type="text/javascript">
14541  */
14542
14543  
14544 /**
14545  * @class Roo.util.TextMetrics
14546  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14547  * wide, in pixels, a given block of text will be.
14548  * @singleton
14549  */
14550 Roo.util.TextMetrics = function(){
14551     var shared;
14552     return {
14553         /**
14554          * Measures the size of the specified text
14555          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14556          * that can affect the size of the rendered text
14557          * @param {String} text The text to measure
14558          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14559          * in order to accurately measure the text height
14560          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14561          */
14562         measure : function(el, text, fixedWidth){
14563             if(!shared){
14564                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14565             }
14566             shared.bind(el);
14567             shared.setFixedWidth(fixedWidth || 'auto');
14568             return shared.getSize(text);
14569         },
14570
14571         /**
14572          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14573          * the overhead of multiple calls to initialize the style properties on each measurement.
14574          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14575          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14576          * in order to accurately measure the text height
14577          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14578          */
14579         createInstance : function(el, fixedWidth){
14580             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14581         }
14582     };
14583 }();
14584
14585  
14586
14587 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14588     var ml = new Roo.Element(document.createElement('div'));
14589     document.body.appendChild(ml.dom);
14590     ml.position('absolute');
14591     ml.setLeftTop(-1000, -1000);
14592     ml.hide();
14593
14594     if(fixedWidth){
14595         ml.setWidth(fixedWidth);
14596     }
14597      
14598     var instance = {
14599         /**
14600          * Returns the size of the specified text based on the internal element's style and width properties
14601          * @memberOf Roo.util.TextMetrics.Instance#
14602          * @param {String} text The text to measure
14603          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14604          */
14605         getSize : function(text){
14606             ml.update(text);
14607             var s = ml.getSize();
14608             ml.update('');
14609             return s;
14610         },
14611
14612         /**
14613          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14614          * that can affect the size of the rendered text
14615          * @memberOf Roo.util.TextMetrics.Instance#
14616          * @param {String/HTMLElement} el The element, dom node or id
14617          */
14618         bind : function(el){
14619             ml.setStyle(
14620                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14621             );
14622         },
14623
14624         /**
14625          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14626          * to set a fixed width in order to accurately measure the text height.
14627          * @memberOf Roo.util.TextMetrics.Instance#
14628          * @param {Number} width The width to set on the element
14629          */
14630         setFixedWidth : function(width){
14631             ml.setWidth(width);
14632         },
14633
14634         /**
14635          * Returns the measured width of the specified text
14636          * @memberOf Roo.util.TextMetrics.Instance#
14637          * @param {String} text The text to measure
14638          * @return {Number} width The width in pixels
14639          */
14640         getWidth : function(text){
14641             ml.dom.style.width = 'auto';
14642             return this.getSize(text).width;
14643         },
14644
14645         /**
14646          * Returns the measured height of the specified text.  For multiline text, be sure to call
14647          * {@link #setFixedWidth} if necessary.
14648          * @memberOf Roo.util.TextMetrics.Instance#
14649          * @param {String} text The text to measure
14650          * @return {Number} height The height in pixels
14651          */
14652         getHeight : function(text){
14653             return this.getSize(text).height;
14654         }
14655     };
14656
14657     instance.bind(bindTo);
14658
14659     return instance;
14660 };
14661
14662 // backwards compat
14663 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14664  * Based on:
14665  * Ext JS Library 1.1.1
14666  * Copyright(c) 2006-2007, Ext JS, LLC.
14667  *
14668  * Originally Released Under LGPL - original licence link has changed is not relivant.
14669  *
14670  * Fork - LGPL
14671  * <script type="text/javascript">
14672  */
14673
14674 /**
14675  * @class Roo.state.Provider
14676  * Abstract base class for state provider implementations. This class provides methods
14677  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14678  * Provider interface.
14679  */
14680 Roo.state.Provider = function(){
14681     /**
14682      * @event statechange
14683      * Fires when a state change occurs.
14684      * @param {Provider} this This state provider
14685      * @param {String} key The state key which was changed
14686      * @param {String} value The encoded value for the state
14687      */
14688     this.addEvents({
14689         "statechange": true
14690     });
14691     this.state = {};
14692     Roo.state.Provider.superclass.constructor.call(this);
14693 };
14694 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14695     /**
14696      * Returns the current value for a key
14697      * @param {String} name The key name
14698      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14699      * @return {Mixed} The state data
14700      */
14701     get : function(name, defaultValue){
14702         return typeof this.state[name] == "undefined" ?
14703             defaultValue : this.state[name];
14704     },
14705     
14706     /**
14707      * Clears a value from the state
14708      * @param {String} name The key name
14709      */
14710     clear : function(name){
14711         delete this.state[name];
14712         this.fireEvent("statechange", this, name, null);
14713     },
14714     
14715     /**
14716      * Sets the value for a key
14717      * @param {String} name The key name
14718      * @param {Mixed} value The value to set
14719      */
14720     set : function(name, value){
14721         this.state[name] = value;
14722         this.fireEvent("statechange", this, name, value);
14723     },
14724     
14725     /**
14726      * Decodes a string previously encoded with {@link #encodeValue}.
14727      * @param {String} value The value to decode
14728      * @return {Mixed} The decoded value
14729      */
14730     decodeValue : function(cookie){
14731         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14732         var matches = re.exec(unescape(cookie));
14733         if(!matches || !matches[1]) return; // non state cookie
14734         var type = matches[1];
14735         var v = matches[2];
14736         switch(type){
14737             case "n":
14738                 return parseFloat(v);
14739             case "d":
14740                 return new Date(Date.parse(v));
14741             case "b":
14742                 return (v == "1");
14743             case "a":
14744                 var all = [];
14745                 var values = v.split("^");
14746                 for(var i = 0, len = values.length; i < len; i++){
14747                     all.push(this.decodeValue(values[i]));
14748                 }
14749                 return all;
14750            case "o":
14751                 var all = {};
14752                 var values = v.split("^");
14753                 for(var i = 0, len = values.length; i < len; i++){
14754                     var kv = values[i].split("=");
14755                     all[kv[0]] = this.decodeValue(kv[1]);
14756                 }
14757                 return all;
14758            default:
14759                 return v;
14760         }
14761     },
14762     
14763     /**
14764      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14765      * @param {Mixed} value The value to encode
14766      * @return {String} The encoded value
14767      */
14768     encodeValue : function(v){
14769         var enc;
14770         if(typeof v == "number"){
14771             enc = "n:" + v;
14772         }else if(typeof v == "boolean"){
14773             enc = "b:" + (v ? "1" : "0");
14774         }else if(v instanceof Date){
14775             enc = "d:" + v.toGMTString();
14776         }else if(v instanceof Array){
14777             var flat = "";
14778             for(var i = 0, len = v.length; i < len; i++){
14779                 flat += this.encodeValue(v[i]);
14780                 if(i != len-1) flat += "^";
14781             }
14782             enc = "a:" + flat;
14783         }else if(typeof v == "object"){
14784             var flat = "";
14785             for(var key in v){
14786                 if(typeof v[key] != "function"){
14787                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14788                 }
14789             }
14790             enc = "o:" + flat.substring(0, flat.length-1);
14791         }else{
14792             enc = "s:" + v;
14793         }
14794         return escape(enc);        
14795     }
14796 });
14797
14798 /*
14799  * Based on:
14800  * Ext JS Library 1.1.1
14801  * Copyright(c) 2006-2007, Ext JS, LLC.
14802  *
14803  * Originally Released Under LGPL - original licence link has changed is not relivant.
14804  *
14805  * Fork - LGPL
14806  * <script type="text/javascript">
14807  */
14808 /**
14809  * @class Roo.state.Manager
14810  * This is the global state manager. By default all components that are "state aware" check this class
14811  * for state information if you don't pass them a custom state provider. In order for this class
14812  * to be useful, it must be initialized with a provider when your application initializes.
14813  <pre><code>
14814 // in your initialization function
14815 init : function(){
14816    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14817    ...
14818    // supposed you have a {@link Roo.BorderLayout}
14819    var layout = new Roo.BorderLayout(...);
14820    layout.restoreState();
14821    // or a {Roo.BasicDialog}
14822    var dialog = new Roo.BasicDialog(...);
14823    dialog.restoreState();
14824  </code></pre>
14825  * @singleton
14826  */
14827 Roo.state.Manager = function(){
14828     var provider = new Roo.state.Provider();
14829     
14830     return {
14831         /**
14832          * Configures the default state provider for your application
14833          * @param {Provider} stateProvider The state provider to set
14834          */
14835         setProvider : function(stateProvider){
14836             provider = stateProvider;
14837         },
14838         
14839         /**
14840          * Returns the current value for a key
14841          * @param {String} name The key name
14842          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14843          * @return {Mixed} The state data
14844          */
14845         get : function(key, defaultValue){
14846             return provider.get(key, defaultValue);
14847         },
14848         
14849         /**
14850          * Sets the value for a key
14851          * @param {String} name The key name
14852          * @param {Mixed} value The state data
14853          */
14854          set : function(key, value){
14855             provider.set(key, value);
14856         },
14857         
14858         /**
14859          * Clears a value from the state
14860          * @param {String} name The key name
14861          */
14862         clear : function(key){
14863             provider.clear(key);
14864         },
14865         
14866         /**
14867          * Gets the currently configured state provider
14868          * @return {Provider} The state provider
14869          */
14870         getProvider : function(){
14871             return provider;
14872         }
14873     };
14874 }();
14875 /*
14876  * Based on:
14877  * Ext JS Library 1.1.1
14878  * Copyright(c) 2006-2007, Ext JS, LLC.
14879  *
14880  * Originally Released Under LGPL - original licence link has changed is not relivant.
14881  *
14882  * Fork - LGPL
14883  * <script type="text/javascript">
14884  */
14885 /**
14886  * @class Roo.state.CookieProvider
14887  * @extends Roo.state.Provider
14888  * The default Provider implementation which saves state via cookies.
14889  * <br />Usage:
14890  <pre><code>
14891    var cp = new Roo.state.CookieProvider({
14892        path: "/cgi-bin/",
14893        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14894        domain: "roojs.com"
14895    })
14896    Roo.state.Manager.setProvider(cp);
14897  </code></pre>
14898  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14899  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14900  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14901  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14902  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14903  * domain the page is running on including the 'www' like 'www.roojs.com')
14904  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14905  * @constructor
14906  * Create a new CookieProvider
14907  * @param {Object} config The configuration object
14908  */
14909 Roo.state.CookieProvider = function(config){
14910     Roo.state.CookieProvider.superclass.constructor.call(this);
14911     this.path = "/";
14912     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14913     this.domain = null;
14914     this.secure = false;
14915     Roo.apply(this, config);
14916     this.state = this.readCookies();
14917 };
14918
14919 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14920     // private
14921     set : function(name, value){
14922         if(typeof value == "undefined" || value === null){
14923             this.clear(name);
14924             return;
14925         }
14926         this.setCookie(name, value);
14927         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14928     },
14929
14930     // private
14931     clear : function(name){
14932         this.clearCookie(name);
14933         Roo.state.CookieProvider.superclass.clear.call(this, name);
14934     },
14935
14936     // private
14937     readCookies : function(){
14938         var cookies = {};
14939         var c = document.cookie + ";";
14940         var re = /\s?(.*?)=(.*?);/g;
14941         var matches;
14942         while((matches = re.exec(c)) != null){
14943             var name = matches[1];
14944             var value = matches[2];
14945             if(name && name.substring(0,3) == "ys-"){
14946                 cookies[name.substr(3)] = this.decodeValue(value);
14947             }
14948         }
14949         return cookies;
14950     },
14951
14952     // private
14953     setCookie : function(name, value){
14954         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14955            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14956            ((this.path == null) ? "" : ("; path=" + this.path)) +
14957            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14958            ((this.secure == true) ? "; secure" : "");
14959     },
14960
14961     // private
14962     clearCookie : function(name){
14963         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14964            ((this.path == null) ? "" : ("; path=" + this.path)) +
14965            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14966            ((this.secure == true) ? "; secure" : "");
14967     }
14968 });/*
14969  * Based on:
14970  * Ext JS Library 1.1.1
14971  * Copyright(c) 2006-2007, Ext JS, LLC.
14972  *
14973  * Originally Released Under LGPL - original licence link has changed is not relivant.
14974  *
14975  * Fork - LGPL
14976  * <script type="text/javascript">
14977  */
14978  
14979
14980 /**
14981  * @class Roo.ComponentMgr
14982  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14983  * @singleton
14984  */
14985 Roo.ComponentMgr = function(){
14986     var all = new Roo.util.MixedCollection();
14987
14988     return {
14989         /**
14990          * Registers a component.
14991          * @param {Roo.Component} c The component
14992          */
14993         register : function(c){
14994             all.add(c);
14995         },
14996
14997         /**
14998          * Unregisters a component.
14999          * @param {Roo.Component} c The component
15000          */
15001         unregister : function(c){
15002             all.remove(c);
15003         },
15004
15005         /**
15006          * Returns a component by id
15007          * @param {String} id The component id
15008          */
15009         get : function(id){
15010             return all.get(id);
15011         },
15012
15013         /**
15014          * Registers a function that will be called when a specified component is added to ComponentMgr
15015          * @param {String} id The component id
15016          * @param {Funtction} fn The callback function
15017          * @param {Object} scope The scope of the callback
15018          */
15019         onAvailable : function(id, fn, scope){
15020             all.on("add", function(index, o){
15021                 if(o.id == id){
15022                     fn.call(scope || o, o);
15023                     all.un("add", fn, scope);
15024                 }
15025             });
15026         }
15027     };
15028 }();/*
15029  * Based on:
15030  * Ext JS Library 1.1.1
15031  * Copyright(c) 2006-2007, Ext JS, LLC.
15032  *
15033  * Originally Released Under LGPL - original licence link has changed is not relivant.
15034  *
15035  * Fork - LGPL
15036  * <script type="text/javascript">
15037  */
15038  
15039 /**
15040  * @class Roo.Component
15041  * @extends Roo.util.Observable
15042  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15043  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15044  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15045  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15046  * All visual components (widgets) that require rendering into a layout should subclass Component.
15047  * @constructor
15048  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15049  * 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
15050  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15051  */
15052 Roo.Component = function(config){
15053     config = config || {};
15054     if(config.tagName || config.dom || typeof config == "string"){ // element object
15055         config = {el: config, id: config.id || config};
15056     }
15057     this.initialConfig = config;
15058
15059     Roo.apply(this, config);
15060     this.addEvents({
15061         /**
15062          * @event disable
15063          * Fires after the component is disabled.
15064              * @param {Roo.Component} this
15065              */
15066         disable : true,
15067         /**
15068          * @event enable
15069          * Fires after the component is enabled.
15070              * @param {Roo.Component} this
15071              */
15072         enable : true,
15073         /**
15074          * @event beforeshow
15075          * Fires before the component is shown.  Return false to stop the show.
15076              * @param {Roo.Component} this
15077              */
15078         beforeshow : true,
15079         /**
15080          * @event show
15081          * Fires after the component is shown.
15082              * @param {Roo.Component} this
15083              */
15084         show : true,
15085         /**
15086          * @event beforehide
15087          * Fires before the component is hidden. Return false to stop the hide.
15088              * @param {Roo.Component} this
15089              */
15090         beforehide : true,
15091         /**
15092          * @event hide
15093          * Fires after the component is hidden.
15094              * @param {Roo.Component} this
15095              */
15096         hide : true,
15097         /**
15098          * @event beforerender
15099          * Fires before the component is rendered. Return false to stop the render.
15100              * @param {Roo.Component} this
15101              */
15102         beforerender : true,
15103         /**
15104          * @event render
15105          * Fires after the component is rendered.
15106              * @param {Roo.Component} this
15107              */
15108         render : true,
15109         /**
15110          * @event beforedestroy
15111          * Fires before the component is destroyed. Return false to stop the destroy.
15112              * @param {Roo.Component} this
15113              */
15114         beforedestroy : true,
15115         /**
15116          * @event destroy
15117          * Fires after the component is destroyed.
15118              * @param {Roo.Component} this
15119              */
15120         destroy : true
15121     });
15122     if(!this.id){
15123         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15124     }
15125     Roo.ComponentMgr.register(this);
15126     Roo.Component.superclass.constructor.call(this);
15127     this.initComponent();
15128     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15129         this.render(this.renderTo);
15130         delete this.renderTo;
15131     }
15132 };
15133
15134 /** @private */
15135 Roo.Component.AUTO_ID = 1000;
15136
15137 Roo.extend(Roo.Component, Roo.util.Observable, {
15138     /**
15139      * @scope Roo.Component.prototype
15140      * @type {Boolean}
15141      * true if this component is hidden. Read-only.
15142      */
15143     hidden : false,
15144     /**
15145      * @type {Boolean}
15146      * true if this component is disabled. Read-only.
15147      */
15148     disabled : false,
15149     /**
15150      * @type {Boolean}
15151      * true if this component has been rendered. Read-only.
15152      */
15153     rendered : false,
15154     
15155     /** @cfg {String} disableClass
15156      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15157      */
15158     disabledClass : "x-item-disabled",
15159         /** @cfg {Boolean} allowDomMove
15160          * Whether the component can move the Dom node when rendering (defaults to true).
15161          */
15162     allowDomMove : true,
15163     /** @cfg {String} hideMode
15164      * How this component should hidden. Supported values are
15165      * "visibility" (css visibility), "offsets" (negative offset position) and
15166      * "display" (css display) - defaults to "display".
15167      */
15168     hideMode: 'display',
15169
15170     /** @private */
15171     ctype : "Roo.Component",
15172
15173     /**
15174      * @cfg {String} actionMode 
15175      * which property holds the element that used for  hide() / show() / disable() / enable()
15176      * default is 'el' 
15177      */
15178     actionMode : "el",
15179
15180     /** @private */
15181     getActionEl : function(){
15182         return this[this.actionMode];
15183     },
15184
15185     initComponent : Roo.emptyFn,
15186     /**
15187      * If this is a lazy rendering component, render it to its container element.
15188      * @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.
15189      */
15190     render : function(container, position){
15191         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15192             if(!container && this.el){
15193                 this.el = Roo.get(this.el);
15194                 container = this.el.dom.parentNode;
15195                 this.allowDomMove = false;
15196             }
15197             this.container = Roo.get(container);
15198             this.rendered = true;
15199             if(position !== undefined){
15200                 if(typeof position == 'number'){
15201                     position = this.container.dom.childNodes[position];
15202                 }else{
15203                     position = Roo.getDom(position);
15204                 }
15205             }
15206             this.onRender(this.container, position || null);
15207             if(this.cls){
15208                 this.el.addClass(this.cls);
15209                 delete this.cls;
15210             }
15211             if(this.style){
15212                 this.el.applyStyles(this.style);
15213                 delete this.style;
15214             }
15215             this.fireEvent("render", this);
15216             this.afterRender(this.container);
15217             if(this.hidden){
15218                 this.hide();
15219             }
15220             if(this.disabled){
15221                 this.disable();
15222             }
15223         }
15224         return this;
15225     },
15226
15227     /** @private */
15228     // default function is not really useful
15229     onRender : function(ct, position){
15230         if(this.el){
15231             this.el = Roo.get(this.el);
15232             if(this.allowDomMove !== false){
15233                 ct.dom.insertBefore(this.el.dom, position);
15234             }
15235         }
15236     },
15237
15238     /** @private */
15239     getAutoCreate : function(){
15240         var cfg = typeof this.autoCreate == "object" ?
15241                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15242         if(this.id && !cfg.id){
15243             cfg.id = this.id;
15244         }
15245         return cfg;
15246     },
15247
15248     /** @private */
15249     afterRender : Roo.emptyFn,
15250
15251     /**
15252      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15253      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15254      */
15255     destroy : function(){
15256         if(this.fireEvent("beforedestroy", this) !== false){
15257             this.purgeListeners();
15258             this.beforeDestroy();
15259             if(this.rendered){
15260                 this.el.removeAllListeners();
15261                 this.el.remove();
15262                 if(this.actionMode == "container"){
15263                     this.container.remove();
15264                 }
15265             }
15266             this.onDestroy();
15267             Roo.ComponentMgr.unregister(this);
15268             this.fireEvent("destroy", this);
15269         }
15270     },
15271
15272         /** @private */
15273     beforeDestroy : function(){
15274
15275     },
15276
15277         /** @private */
15278         onDestroy : function(){
15279
15280     },
15281
15282     /**
15283      * Returns the underlying {@link Roo.Element}.
15284      * @return {Roo.Element} The element
15285      */
15286     getEl : function(){
15287         return this.el;
15288     },
15289
15290     /**
15291      * Returns the id of this component.
15292      * @return {String}
15293      */
15294     getId : function(){
15295         return this.id;
15296     },
15297
15298     /**
15299      * Try to focus this component.
15300      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15301      * @return {Roo.Component} this
15302      */
15303     focus : function(selectText){
15304         if(this.rendered){
15305             this.el.focus();
15306             if(selectText === true){
15307                 this.el.dom.select();
15308             }
15309         }
15310         return this;
15311     },
15312
15313     /** @private */
15314     blur : function(){
15315         if(this.rendered){
15316             this.el.blur();
15317         }
15318         return this;
15319     },
15320
15321     /**
15322      * Disable this component.
15323      * @return {Roo.Component} this
15324      */
15325     disable : function(){
15326         if(this.rendered){
15327             this.onDisable();
15328         }
15329         this.disabled = true;
15330         this.fireEvent("disable", this);
15331         return this;
15332     },
15333
15334         // private
15335     onDisable : function(){
15336         this.getActionEl().addClass(this.disabledClass);
15337         this.el.dom.disabled = true;
15338     },
15339
15340     /**
15341      * Enable this component.
15342      * @return {Roo.Component} this
15343      */
15344     enable : function(){
15345         if(this.rendered){
15346             this.onEnable();
15347         }
15348         this.disabled = false;
15349         this.fireEvent("enable", this);
15350         return this;
15351     },
15352
15353         // private
15354     onEnable : function(){
15355         this.getActionEl().removeClass(this.disabledClass);
15356         this.el.dom.disabled = false;
15357     },
15358
15359     /**
15360      * Convenience function for setting disabled/enabled by boolean.
15361      * @param {Boolean} disabled
15362      */
15363     setDisabled : function(disabled){
15364         this[disabled ? "disable" : "enable"]();
15365     },
15366
15367     /**
15368      * Show this component.
15369      * @return {Roo.Component} this
15370      */
15371     show: function(){
15372         if(this.fireEvent("beforeshow", this) !== false){
15373             this.hidden = false;
15374             if(this.rendered){
15375                 this.onShow();
15376             }
15377             this.fireEvent("show", this);
15378         }
15379         return this;
15380     },
15381
15382     // private
15383     onShow : function(){
15384         var ae = this.getActionEl();
15385         if(this.hideMode == 'visibility'){
15386             ae.dom.style.visibility = "visible";
15387         }else if(this.hideMode == 'offsets'){
15388             ae.removeClass('x-hidden');
15389         }else{
15390             ae.dom.style.display = "";
15391         }
15392     },
15393
15394     /**
15395      * Hide this component.
15396      * @return {Roo.Component} this
15397      */
15398     hide: function(){
15399         if(this.fireEvent("beforehide", this) !== false){
15400             this.hidden = true;
15401             if(this.rendered){
15402                 this.onHide();
15403             }
15404             this.fireEvent("hide", this);
15405         }
15406         return this;
15407     },
15408
15409     // private
15410     onHide : function(){
15411         var ae = this.getActionEl();
15412         if(this.hideMode == 'visibility'){
15413             ae.dom.style.visibility = "hidden";
15414         }else if(this.hideMode == 'offsets'){
15415             ae.addClass('x-hidden');
15416         }else{
15417             ae.dom.style.display = "none";
15418         }
15419     },
15420
15421     /**
15422      * Convenience function to hide or show this component by boolean.
15423      * @param {Boolean} visible True to show, false to hide
15424      * @return {Roo.Component} this
15425      */
15426     setVisible: function(visible){
15427         if(visible) {
15428             this.show();
15429         }else{
15430             this.hide();
15431         }
15432         return this;
15433     },
15434
15435     /**
15436      * Returns true if this component is visible.
15437      */
15438     isVisible : function(){
15439         return this.getActionEl().isVisible();
15440     },
15441
15442     cloneConfig : function(overrides){
15443         overrides = overrides || {};
15444         var id = overrides.id || Roo.id();
15445         var cfg = Roo.applyIf(overrides, this.initialConfig);
15446         cfg.id = id; // prevent dup id
15447         return new this.constructor(cfg);
15448     }
15449 });/*
15450  * Based on:
15451  * Ext JS Library 1.1.1
15452  * Copyright(c) 2006-2007, Ext JS, LLC.
15453  *
15454  * Originally Released Under LGPL - original licence link has changed is not relivant.
15455  *
15456  * Fork - LGPL
15457  * <script type="text/javascript">
15458  */
15459
15460 /**
15461  * @class Roo.BoxComponent
15462  * @extends Roo.Component
15463  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15464  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15465  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15466  * layout containers.
15467  * @constructor
15468  * @param {Roo.Element/String/Object} config The configuration options.
15469  */
15470 Roo.BoxComponent = function(config){
15471     Roo.Component.call(this, config);
15472     this.addEvents({
15473         /**
15474          * @event resize
15475          * Fires after the component is resized.
15476              * @param {Roo.Component} this
15477              * @param {Number} adjWidth The box-adjusted width that was set
15478              * @param {Number} adjHeight The box-adjusted height that was set
15479              * @param {Number} rawWidth The width that was originally specified
15480              * @param {Number} rawHeight The height that was originally specified
15481              */
15482         resize : true,
15483         /**
15484          * @event move
15485          * Fires after the component is moved.
15486              * @param {Roo.Component} this
15487              * @param {Number} x The new x position
15488              * @param {Number} y The new y position
15489              */
15490         move : true
15491     });
15492 };
15493
15494 Roo.extend(Roo.BoxComponent, Roo.Component, {
15495     // private, set in afterRender to signify that the component has been rendered
15496     boxReady : false,
15497     // private, used to defer height settings to subclasses
15498     deferHeight: false,
15499     /** @cfg {Number} width
15500      * width (optional) size of component
15501      */
15502      /** @cfg {Number} height
15503      * height (optional) size of component
15504      */
15505      
15506     /**
15507      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15508      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15509      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15510      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15511      * @return {Roo.BoxComponent} this
15512      */
15513     setSize : function(w, h){
15514         // support for standard size objects
15515         if(typeof w == 'object'){
15516             h = w.height;
15517             w = w.width;
15518         }
15519         // not rendered
15520         if(!this.boxReady){
15521             this.width = w;
15522             this.height = h;
15523             return this;
15524         }
15525
15526         // prevent recalcs when not needed
15527         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15528             return this;
15529         }
15530         this.lastSize = {width: w, height: h};
15531
15532         var adj = this.adjustSize(w, h);
15533         var aw = adj.width, ah = adj.height;
15534         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15535             var rz = this.getResizeEl();
15536             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15537                 rz.setSize(aw, ah);
15538             }else if(!this.deferHeight && ah !== undefined){
15539                 rz.setHeight(ah);
15540             }else if(aw !== undefined){
15541                 rz.setWidth(aw);
15542             }
15543             this.onResize(aw, ah, w, h);
15544             this.fireEvent('resize', this, aw, ah, w, h);
15545         }
15546         return this;
15547     },
15548
15549     /**
15550      * Gets the current size of the component's underlying element.
15551      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15552      */
15553     getSize : function(){
15554         return this.el.getSize();
15555     },
15556
15557     /**
15558      * Gets the current XY position of the component's underlying element.
15559      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15560      * @return {Array} The XY position of the element (e.g., [100, 200])
15561      */
15562     getPosition : function(local){
15563         if(local === true){
15564             return [this.el.getLeft(true), this.el.getTop(true)];
15565         }
15566         return this.xy || this.el.getXY();
15567     },
15568
15569     /**
15570      * Gets the current box measurements of the component's underlying element.
15571      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15572      * @returns {Object} box An object in the format {x, y, width, height}
15573      */
15574     getBox : function(local){
15575         var s = this.el.getSize();
15576         if(local){
15577             s.x = this.el.getLeft(true);
15578             s.y = this.el.getTop(true);
15579         }else{
15580             var xy = this.xy || this.el.getXY();
15581             s.x = xy[0];
15582             s.y = xy[1];
15583         }
15584         return s;
15585     },
15586
15587     /**
15588      * Sets the current box measurements of the component's underlying element.
15589      * @param {Object} box An object in the format {x, y, width, height}
15590      * @returns {Roo.BoxComponent} this
15591      */
15592     updateBox : function(box){
15593         this.setSize(box.width, box.height);
15594         this.setPagePosition(box.x, box.y);
15595         return this;
15596     },
15597
15598     // protected
15599     getResizeEl : function(){
15600         return this.resizeEl || this.el;
15601     },
15602
15603     // protected
15604     getPositionEl : function(){
15605         return this.positionEl || this.el;
15606     },
15607
15608     /**
15609      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15610      * This method fires the move event.
15611      * @param {Number} left The new left
15612      * @param {Number} top The new top
15613      * @returns {Roo.BoxComponent} this
15614      */
15615     setPosition : function(x, y){
15616         this.x = x;
15617         this.y = y;
15618         if(!this.boxReady){
15619             return this;
15620         }
15621         var adj = this.adjustPosition(x, y);
15622         var ax = adj.x, ay = adj.y;
15623
15624         var el = this.getPositionEl();
15625         if(ax !== undefined || ay !== undefined){
15626             if(ax !== undefined && ay !== undefined){
15627                 el.setLeftTop(ax, ay);
15628             }else if(ax !== undefined){
15629                 el.setLeft(ax);
15630             }else if(ay !== undefined){
15631                 el.setTop(ay);
15632             }
15633             this.onPosition(ax, ay);
15634             this.fireEvent('move', this, ax, ay);
15635         }
15636         return this;
15637     },
15638
15639     /**
15640      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15641      * This method fires the move event.
15642      * @param {Number} x The new x position
15643      * @param {Number} y The new y position
15644      * @returns {Roo.BoxComponent} this
15645      */
15646     setPagePosition : function(x, y){
15647         this.pageX = x;
15648         this.pageY = y;
15649         if(!this.boxReady){
15650             return;
15651         }
15652         if(x === undefined || y === undefined){ // cannot translate undefined points
15653             return;
15654         }
15655         var p = this.el.translatePoints(x, y);
15656         this.setPosition(p.left, p.top);
15657         return this;
15658     },
15659
15660     // private
15661     onRender : function(ct, position){
15662         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15663         if(this.resizeEl){
15664             this.resizeEl = Roo.get(this.resizeEl);
15665         }
15666         if(this.positionEl){
15667             this.positionEl = Roo.get(this.positionEl);
15668         }
15669     },
15670
15671     // private
15672     afterRender : function(){
15673         Roo.BoxComponent.superclass.afterRender.call(this);
15674         this.boxReady = true;
15675         this.setSize(this.width, this.height);
15676         if(this.x || this.y){
15677             this.setPosition(this.x, this.y);
15678         }
15679         if(this.pageX || this.pageY){
15680             this.setPagePosition(this.pageX, this.pageY);
15681         }
15682     },
15683
15684     /**
15685      * Force the component's size to recalculate based on the underlying element's current height and width.
15686      * @returns {Roo.BoxComponent} this
15687      */
15688     syncSize : function(){
15689         delete this.lastSize;
15690         this.setSize(this.el.getWidth(), this.el.getHeight());
15691         return this;
15692     },
15693
15694     /**
15695      * Called after the component is resized, this method is empty by default but can be implemented by any
15696      * subclass that needs to perform custom logic after a resize occurs.
15697      * @param {Number} adjWidth The box-adjusted width that was set
15698      * @param {Number} adjHeight The box-adjusted height that was set
15699      * @param {Number} rawWidth The width that was originally specified
15700      * @param {Number} rawHeight The height that was originally specified
15701      */
15702     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15703
15704     },
15705
15706     /**
15707      * Called after the component is moved, this method is empty by default but can be implemented by any
15708      * subclass that needs to perform custom logic after a move occurs.
15709      * @param {Number} x The new x position
15710      * @param {Number} y The new y position
15711      */
15712     onPosition : function(x, y){
15713
15714     },
15715
15716     // private
15717     adjustSize : function(w, h){
15718         if(this.autoWidth){
15719             w = 'auto';
15720         }
15721         if(this.autoHeight){
15722             h = 'auto';
15723         }
15724         return {width : w, height: h};
15725     },
15726
15727     // private
15728     adjustPosition : function(x, y){
15729         return {x : x, y: y};
15730     }
15731 });/*
15732  * Original code for Roojs - LGPL
15733  * <script type="text/javascript">
15734  */
15735  
15736 /**
15737  * @class Roo.XComponent
15738  * A delayed Element creator...
15739  * Or a way to group chunks of interface together.
15740  * 
15741  * Mypart.xyx = new Roo.XComponent({
15742
15743     parent : 'Mypart.xyz', // empty == document.element.!!
15744     order : '001',
15745     name : 'xxxx'
15746     region : 'xxxx'
15747     disabled : function() {} 
15748      
15749     tree : function() { // return an tree of xtype declared components
15750         var MODULE = this;
15751         return 
15752         {
15753             xtype : 'NestedLayoutPanel',
15754             // technicall
15755         }
15756      ]
15757  *})
15758  *
15759  *
15760  * It can be used to build a big heiracy, with parent etc.
15761  * or you can just use this to render a single compoent to a dom element
15762  * MYPART.render(Roo.Element | String(id) | dom_element )
15763  * 
15764  * @extends Roo.util.Observable
15765  * @constructor
15766  * @param cfg {Object} configuration of component
15767  * 
15768  */
15769 Roo.XComponent = function(cfg) {
15770     Roo.apply(this, cfg);
15771     this.addEvents({ 
15772         /**
15773              * @event built
15774              * Fires when this the componnt is built
15775              * @param {Roo.XComponent} c the component
15776              */
15777         'built' : true
15778         
15779     });
15780     this.region = this.region || 'center'; // default..
15781     Roo.XComponent.register(this);
15782     this.modules = false;
15783     this.el = false; // where the layout goes..
15784     
15785     
15786 }
15787 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15788     /**
15789      * @property el
15790      * The created element (with Roo.factory())
15791      * @type {Roo.Layout}
15792      */
15793     el  : false,
15794     
15795     /**
15796      * @property el
15797      * for BC  - use el in new code
15798      * @type {Roo.Layout}
15799      */
15800     panel : false,
15801     
15802     /**
15803      * @property layout
15804      * for BC  - use el in new code
15805      * @type {Roo.Layout}
15806      */
15807     layout : false,
15808     
15809      /**
15810      * @cfg {Function|boolean} disabled
15811      * If this module is disabled by some rule, return true from the funtion
15812      */
15813     disabled : false,
15814     
15815     /**
15816      * @cfg {String} parent 
15817      * Name of parent element which it get xtype added to..
15818      */
15819     parent: false,
15820     
15821     /**
15822      * @cfg {String} order
15823      * Used to set the order in which elements are created (usefull for multiple tabs)
15824      */
15825     
15826     order : false,
15827     /**
15828      * @cfg {String} name
15829      * String to display while loading.
15830      */
15831     name : false,
15832     /**
15833      * @cfg {String} region
15834      * Region to render component to (defaults to center)
15835      */
15836     region : 'center',
15837     
15838     /**
15839      * @cfg {Array} items
15840      * A single item array - the first element is the root of the tree..
15841      * It's done this way to stay compatible with the Xtype system...
15842      */
15843     items : false,
15844     
15845     /**
15846      * @property _tree
15847      * The method that retuns the tree of parts that make up this compoennt 
15848      * @type {function}
15849      */
15850     _tree  : false,
15851     
15852      /**
15853      * render
15854      * render element to dom or tree
15855      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15856      */
15857     
15858     render : function(el)
15859     {
15860         
15861         el = el || false;
15862         var hp = this.parent ? 1 : 0;
15863         
15864         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15865             // if parent is a '#.....' string, then let's use that..
15866             var ename = this.parent.substr(1)
15867             this.parent = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
15868             el = Roo.get(ename);
15869             if (!el && !this.parent) {
15870                 Roo.log("Warning - element can not be found :#" + ename );
15871                 return;
15872             }
15873         }
15874         var tree = this._tree ? this._tree() : this.tree();
15875
15876         
15877         if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15878             //el = Roo.get(document.body);
15879             this.parent = { el : true };
15880         }
15881             
15882             
15883         
15884         if (!this.parent) {
15885             
15886             Roo.log("no parent - creating one");
15887             
15888             el = el ? Roo.get(el) : false;      
15889             
15890             // it's a top level one..
15891             this.parent =  {
15892                 el : new Roo.BorderLayout(el || document.body, {
15893                 
15894                      center: {
15895                          titlebar: false,
15896                          autoScroll:false,
15897                          closeOnTab: true,
15898                          tabPosition: 'top',
15899                           //resizeTabs: true,
15900                          alwaysShowTabs: el && hp? false :  true,
15901                          hideTabs: el || !hp ? true :  false,
15902                          minTabWidth: 140
15903                      }
15904                  })
15905             }
15906         }
15907         
15908                 if (!this.parent.el) {
15909                         // probably an old style ctor, which has been disabled.
15910                         return;
15911                         
15912                 }
15913                 // The 'tree' method is  '_tree now' 
15914             
15915         tree.region = tree.region || this.region;
15916         
15917         if (this.parent.el === true) {
15918             // bootstrap... - body..
15919             this.parent.el = Roo.factory(tree);
15920         }
15921         
15922         this.el = this.parent.el.addxtype(tree);
15923         this.fireEvent('built', this);
15924         
15925         this.panel = this.el;
15926         this.layout = this.panel.layout;
15927                 this.parentLayout = this.parent.layout  || false;  
15928          
15929     }
15930     
15931 });
15932
15933 Roo.apply(Roo.XComponent, {
15934     /**
15935      * @property  hideProgress
15936      * true to disable the building progress bar.. usefull on single page renders.
15937      * @type Boolean
15938      */
15939     hideProgress : false,
15940     /**
15941      * @property  buildCompleted
15942      * True when the builder has completed building the interface.
15943      * @type Boolean
15944      */
15945     buildCompleted : false,
15946      
15947     /**
15948      * @property  topModule
15949      * the upper most module - uses document.element as it's constructor.
15950      * @type Object
15951      */
15952      
15953     topModule  : false,
15954       
15955     /**
15956      * @property  modules
15957      * array of modules to be created by registration system.
15958      * @type {Array} of Roo.XComponent
15959      */
15960     
15961     modules : [],
15962     /**
15963      * @property  elmodules
15964      * array of modules to be created by which use #ID 
15965      * @type {Array} of Roo.XComponent
15966      */
15967      
15968     elmodules : [],
15969
15970      /**
15971      * @property  build_from_html
15972      * Build elements from html - used by bootstrap HTML stuff 
15973      *    - this is cleared after build is completed
15974      * @type {boolean} true  (default false)
15975      */
15976      
15977     build_from_html : false,
15978
15979     /**
15980      * Register components to be built later.
15981      *
15982      * This solves the following issues
15983      * - Building is not done on page load, but after an authentication process has occured.
15984      * - Interface elements are registered on page load
15985      * - Parent Interface elements may not be loaded before child, so this handles that..
15986      * 
15987      *
15988      * example:
15989      * 
15990      * MyApp.register({
15991           order : '000001',
15992           module : 'Pman.Tab.projectMgr',
15993           region : 'center',
15994           parent : 'Pman.layout',
15995           disabled : false,  // or use a function..
15996         })
15997      
15998      * * @param {Object} details about module
15999      */
16000     register : function(obj) {
16001                 
16002         Roo.XComponent.event.fireEvent('register', obj);
16003         switch(typeof(obj.disabled) ) {
16004                 
16005             case 'undefined':
16006                 break;
16007             
16008             case 'function':
16009                 if ( obj.disabled() ) {
16010                         return;
16011                 }
16012                 break;
16013             
16014             default:
16015                 if (obj.disabled) {
16016                         return;
16017                 }
16018                 break;
16019         }
16020                 
16021         this.modules.push(obj);
16022          
16023     },
16024     /**
16025      * convert a string to an object..
16026      * eg. 'AAA.BBB' -> finds AAA.BBB
16027
16028      */
16029     
16030     toObject : function(str)
16031     {
16032         if (!str || typeof(str) == 'object') {
16033             return str;
16034         }
16035         if (str.substring(0,1) == '#') {
16036             return str;
16037         }
16038
16039         var ar = str.split('.');
16040         var rt, o;
16041         rt = ar.shift();
16042             /** eval:var:o */
16043         try {
16044             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16045         } catch (e) {
16046             throw "Module not found : " + str;
16047         }
16048         
16049         if (o === false) {
16050             throw "Module not found : " + str;
16051         }
16052         Roo.each(ar, function(e) {
16053             if (typeof(o[e]) == 'undefined') {
16054                 throw "Module not found : " + str;
16055             }
16056             o = o[e];
16057         });
16058         
16059         return o;
16060         
16061     },
16062     
16063     
16064     /**
16065      * move modules into their correct place in the tree..
16066      * 
16067      */
16068     preBuild : function ()
16069     {
16070         var _t = this;
16071         Roo.each(this.modules , function (obj)
16072         {
16073             Roo.XComponent.event.fireEvent('beforebuild', obj);
16074             
16075             var opar = obj.parent;
16076             try { 
16077                 obj.parent = this.toObject(opar);
16078             } catch(e) {
16079                 Roo.log("parent:toObject failed: " + e.toString());
16080                 return;
16081             }
16082             
16083             if (!obj.parent) {
16084                 Roo.debug && Roo.log("GOT top level module");
16085                 Roo.debug && Roo.log(obj);
16086                 obj.modules = new Roo.util.MixedCollection(false, 
16087                     function(o) { return o.order + '' }
16088                 );
16089                 this.topModule = obj;
16090                 return;
16091             }
16092                         // parent is a string (usually a dom element name..)
16093             if (typeof(obj.parent) == 'string') {
16094                 this.elmodules.push(obj);
16095                 return;
16096             }
16097             if (obj.parent.constructor != Roo.XComponent) {
16098                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16099             }
16100             if (!obj.parent.modules) {
16101                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16102                     function(o) { return o.order + '' }
16103                 );
16104             }
16105             if (obj.parent.disabled) {
16106                 obj.disabled = true;
16107             }
16108             obj.parent.modules.add(obj);
16109         }, this);
16110     },
16111     
16112      /**
16113      * make a list of modules to build.
16114      * @return {Array} list of modules. 
16115      */ 
16116     
16117     buildOrder : function()
16118     {
16119         var _this = this;
16120         var cmp = function(a,b) {   
16121             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16122         };
16123         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16124             throw "No top level modules to build";
16125         }
16126         
16127         // make a flat list in order of modules to build.
16128         var mods = this.topModule ? [ this.topModule ] : [];
16129                 
16130         
16131         // elmodules (is a list of DOM based modules )
16132         Roo.each(this.elmodules, function(e) {
16133             mods.push(e);
16134             if (!this.topModule &&
16135                 typeof(e.parent) == 'string' &&
16136                 e.parent.substring(0,1) == '#' &&
16137                 Roo.get(e.parent.substr(1))
16138                ) {
16139                 
16140                 _this.topModule = e;
16141             }
16142             
16143         });
16144
16145         
16146         // add modules to their parents..
16147         var addMod = function(m) {
16148             Roo.debug && Roo.log("build Order: add: " + m.name);
16149                 
16150             mods.push(m);
16151             if (m.modules && !m.disabled) {
16152                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16153                 m.modules.keySort('ASC',  cmp );
16154                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16155     
16156                 m.modules.each(addMod);
16157             } else {
16158                 Roo.debug && Roo.log("build Order: no child modules");
16159             }
16160             // not sure if this is used any more..
16161             if (m.finalize) {
16162                 m.finalize.name = m.name + " (clean up) ";
16163                 mods.push(m.finalize);
16164             }
16165             
16166         }
16167         if (this.topModule && this.topModule.modules) { 
16168             this.topModule.modules.keySort('ASC',  cmp );
16169             this.topModule.modules.each(addMod);
16170         } 
16171         return mods;
16172     },
16173     
16174      /**
16175      * Build the registered modules.
16176      * @param {Object} parent element.
16177      * @param {Function} optional method to call after module has been added.
16178      * 
16179      */ 
16180    
16181     build : function(opts) 
16182     {
16183         
16184         if (typeof(opts) != 'undefined') {
16185             Roo.apply(this,opts);
16186         }
16187         
16188         this.preBuild();
16189         var mods = this.buildOrder();
16190       
16191         //this.allmods = mods;
16192         //Roo.debug && Roo.log(mods);
16193         //return;
16194         if (!mods.length) { // should not happen
16195             throw "NO modules!!!";
16196         }
16197         
16198         
16199         var msg = "Building Interface...";
16200         // flash it up as modal - so we store the mask!?
16201         if (!this.hideProgress && Roo.MessageBox) {
16202             Roo.MessageBox.show({ title: 'loading' });
16203             Roo.MessageBox.show({
16204                title: "Please wait...",
16205                msg: msg,
16206                width:450,
16207                progress:true,
16208                closable:false,
16209                modal: false
16210               
16211             });
16212         }
16213         var total = mods.length;
16214         
16215         var _this = this;
16216         var progressRun = function() {
16217             if (!mods.length) {
16218                 Roo.debug && Roo.log('hide?');
16219                 if (!this.hideProgress && Roo.MessageBox) {
16220                     Roo.MessageBox.hide();
16221                 }
16222                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16223                 
16224                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16225                 
16226                 // THE END...
16227                 return false;   
16228             }
16229             
16230             var m = mods.shift();
16231             
16232             
16233             Roo.debug && Roo.log(m);
16234             // not sure if this is supported any more.. - modules that are are just function
16235             if (typeof(m) == 'function') { 
16236                 m.call(this);
16237                 return progressRun.defer(10, _this);
16238             } 
16239             
16240             
16241             msg = "Building Interface " + (total  - mods.length) + 
16242                     " of " + total + 
16243                     (m.name ? (' - ' + m.name) : '');
16244                         Roo.debug && Roo.log(msg);
16245             if (!this.hideProgress &&  Roo.MessageBox) { 
16246                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16247             }
16248             
16249          
16250             // is the module disabled?
16251             var disabled = (typeof(m.disabled) == 'function') ?
16252                 m.disabled.call(m.module.disabled) : m.disabled;    
16253             
16254             
16255             if (disabled) {
16256                 return progressRun(); // we do not update the display!
16257             }
16258             
16259             // now build 
16260             
16261                         
16262                         
16263             m.render();
16264             // it's 10 on top level, and 1 on others??? why...
16265             return progressRun.defer(10, _this);
16266              
16267         }
16268         progressRun.defer(1, _this);
16269      
16270         
16271         
16272     },
16273         
16274         
16275         /**
16276          * Event Object.
16277          *
16278          *
16279          */
16280         event: false, 
16281     /**
16282          * wrapper for event.on - aliased later..  
16283          * Typically use to register a event handler for register:
16284          *
16285          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16286          *
16287          */
16288     on : false
16289    
16290     
16291     
16292 });
16293
16294 Roo.XComponent.event = new Roo.util.Observable({
16295                 events : { 
16296                         /**
16297                          * @event register
16298                          * Fires when an Component is registered,
16299                          * set the disable property on the Component to stop registration.
16300                          * @param {Roo.XComponent} c the component being registerd.
16301                          * 
16302                          */
16303                         'register' : true,
16304             /**
16305                          * @event beforebuild
16306                          * Fires before each Component is built
16307                          * can be used to apply permissions.
16308                          * @param {Roo.XComponent} c the component being registerd.
16309                          * 
16310                          */
16311                         'beforebuild' : true,
16312                         /**
16313                          * @event buildcomplete
16314                          * Fires on the top level element when all elements have been built
16315                          * @param {Roo.XComponent} the top level component.
16316                          */
16317                         'buildcomplete' : true
16318                         
16319                 }
16320 });
16321
16322 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16323