roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isIE = ua.indexOf("msie") > -1,
57         isIE7 = ua.indexOf("msie 7") > -1,
58         isGecko = !isSafari && ua.indexOf("gecko") > -1,
59         isBorderBox = isIE && !isStrict,
60         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
61         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
62         isLinux = (ua.indexOf("linux") != -1),
63         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
64         isTouch =  'ontouchstart' in window || window.DocumentTouch && document instanceof DocumentTouch;
65     // remove css image flicker
66         if(isIE && !isIE7){
67         try{
68             document.execCommand("BackgroundImageCache", false, true);
69         }catch(e){}
70     }
71     
72     Roo.apply(Roo, {
73         /**
74          * True if the browser is in strict mode
75          * @type Boolean
76          */
77         isStrict : isStrict,
78         /**
79          * True if the page is running over SSL
80          * @type Boolean
81          */
82         isSecure : isSecure,
83         /**
84          * True when the document is fully initialized and ready for action
85          * @type Boolean
86          */
87         isReady : false,
88         /**
89          * Turn on debugging output (currently only the factory uses this)
90          * @type Boolean
91          */
92         
93         debug: false,
94
95         /**
96          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
97          * @type Boolean
98          */
99         enableGarbageCollector : true,
100
101         /**
102          * True to automatically purge event listeners after uncaching an element (defaults to false).
103          * Note: this only happens if enableGarbageCollector is true.
104          * @type Boolean
105          */
106         enableListenerCollection:false,
107
108         /**
109          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
110          * the IE insecure content warning (defaults to javascript:false).
111          * @type String
112          */
113         SSL_SECURE_URL : "javascript:false",
114
115         /**
116          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
117          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
118          * @type String
119          */
120         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
121
122         emptyFn : function(){},
123         
124         /**
125          * Copies all the properties of config to obj if they don't already exist.
126          * @param {Object} obj The receiver of the properties
127          * @param {Object} config The source of the properties
128          * @return {Object} returns obj
129          */
130         applyIf : function(o, c){
131             if(o && c){
132                 for(var p in c){
133                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
134                 }
135             }
136             return o;
137         },
138
139         /**
140          * Applies event listeners to elements by selectors when the document is ready.
141          * The event name is specified with an @ suffix.
142 <pre><code>
143 Roo.addBehaviors({
144    // add a listener for click on all anchors in element with id foo
145    '#foo a@click' : function(e, t){
146        // do something
147    },
148
149    // add the same listener to multiple selectors (separated by comma BEFORE the @)
150    '#foo a, #bar span.some-class@mouseover' : function(){
151        // do something
152    }
153 });
154 </code></pre>
155          * @param {Object} obj The list of behaviors to apply
156          */
157         addBehaviors : function(o){
158             if(!Roo.isReady){
159                 Roo.onReady(function(){
160                     Roo.addBehaviors(o);
161                 });
162                 return;
163             }
164             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
165             for(var b in o){
166                 var parts = b.split('@');
167                 if(parts[1]){ // for Object prototype breakers
168                     var s = parts[0];
169                     if(!cache[s]){
170                         cache[s] = Roo.select(s);
171                     }
172                     cache[s].on(parts[1], o[b]);
173                 }
174             }
175             cache = null;
176         },
177
178         /**
179          * Generates unique ids. If the element already has an id, it is unchanged
180          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
181          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
182          * @return {String} The generated Id.
183          */
184         id : function(el, prefix){
185             prefix = prefix || "roo-gen";
186             el = Roo.getDom(el);
187             var id = prefix + (++idSeed);
188             return el ? (el.id ? el.id : (el.id = id)) : id;
189         },
190          
191        
192         /**
193          * Extends one class with another class and optionally overrides members with the passed literal. This class
194          * also adds the function "override()" to the class that can be used to override
195          * members on an instance.
196          * @param {Object} subclass The class inheriting the functionality
197          * @param {Object} superclass The class being extended
198          * @param {Object} overrides (optional) A literal with members
199          * @method extend
200          */
201         extend : function(){
202             // inline overrides
203             var io = function(o){
204                 for(var m in o){
205                     this[m] = o[m];
206                 }
207             };
208             return function(sb, sp, overrides){
209                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
210                     overrides = sp;
211                     sp = sb;
212                     sb = function(){sp.apply(this, arguments);};
213                 }
214                 var F = function(){}, sbp, spp = sp.prototype;
215                 F.prototype = spp;
216                 sbp = sb.prototype = new F();
217                 sbp.constructor=sb;
218                 sb.superclass=spp;
219                 
220                 if(spp.constructor == Object.prototype.constructor){
221                     spp.constructor=sp;
222                    
223                 }
224                 
225                 sb.override = function(o){
226                     Roo.override(sb, o);
227                 };
228                 sbp.override = io;
229                 Roo.override(sb, overrides);
230                 return sb;
231             };
232         }(),
233
234         /**
235          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
236          * Usage:<pre><code>
237 Roo.override(MyClass, {
238     newMethod1: function(){
239         // etc.
240     },
241     newMethod2: function(foo){
242         // etc.
243     }
244 });
245  </code></pre>
246          * @param {Object} origclass The class to override
247          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
248          * containing one or more methods.
249          * @method override
250          */
251         override : function(origclass, overrides){
252             if(overrides){
253                 var p = origclass.prototype;
254                 for(var method in overrides){
255                     p[method] = overrides[method];
256                 }
257             }
258         },
259         /**
260          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
261          * <pre><code>
262 Roo.namespace('Company', 'Company.data');
263 Company.Widget = function() { ... }
264 Company.data.CustomStore = function(config) { ... }
265 </code></pre>
266          * @param {String} namespace1
267          * @param {String} namespace2
268          * @param {String} etc
269          * @method namespace
270          */
271         namespace : function(){
272             var a=arguments, o=null, i, j, d, rt;
273             for (i=0; i<a.length; ++i) {
274                 d=a[i].split(".");
275                 rt = d[0];
276                 /** eval:var:o */
277                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
278                 for (j=1; j<d.length; ++j) {
279                     o[d[j]]=o[d[j]] || {};
280                     o=o[d[j]];
281                 }
282             }
283         },
284         /**
285          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
286          * <pre><code>
287 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
288 Roo.factory(conf, Roo.data);
289 </code></pre>
290          * @param {String} classname
291          * @param {String} namespace (optional)
292          * @method factory
293          */
294          
295         factory : function(c, ns)
296         {
297             // no xtype, no ns or c.xns - or forced off by c.xns
298             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
299                 return c;
300             }
301             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
302             if (c.constructor == ns[c.xtype]) {// already created...
303                 return c;
304             }
305             if (ns[c.xtype]) {
306                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
307                 var ret = new ns[c.xtype](c);
308                 ret.xns = false;
309                 return ret;
310             }
311             c.xns = false; // prevent recursion..
312             return c;
313         },
314          /**
315          * Logs to console if it can.
316          *
317          * @param {String|Object} string
318          * @method log
319          */
320         log : function(s)
321         {
322             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
323                 return; // alerT?
324             }
325             console.log(s);
326             
327         },
328         /**
329          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
330          * @param {Object} o
331          * @return {String}
332          */
333         urlEncode : function(o){
334             if(!o){
335                 return "";
336             }
337             var buf = [];
338             for(var key in o){
339                 var ov = o[key], k = Roo.encodeURIComponent(key);
340                 var type = typeof ov;
341                 if(type == 'undefined'){
342                     buf.push(k, "=&");
343                 }else if(type != "function" && type != "object"){
344                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
345                 }else if(ov instanceof Array){
346                     if (ov.length) {
347                             for(var i = 0, len = ov.length; i < len; i++) {
348                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
349                             }
350                         } else {
351                             buf.push(k, "=&");
352                         }
353                 }
354             }
355             buf.pop();
356             return buf.join("");
357         },
358          /**
359          * Safe version of encodeURIComponent
360          * @param {String} data 
361          * @return {String} 
362          */
363         
364         encodeURIComponent : function (data)
365         {
366             try {
367                 return encodeURIComponent(data);
368             } catch(e) {} // should be an uri encode error.
369             
370             if (data == '' || data == null){
371                return '';
372             }
373             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
374             function nibble_to_hex(nibble){
375                 var chars = '0123456789ABCDEF';
376                 return chars.charAt(nibble);
377             }
378             data = data.toString();
379             var buffer = '';
380             for(var i=0; i<data.length; i++){
381                 var c = data.charCodeAt(i);
382                 var bs = new Array();
383                 if (c > 0x10000){
384                         // 4 bytes
385                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
386                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
387                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
388                     bs[3] = 0x80 | (c & 0x3F);
389                 }else if (c > 0x800){
390                          // 3 bytes
391                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
392                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
393                     bs[2] = 0x80 | (c & 0x3F);
394                 }else if (c > 0x80){
395                        // 2 bytes
396                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
397                     bs[1] = 0x80 | (c & 0x3F);
398                 }else{
399                         // 1 byte
400                     bs[0] = c;
401                 }
402                 for(var j=0; j<bs.length; j++){
403                     var b = bs[j];
404                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
405                             + nibble_to_hex(b &0x0F);
406                     buffer += '%'+hex;
407                }
408             }
409             return buffer;    
410              
411         },
412
413         /**
414          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
415          * @param {String} string
416          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
417          * @return {Object} A literal with members
418          */
419         urlDecode : function(string, overwrite){
420             if(!string || !string.length){
421                 return {};
422             }
423             var obj = {};
424             var pairs = string.split('&');
425             var pair, name, value;
426             for(var i = 0, len = pairs.length; i < len; i++){
427                 pair = pairs[i].split('=');
428                 name = decodeURIComponent(pair[0]);
429                 value = decodeURIComponent(pair[1]);
430                 if(overwrite !== true){
431                     if(typeof obj[name] == "undefined"){
432                         obj[name] = value;
433                     }else if(typeof obj[name] == "string"){
434                         obj[name] = [obj[name]];
435                         obj[name].push(value);
436                     }else{
437                         obj[name].push(value);
438                     }
439                 }else{
440                     obj[name] = value;
441                 }
442             }
443             return obj;
444         },
445
446         /**
447          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
448          * passed array is not really an array, your function is called once with it.
449          * The supplied function is called with (Object item, Number index, Array allItems).
450          * @param {Array/NodeList/Mixed} array
451          * @param {Function} fn
452          * @param {Object} scope
453          */
454         each : function(array, fn, scope){
455             if(typeof array.length == "undefined" || typeof array == "string"){
456                 array = [array];
457             }
458             for(var i = 0, len = array.length; i < len; i++){
459                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
460             }
461         },
462
463         // deprecated
464         combine : function(){
465             var as = arguments, l = as.length, r = [];
466             for(var i = 0; i < l; i++){
467                 var a = as[i];
468                 if(a instanceof Array){
469                     r = r.concat(a);
470                 }else if(a.length !== undefined && !a.substr){
471                     r = r.concat(Array.prototype.slice.call(a, 0));
472                 }else{
473                     r.push(a);
474                 }
475             }
476             return r;
477         },
478
479         /**
480          * Escapes the passed string for use in a regular expression
481          * @param {String} str
482          * @return {String}
483          */
484         escapeRe : function(s) {
485             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
486         },
487
488         // internal
489         callback : function(cb, scope, args, delay){
490             if(typeof cb == "function"){
491                 if(delay){
492                     cb.defer(delay, scope, args || []);
493                 }else{
494                     cb.apply(scope, args || []);
495                 }
496             }
497         },
498
499         /**
500          * Return the dom node for the passed string (id), dom node, or Roo.Element
501          * @param {String/HTMLElement/Roo.Element} el
502          * @return HTMLElement
503          */
504         getDom : function(el){
505             if(!el){
506                 return null;
507             }
508             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
509         },
510
511         /**
512         * Shorthand for {@link Roo.ComponentMgr#get}
513         * @param {String} id
514         * @return Roo.Component
515         */
516         getCmp : function(id){
517             return Roo.ComponentMgr.get(id);
518         },
519          
520         num : function(v, defaultValue){
521             if(typeof v != 'number'){
522                 return defaultValue;
523             }
524             return v;
525         },
526
527         destroy : function(){
528             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
529                 var as = a[i];
530                 if(as){
531                     if(as.dom){
532                         as.removeAllListeners();
533                         as.remove();
534                         continue;
535                     }
536                     if(typeof as.purgeListeners == 'function'){
537                         as.purgeListeners();
538                     }
539                     if(typeof as.destroy == 'function'){
540                         as.destroy();
541                     }
542                 }
543             }
544         },
545
546         // inpired by a similar function in mootools library
547         /**
548          * Returns the type of object that is passed in. If the object passed in is null or undefined it
549          * return false otherwise it returns one of the following values:<ul>
550          * <li><b>string</b>: If the object passed is a string</li>
551          * <li><b>number</b>: If the object passed is a number</li>
552          * <li><b>boolean</b>: If the object passed is a boolean value</li>
553          * <li><b>function</b>: If the object passed is a function reference</li>
554          * <li><b>object</b>: If the object passed is an object</li>
555          * <li><b>array</b>: If the object passed is an array</li>
556          * <li><b>regexp</b>: If the object passed is a regular expression</li>
557          * <li><b>element</b>: If the object passed is a DOM Element</li>
558          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
559          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
560          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
561          * @param {Mixed} object
562          * @return {String}
563          */
564         type : function(o){
565             if(o === undefined || o === null){
566                 return false;
567             }
568             if(o.htmlElement){
569                 return 'element';
570             }
571             var t = typeof o;
572             if(t == 'object' && o.nodeName) {
573                 switch(o.nodeType) {
574                     case 1: return 'element';
575                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
576                 }
577             }
578             if(t == 'object' || t == 'function') {
579                 switch(o.constructor) {
580                     case Array: return 'array';
581                     case RegExp: return 'regexp';
582                 }
583                 if(typeof o.length == 'number' && typeof o.item == 'function') {
584                     return 'nodelist';
585                 }
586             }
587             return t;
588         },
589
590         /**
591          * Returns true if the passed value is null, undefined or an empty string (optional).
592          * @param {Mixed} value The value to test
593          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
594          * @return {Boolean}
595          */
596         isEmpty : function(v, allowBlank){
597             return v === null || v === undefined || (!allowBlank ? v === '' : false);
598         },
599         
600         /** @type Boolean */
601         isOpera : isOpera,
602         /** @type Boolean */
603         isSafari : isSafari,
604         /** @type Boolean */
605         isIE : isIE,
606         /** @type Boolean */
607         isIE7 : isIE7,
608         /** @type Boolean */
609         isGecko : isGecko,
610         /** @type Boolean */
611         isBorderBox : isBorderBox,
612         /** @type Boolean */
613         isWindows : isWindows,
614         /** @type Boolean */
615         isLinux : isLinux,
616         /** @type Boolean */
617         isMac : isMac,
618         /** @type Boolean */
619         isTouch : isTouch,
620
621         /**
622          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
623          * you may want to set this to true.
624          * @type Boolean
625          */
626         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
627         
628         
629                 
630         /**
631          * Selects a single element as a Roo Element
632          * This is about as close as you can get to jQuery's $('do crazy stuff')
633          * @param {String} selector The selector/xpath query
634          * @param {Node} root (optional) The start of the query (defaults to document).
635          * @return {Roo.Element}
636          */
637         selectNode : function(selector, root) 
638         {
639             var node = Roo.DomQuery.selectNode(selector,root);
640             return node ? Roo.get(node) : new Roo.Element(false);
641         }
642         
643     });
644
645
646 })();
647
648 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
649                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", "Roo.app", "Roo.ux");
650 /*
651  * Based on:
652  * Ext JS Library 1.1.1
653  * Copyright(c) 2006-2007, Ext JS, LLC.
654  *
655  * Originally Released Under LGPL - original licence link has changed is not relivant.
656  *
657  * Fork - LGPL
658  * <script type="text/javascript">
659  */
660
661 (function() {    
662     // wrappedn so fnCleanup is not in global scope...
663     if(Roo.isIE) {
664         function fnCleanUp() {
665             var p = Function.prototype;
666             delete p.createSequence;
667             delete p.defer;
668             delete p.createDelegate;
669             delete p.createCallback;
670             delete p.createInterceptor;
671
672             window.detachEvent("onunload", fnCleanUp);
673         }
674         window.attachEvent("onunload", fnCleanUp);
675     }
676 })();
677
678
679 /**
680  * @class Function
681  * These functions are available on every Function object (any JavaScript function).
682  */
683 Roo.apply(Function.prototype, {
684      /**
685      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
686      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
687      * Will create a function that is bound to those 2 args.
688      * @return {Function} The new function
689     */
690     createCallback : function(/*args...*/){
691         // make args available, in function below
692         var args = arguments;
693         var method = this;
694         return function() {
695             return method.apply(window, args);
696         };
697     },
698
699     /**
700      * Creates a delegate (callback) that sets the scope to obj.
701      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
702      * Will create a function that is automatically scoped to this.
703      * @param {Object} obj (optional) The object for which the scope is set
704      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
705      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
706      *                                             if a number the args are inserted at the specified position
707      * @return {Function} The new function
708      */
709     createDelegate : function(obj, args, appendArgs){
710         var method = this;
711         return function() {
712             var callArgs = args || arguments;
713             if(appendArgs === true){
714                 callArgs = Array.prototype.slice.call(arguments, 0);
715                 callArgs = callArgs.concat(args);
716             }else if(typeof appendArgs == "number"){
717                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
718                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
719                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
720             }
721             return method.apply(obj || window, callArgs);
722         };
723     },
724
725     /**
726      * Calls this function after the number of millseconds specified.
727      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
728      * @param {Object} obj (optional) The object for which the scope is set
729      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
730      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
731      *                                             if a number the args are inserted at the specified position
732      * @return {Number} The timeout id that can be used with clearTimeout
733      */
734     defer : function(millis, obj, args, appendArgs){
735         var fn = this.createDelegate(obj, args, appendArgs);
736         if(millis){
737             return setTimeout(fn, millis);
738         }
739         fn();
740         return 0;
741     },
742     /**
743      * Create a combined function call sequence of the original function + the passed function.
744      * The resulting function returns the results of the original function.
745      * The passed fcn is called with the parameters of the original function
746      * @param {Function} fcn The function to sequence
747      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
748      * @return {Function} The new function
749      */
750     createSequence : function(fcn, scope){
751         if(typeof fcn != "function"){
752             return this;
753         }
754         var method = this;
755         return function() {
756             var retval = method.apply(this || window, arguments);
757             fcn.apply(scope || this || window, arguments);
758             return retval;
759         };
760     },
761
762     /**
763      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function.
766      * @addon
767      * @param {Function} fcn The function to call before the original
768      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
769      * @return {Function} The new function
770      */
771     createInterceptor : function(fcn, scope){
772         if(typeof fcn != "function"){
773             return this;
774         }
775         var method = this;
776         return function() {
777             fcn.target = this;
778             fcn.method = method;
779             if(fcn.apply(scope || this || window, arguments) === false){
780                 return;
781             }
782             return method.apply(this || window, arguments);
783         };
784     }
785 });
786 /*
787  * Based on:
788  * Ext JS Library 1.1.1
789  * Copyright(c) 2006-2007, Ext JS, LLC.
790  *
791  * Originally Released Under LGPL - original licence link has changed is not relivant.
792  *
793  * Fork - LGPL
794  * <script type="text/javascript">
795  */
796
797 Roo.applyIf(String, {
798     
799     /** @scope String */
800     
801     /**
802      * Escapes the passed string for ' and \
803      * @param {String} string The string to escape
804      * @return {String} The escaped string
805      * @static
806      */
807     escape : function(string) {
808         return string.replace(/('|\\)/g, "\\$1");
809     },
810
811     /**
812      * Pads the left side of a string with a specified character.  This is especially useful
813      * for normalizing number and date strings.  Example usage:
814      * <pre><code>
815 var s = String.leftPad('123', 5, '0');
816 // s now contains the string: '00123'
817 </code></pre>
818      * @param {String} string The original string
819      * @param {Number} size The total length of the output string
820      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
821      * @return {String} The padded string
822      * @static
823      */
824     leftPad : function (val, size, ch) {
825         var result = new String(val);
826         if(ch === null || ch === undefined || ch === '') {
827             ch = " ";
828         }
829         while (result.length < size) {
830             result = ch + result;
831         }
832         return result;
833     },
834
835     /**
836      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
837      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
838      * <pre><code>
839 var cls = 'my-class', text = 'Some text';
840 var s = String.format('<div class="{0}">{1}</div>', cls, text);
841 // s now contains the string: '<div class="my-class">Some text</div>'
842 </code></pre>
843      * @param {String} string The tokenized string to be formatted
844      * @param {String} value1 The value to replace token {0}
845      * @param {String} value2 Etc...
846      * @return {String} The formatted string
847      * @static
848      */
849     format : function(format){
850         var args = Array.prototype.slice.call(arguments, 1);
851         return format.replace(/\{(\d+)\}/g, function(m, i){
852             return Roo.util.Format.htmlEncode(args[i]);
853         });
854     }
855 });
856
857 /**
858  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
859  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
860  * they are already different, the first value passed in is returned.  Note that this method returns the new value
861  * but does not change the current string.
862  * <pre><code>
863 // alternate sort directions
864 sort = sort.toggle('ASC', 'DESC');
865
866 // instead of conditional logic:
867 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
868 </code></pre>
869  * @param {String} value The value to compare to the current string
870  * @param {String} other The new value to use if the string already equals the first value passed in
871  * @return {String} The new value
872  */
873  
874 String.prototype.toggle = function(value, other){
875     return this == value ? other : value;
876 };/*
877  * Based on:
878  * Ext JS Library 1.1.1
879  * Copyright(c) 2006-2007, Ext JS, LLC.
880  *
881  * Originally Released Under LGPL - original licence link has changed is not relivant.
882  *
883  * Fork - LGPL
884  * <script type="text/javascript">
885  */
886
887  /**
888  * @class Number
889  */
890 Roo.applyIf(Number.prototype, {
891     /**
892      * Checks whether or not the current number is within a desired range.  If the number is already within the
893      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
894      * exceeded.  Note that this method returns the constrained value but does not change the current number.
895      * @param {Number} min The minimum number in the range
896      * @param {Number} max The maximum number in the range
897      * @return {Number} The constrained value if outside the range, otherwise the current value
898      */
899     constrain : function(min, max){
900         return Math.min(Math.max(this, min), max);
901     }
902 });/*
903  * Based on:
904  * Ext JS Library 1.1.1
905  * Copyright(c) 2006-2007, Ext JS, LLC.
906  *
907  * Originally Released Under LGPL - original licence link has changed is not relivant.
908  *
909  * Fork - LGPL
910  * <script type="text/javascript">
911  */
912  /**
913  * @class Array
914  */
915 Roo.applyIf(Array.prototype, {
916     /**
917      * Checks whether or not the specified object exists in the array.
918      * @param {Object} o The object to check for
919      * @return {Number} The index of o in the array (or -1 if it is not found)
920      */
921     indexOf : function(o){
922        for (var i = 0, len = this.length; i < len; i++){
923               if(this[i] == o) return i;
924        }
925            return -1;
926     },
927
928     /**
929      * Removes the specified object from the array.  If the object is not found nothing happens.
930      * @param {Object} o The object to remove
931      */
932     remove : function(o){
933        var index = this.indexOf(o);
934        if(index != -1){
935            this.splice(index, 1);
936        }
937     },
938     /**
939      * Map (JS 1.6 compatibility)
940      * @param {Function} function  to call
941      */
942     map : function(fun )
943     {
944         var len = this.length >>> 0;
945         if (typeof fun != "function")
946             throw new TypeError();
947
948         var res = new Array(len);
949         var thisp = arguments[1];
950         for (var i = 0; i < len; i++)
951         {
952             if (i in this)
953                 res[i] = fun.call(thisp, this[i], i, this);
954         }
955
956         return res;
957     }
958     
959 });
960
961
962  /*
963  * Based on:
964  * Ext JS Library 1.1.1
965  * Copyright(c) 2006-2007, Ext JS, LLC.
966  *
967  * Originally Released Under LGPL - original licence link has changed is not relivant.
968  *
969  * Fork - LGPL
970  * <script type="text/javascript">
971  */
972
973 /**
974  * @class Date
975  *
976  * The date parsing and format syntax is a subset of
977  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
978  * supported will provide results equivalent to their PHP versions.
979  *
980  * Following is the list of all currently supported formats:
981  *<pre>
982 Sample date:
983 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
984
985 Format  Output      Description
986 ------  ----------  --------------------------------------------------------------
987   d      10         Day of the month, 2 digits with leading zeros
988   D      Wed        A textual representation of a day, three letters
989   j      10         Day of the month without leading zeros
990   l      Wednesday  A full textual representation of the day of the week
991   S      th         English ordinal day of month suffix, 2 chars (use with j)
992   w      3          Numeric representation of the day of the week
993   z      9          The julian date, or day of the year (0-365)
994   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
995   F      January    A full textual representation of the month
996   m      01         Numeric representation of a month, with leading zeros
997   M      Jan        Month name abbreviation, three letters
998   n      1          Numeric representation of a month, without leading zeros
999   t      31         Number of days in the given month
1000   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1001   Y      2007       A full numeric representation of a year, 4 digits
1002   y      07         A two digit representation of a year
1003   a      pm         Lowercase Ante meridiem and Post meridiem
1004   A      PM         Uppercase Ante meridiem and Post meridiem
1005   g      3          12-hour format of an hour without leading zeros
1006   G      15         24-hour format of an hour without leading zeros
1007   h      03         12-hour format of an hour with leading zeros
1008   H      15         24-hour format of an hour with leading zeros
1009   i      05         Minutes with leading zeros
1010   s      01         Seconds, with leading zeros
1011   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1012   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1013   T      CST        Timezone setting of the machine running the code
1014   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1015 </pre>
1016  *
1017  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1018  * <pre><code>
1019 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1020 document.write(dt.format('Y-m-d'));                         //2007-01-10
1021 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1022 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1023  </code></pre>
1024  *
1025  * Here are some standard date/time patterns that you might find helpful.  They
1026  * are not part of the source of Date.js, but to use them you can simply copy this
1027  * block of code into any script that is included after Date.js and they will also become
1028  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1029  * <pre><code>
1030 Date.patterns = {
1031     ISO8601Long:"Y-m-d H:i:s",
1032     ISO8601Short:"Y-m-d",
1033     ShortDate: "n/j/Y",
1034     LongDate: "l, F d, Y",
1035     FullDateTime: "l, F d, Y g:i:s A",
1036     MonthDay: "F d",
1037     ShortTime: "g:i A",
1038     LongTime: "g:i:s A",
1039     SortableDateTime: "Y-m-d\\TH:i:s",
1040     UniversalSortableDateTime: "Y-m-d H:i:sO",
1041     YearMonth: "F, Y"
1042 };
1043 </code></pre>
1044  *
1045  * Example usage:
1046  * <pre><code>
1047 var dt = new Date();
1048 document.write(dt.format(Date.patterns.ShortDate));
1049  </code></pre>
1050  */
1051
1052 /*
1053  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1054  * They generate precompiled functions from date formats instead of parsing and
1055  * processing the pattern every time you format a date.  These functions are available
1056  * on every Date object (any javascript function).
1057  *
1058  * The original article and download are here:
1059  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1060  *
1061  */
1062  
1063  
1064  // was in core
1065 /**
1066  Returns the number of milliseconds between this date and date
1067  @param {Date} date (optional) Defaults to now
1068  @return {Number} The diff in milliseconds
1069  @member Date getElapsed
1070  */
1071 Date.prototype.getElapsed = function(date) {
1072         return Math.abs((date || new Date()).getTime()-this.getTime());
1073 };
1074 // was in date file..
1075
1076
1077 // private
1078 Date.parseFunctions = {count:0};
1079 // private
1080 Date.parseRegexes = [];
1081 // private
1082 Date.formatFunctions = {count:0};
1083
1084 // private
1085 Date.prototype.dateFormat = function(format) {
1086     if (Date.formatFunctions[format] == null) {
1087         Date.createNewFormat(format);
1088     }
1089     var func = Date.formatFunctions[format];
1090     return this[func]();
1091 };
1092
1093
1094 /**
1095  * Formats a date given the supplied format string
1096  * @param {String} format The format string
1097  * @return {String} The formatted date
1098  * @method
1099  */
1100 Date.prototype.format = Date.prototype.dateFormat;
1101
1102 // private
1103 Date.createNewFormat = function(format) {
1104     var funcName = "format" + Date.formatFunctions.count++;
1105     Date.formatFunctions[format] = funcName;
1106     var code = "Date.prototype." + funcName + " = function(){return ";
1107     var special = false;
1108     var ch = '';
1109     for (var i = 0; i < format.length; ++i) {
1110         ch = format.charAt(i);
1111         if (!special && ch == "\\") {
1112             special = true;
1113         }
1114         else if (special) {
1115             special = false;
1116             code += "'" + String.escape(ch) + "' + ";
1117         }
1118         else {
1119             code += Date.getFormatCode(ch);
1120         }
1121     }
1122     /** eval:var:zzzzzzzzzzzzz */
1123     eval(code.substring(0, code.length - 3) + ";}");
1124 };
1125
1126 // private
1127 Date.getFormatCode = function(character) {
1128     switch (character) {
1129     case "d":
1130         return "String.leftPad(this.getDate(), 2, '0') + ";
1131     case "D":
1132         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1133     case "j":
1134         return "this.getDate() + ";
1135     case "l":
1136         return "Date.dayNames[this.getDay()] + ";
1137     case "S":
1138         return "this.getSuffix() + ";
1139     case "w":
1140         return "this.getDay() + ";
1141     case "z":
1142         return "this.getDayOfYear() + ";
1143     case "W":
1144         return "this.getWeekOfYear() + ";
1145     case "F":
1146         return "Date.monthNames[this.getMonth()] + ";
1147     case "m":
1148         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1149     case "M":
1150         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1151     case "n":
1152         return "(this.getMonth() + 1) + ";
1153     case "t":
1154         return "this.getDaysInMonth() + ";
1155     case "L":
1156         return "(this.isLeapYear() ? 1 : 0) + ";
1157     case "Y":
1158         return "this.getFullYear() + ";
1159     case "y":
1160         return "('' + this.getFullYear()).substring(2, 4) + ";
1161     case "a":
1162         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1163     case "A":
1164         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1165     case "g":
1166         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1167     case "G":
1168         return "this.getHours() + ";
1169     case "h":
1170         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1171     case "H":
1172         return "String.leftPad(this.getHours(), 2, '0') + ";
1173     case "i":
1174         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1175     case "s":
1176         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1177     case "O":
1178         return "this.getGMTOffset() + ";
1179     case "P":
1180         return "this.getGMTColonOffset() + ";
1181     case "T":
1182         return "this.getTimezone() + ";
1183     case "Z":
1184         return "(this.getTimezoneOffset() * -60) + ";
1185     default:
1186         return "'" + String.escape(character) + "' + ";
1187     }
1188 };
1189
1190 /**
1191  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1192  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1193  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1194  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1195  * string or the parse operation will fail.
1196  * Example Usage:
1197 <pre><code>
1198 //dt = Fri May 25 2007 (current date)
1199 var dt = new Date();
1200
1201 //dt = Thu May 25 2006 (today's month/day in 2006)
1202 dt = Date.parseDate("2006", "Y");
1203
1204 //dt = Sun Jan 15 2006 (all date parts specified)
1205 dt = Date.parseDate("2006-1-15", "Y-m-d");
1206
1207 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1208 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1209 </code></pre>
1210  * @param {String} input The unparsed date as a string
1211  * @param {String} format The format the date is in
1212  * @return {Date} The parsed date
1213  * @static
1214  */
1215 Date.parseDate = function(input, format) {
1216     if (Date.parseFunctions[format] == null) {
1217         Date.createParser(format);
1218     }
1219     var func = Date.parseFunctions[format];
1220     return Date[func](input);
1221 };
1222 /**
1223  * @private
1224  */
1225 Date.createParser = function(format) {
1226     var funcName = "parse" + Date.parseFunctions.count++;
1227     var regexNum = Date.parseRegexes.length;
1228     var currentGroup = 1;
1229     Date.parseFunctions[format] = funcName;
1230
1231     var code = "Date." + funcName + " = function(input){\n"
1232         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1233         + "var d = new Date();\n"
1234         + "y = d.getFullYear();\n"
1235         + "m = d.getMonth();\n"
1236         + "d = d.getDate();\n"
1237         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1238         + "if (results && results.length > 0) {";
1239     var regex = "";
1240
1241     var special = false;
1242     var ch = '';
1243     for (var i = 0; i < format.length; ++i) {
1244         ch = format.charAt(i);
1245         if (!special && ch == "\\") {
1246             special = true;
1247         }
1248         else if (special) {
1249             special = false;
1250             regex += String.escape(ch);
1251         }
1252         else {
1253             var obj = Date.formatCodeToRegex(ch, currentGroup);
1254             currentGroup += obj.g;
1255             regex += obj.s;
1256             if (obj.g && obj.c) {
1257                 code += obj.c;
1258             }
1259         }
1260     }
1261
1262     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1263         + "{v = new Date(y, m, d, h, i, s);}\n"
1264         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1265         + "{v = new Date(y, m, d, h, i);}\n"
1266         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1267         + "{v = new Date(y, m, d, h);}\n"
1268         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1269         + "{v = new Date(y, m, d);}\n"
1270         + "else if (y >= 0 && m >= 0)\n"
1271         + "{v = new Date(y, m);}\n"
1272         + "else if (y >= 0)\n"
1273         + "{v = new Date(y);}\n"
1274         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1275         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1276         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1277         + ";}";
1278
1279     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1280     /** eval:var:zzzzzzzzzzzzz */
1281     eval(code);
1282 };
1283
1284 // private
1285 Date.formatCodeToRegex = function(character, currentGroup) {
1286     switch (character) {
1287     case "D":
1288         return {g:0,
1289         c:null,
1290         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1291     case "j":
1292         return {g:1,
1293             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1294             s:"(\\d{1,2})"}; // day of month without leading zeroes
1295     case "d":
1296         return {g:1,
1297             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1298             s:"(\\d{2})"}; // day of month with leading zeroes
1299     case "l":
1300         return {g:0,
1301             c:null,
1302             s:"(?:" + Date.dayNames.join("|") + ")"};
1303     case "S":
1304         return {g:0,
1305             c:null,
1306             s:"(?:st|nd|rd|th)"};
1307     case "w":
1308         return {g:0,
1309             c:null,
1310             s:"\\d"};
1311     case "z":
1312         return {g:0,
1313             c:null,
1314             s:"(?:\\d{1,3})"};
1315     case "W":
1316         return {g:0,
1317             c:null,
1318             s:"(?:\\d{2})"};
1319     case "F":
1320         return {g:1,
1321             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1322             s:"(" + Date.monthNames.join("|") + ")"};
1323     case "M":
1324         return {g:1,
1325             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1326             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1327     case "n":
1328         return {g:1,
1329             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1330             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1331     case "m":
1332         return {g:1,
1333             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1334             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1335     case "t":
1336         return {g:0,
1337             c:null,
1338             s:"\\d{1,2}"};
1339     case "L":
1340         return {g:0,
1341             c:null,
1342             s:"(?:1|0)"};
1343     case "Y":
1344         return {g:1,
1345             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1346             s:"(\\d{4})"};
1347     case "y":
1348         return {g:1,
1349             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1350                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1351             s:"(\\d{1,2})"};
1352     case "a":
1353         return {g:1,
1354             c:"if (results[" + currentGroup + "] == 'am') {\n"
1355                 + "if (h == 12) { h = 0; }\n"
1356                 + "} else { if (h < 12) { h += 12; }}",
1357             s:"(am|pm)"};
1358     case "A":
1359         return {g:1,
1360             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1361                 + "if (h == 12) { h = 0; }\n"
1362                 + "} else { if (h < 12) { h += 12; }}",
1363             s:"(AM|PM)"};
1364     case "g":
1365     case "G":
1366         return {g:1,
1367             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1368             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1369     case "h":
1370     case "H":
1371         return {g:1,
1372             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1373             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1374     case "i":
1375         return {g:1,
1376             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1377             s:"(\\d{2})"};
1378     case "s":
1379         return {g:1,
1380             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1381             s:"(\\d{2})"};
1382     case "O":
1383         return {g:1,
1384             c:[
1385                 "o = results[", currentGroup, "];\n",
1386                 "var sn = o.substring(0,1);\n", // get + / - sign
1387                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1388                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1389                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1390                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1391             ].join(""),
1392             s:"([+\-]\\d{2,4})"};
1393     
1394     
1395     case "P":
1396         return {g:1,
1397                 c:[
1398                    "o = results[", currentGroup, "];\n",
1399                    "var sn = o.substring(0,1);\n",
1400                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1401                    "var mn = o.substring(4,6) % 60;\n",
1402                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1403                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1404             ].join(""),
1405             s:"([+\-]\\d{4})"};
1406     case "T":
1407         return {g:0,
1408             c:null,
1409             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1410     case "Z":
1411         return {g:1,
1412             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1413                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1414             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1415     default:
1416         return {g:0,
1417             c:null,
1418             s:String.escape(character)};
1419     }
1420 };
1421
1422 /**
1423  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1424  * @return {String} The abbreviated timezone name (e.g. 'CST')
1425  */
1426 Date.prototype.getTimezone = function() {
1427     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1428 };
1429
1430 /**
1431  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1432  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1433  */
1434 Date.prototype.getGMTOffset = function() {
1435     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1436         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1437         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1438 };
1439
1440 /**
1441  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1442  * @return {String} 2-characters representing hours and 2-characters representing minutes
1443  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1444  */
1445 Date.prototype.getGMTColonOffset = function() {
1446         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1447                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1448                 + ":"
1449                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1450 }
1451
1452 /**
1453  * Get the numeric day number of the year, adjusted for leap year.
1454  * @return {Number} 0 through 364 (365 in leap years)
1455  */
1456 Date.prototype.getDayOfYear = function() {
1457     var num = 0;
1458     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1459     for (var i = 0; i < this.getMonth(); ++i) {
1460         num += Date.daysInMonth[i];
1461     }
1462     return num + this.getDate() - 1;
1463 };
1464
1465 /**
1466  * Get the string representation of the numeric week number of the year
1467  * (equivalent to the format specifier 'W').
1468  * @return {String} '00' through '52'
1469  */
1470 Date.prototype.getWeekOfYear = function() {
1471     // Skip to Thursday of this week
1472     var now = this.getDayOfYear() + (4 - this.getDay());
1473     // Find the first Thursday of the year
1474     var jan1 = new Date(this.getFullYear(), 0, 1);
1475     var then = (7 - jan1.getDay() + 4);
1476     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1477 };
1478
1479 /**
1480  * Whether or not the current date is in a leap year.
1481  * @return {Boolean} True if the current date is in a leap year, else false
1482  */
1483 Date.prototype.isLeapYear = function() {
1484     var year = this.getFullYear();
1485     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1486 };
1487
1488 /**
1489  * Get the first day of the current month, adjusted for leap year.  The returned value
1490  * is the numeric day index within the week (0-6) which can be used in conjunction with
1491  * the {@link #monthNames} array to retrieve the textual day name.
1492  * Example:
1493  *<pre><code>
1494 var dt = new Date('1/10/2007');
1495 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1496 </code></pre>
1497  * @return {Number} The day number (0-6)
1498  */
1499 Date.prototype.getFirstDayOfMonth = function() {
1500     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1501     return (day < 0) ? (day + 7) : day;
1502 };
1503
1504 /**
1505  * Get the last day of the current month, adjusted for leap year.  The returned value
1506  * is the numeric day index within the week (0-6) which can be used in conjunction with
1507  * the {@link #monthNames} array to retrieve the textual day name.
1508  * Example:
1509  *<pre><code>
1510 var dt = new Date('1/10/2007');
1511 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1512 </code></pre>
1513  * @return {Number} The day number (0-6)
1514  */
1515 Date.prototype.getLastDayOfMonth = function() {
1516     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1517     return (day < 0) ? (day + 7) : day;
1518 };
1519
1520
1521 /**
1522  * Get the first date of this date's month
1523  * @return {Date}
1524  */
1525 Date.prototype.getFirstDateOfMonth = function() {
1526     return new Date(this.getFullYear(), this.getMonth(), 1);
1527 };
1528
1529 /**
1530  * Get the last date of this date's month
1531  * @return {Date}
1532  */
1533 Date.prototype.getLastDateOfMonth = function() {
1534     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1535 };
1536 /**
1537  * Get the number of days in the current month, adjusted for leap year.
1538  * @return {Number} The number of days in the month
1539  */
1540 Date.prototype.getDaysInMonth = function() {
1541     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1542     return Date.daysInMonth[this.getMonth()];
1543 };
1544
1545 /**
1546  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1547  * @return {String} 'st, 'nd', 'rd' or 'th'
1548  */
1549 Date.prototype.getSuffix = function() {
1550     switch (this.getDate()) {
1551         case 1:
1552         case 21:
1553         case 31:
1554             return "st";
1555         case 2:
1556         case 22:
1557             return "nd";
1558         case 3:
1559         case 23:
1560             return "rd";
1561         default:
1562             return "th";
1563     }
1564 };
1565
1566 // private
1567 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1568
1569 /**
1570  * An array of textual month names.
1571  * Override these values for international dates, for example...
1572  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1573  * @type Array
1574  * @static
1575  */
1576 Date.monthNames =
1577    ["January",
1578     "February",
1579     "March",
1580     "April",
1581     "May",
1582     "June",
1583     "July",
1584     "August",
1585     "September",
1586     "October",
1587     "November",
1588     "December"];
1589
1590 /**
1591  * An array of textual day names.
1592  * Override these values for international dates, for example...
1593  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1594  * @type Array
1595  * @static
1596  */
1597 Date.dayNames =
1598    ["Sunday",
1599     "Monday",
1600     "Tuesday",
1601     "Wednesday",
1602     "Thursday",
1603     "Friday",
1604     "Saturday"];
1605
1606 // private
1607 Date.y2kYear = 50;
1608 // private
1609 Date.monthNumbers = {
1610     Jan:0,
1611     Feb:1,
1612     Mar:2,
1613     Apr:3,
1614     May:4,
1615     Jun:5,
1616     Jul:6,
1617     Aug:7,
1618     Sep:8,
1619     Oct:9,
1620     Nov:10,
1621     Dec:11};
1622
1623 /**
1624  * Creates and returns a new Date instance with the exact same date value as the called instance.
1625  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1626  * variable will also be changed.  When the intention is to create a new variable that will not
1627  * modify the original instance, you should create a clone.
1628  *
1629  * Example of correctly cloning a date:
1630  * <pre><code>
1631 //wrong way:
1632 var orig = new Date('10/1/2006');
1633 var copy = orig;
1634 copy.setDate(5);
1635 document.write(orig);  //returns 'Thu Oct 05 2006'!
1636
1637 //correct way:
1638 var orig = new Date('10/1/2006');
1639 var copy = orig.clone();
1640 copy.setDate(5);
1641 document.write(orig);  //returns 'Thu Oct 01 2006'
1642 </code></pre>
1643  * @return {Date} The new Date instance
1644  */
1645 Date.prototype.clone = function() {
1646         return new Date(this.getTime());
1647 };
1648
1649 /**
1650  * Clears any time information from this date
1651  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1652  @return {Date} this or the clone
1653  */
1654 Date.prototype.clearTime = function(clone){
1655     if(clone){
1656         return this.clone().clearTime();
1657     }
1658     this.setHours(0);
1659     this.setMinutes(0);
1660     this.setSeconds(0);
1661     this.setMilliseconds(0);
1662     return this;
1663 };
1664
1665 // private
1666 // safari setMonth is broken
1667 if(Roo.isSafari){
1668     Date.brokenSetMonth = Date.prototype.setMonth;
1669         Date.prototype.setMonth = function(num){
1670                 if(num <= -1){
1671                         var n = Math.ceil(-num);
1672                         var back_year = Math.ceil(n/12);
1673                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1674                         this.setFullYear(this.getFullYear() - back_year);
1675                         return Date.brokenSetMonth.call(this, month);
1676                 } else {
1677                         return Date.brokenSetMonth.apply(this, arguments);
1678                 }
1679         };
1680 }
1681
1682 /** Date interval constant 
1683 * @static 
1684 * @type String */
1685 Date.MILLI = "ms";
1686 /** Date interval constant 
1687 * @static 
1688 * @type String */
1689 Date.SECOND = "s";
1690 /** Date interval constant 
1691 * @static 
1692 * @type String */
1693 Date.MINUTE = "mi";
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.HOUR = "h";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.DAY = "d";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MONTH = "mo";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.YEAR = "y";
1710
1711 /**
1712  * Provides a convenient method of performing basic date arithmetic.  This method
1713  * does not modify the Date instance being called - it creates and returns
1714  * a new Date instance containing the resulting date value.
1715  *
1716  * Examples:
1717  * <pre><code>
1718 //Basic usage:
1719 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1720 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1721
1722 //Negative values will subtract correctly:
1723 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1724 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1725
1726 //You can even chain several calls together in one line!
1727 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1728 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1729  </code></pre>
1730  *
1731  * @param {String} interval   A valid date interval enum value
1732  * @param {Number} value      The amount to add to the current date
1733  * @return {Date} The new Date instance
1734  */
1735 Date.prototype.add = function(interval, value){
1736   var d = this.clone();
1737   if (!interval || value === 0) return d;
1738   switch(interval.toLowerCase()){
1739     case Date.MILLI:
1740       d.setMilliseconds(this.getMilliseconds() + value);
1741       break;
1742     case Date.SECOND:
1743       d.setSeconds(this.getSeconds() + value);
1744       break;
1745     case Date.MINUTE:
1746       d.setMinutes(this.getMinutes() + value);
1747       break;
1748     case Date.HOUR:
1749       d.setHours(this.getHours() + value);
1750       break;
1751     case Date.DAY:
1752       d.setDate(this.getDate() + value);
1753       break;
1754     case Date.MONTH:
1755       var day = this.getDate();
1756       if(day > 28){
1757           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1758       }
1759       d.setDate(day);
1760       d.setMonth(this.getMonth() + value);
1761       break;
1762     case Date.YEAR:
1763       d.setFullYear(this.getFullYear() + value);
1764       break;
1765   }
1766   return d;
1767 };
1768 /*
1769  * Based on:
1770  * Ext JS Library 1.1.1
1771  * Copyright(c) 2006-2007, Ext JS, LLC.
1772  *
1773  * Originally Released Under LGPL - original licence link has changed is not relivant.
1774  *
1775  * Fork - LGPL
1776  * <script type="text/javascript">
1777  */
1778
1779 /**
1780  * @class Roo.lib.Dom
1781  * @static
1782  * 
1783  * Dom utils (from YIU afaik)
1784  * 
1785  **/
1786 Roo.lib.Dom = {
1787     /**
1788      * Get the view width
1789      * @param {Boolean} full True will get the full document, otherwise it's the view width
1790      * @return {Number} The width
1791      */
1792      
1793     getViewWidth : function(full) {
1794         return full ? this.getDocumentWidth() : this.getViewportWidth();
1795     },
1796     /**
1797      * Get the view height
1798      * @param {Boolean} full True will get the full document, otherwise it's the view height
1799      * @return {Number} The height
1800      */
1801     getViewHeight : function(full) {
1802         return full ? this.getDocumentHeight() : this.getViewportHeight();
1803     },
1804
1805     getDocumentHeight: function() {
1806         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1807         return Math.max(scrollHeight, this.getViewportHeight());
1808     },
1809
1810     getDocumentWidth: function() {
1811         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1812         return Math.max(scrollWidth, this.getViewportWidth());
1813     },
1814
1815     getViewportHeight: function() {
1816         var height = self.innerHeight;
1817         var mode = document.compatMode;
1818
1819         if ((mode || Roo.isIE) && !Roo.isOpera) {
1820             height = (mode == "CSS1Compat") ?
1821                      document.documentElement.clientHeight :
1822                      document.body.clientHeight;
1823         }
1824
1825         return height;
1826     },
1827
1828     getViewportWidth: function() {
1829         var width = self.innerWidth;
1830         var mode = document.compatMode;
1831
1832         if (mode || Roo.isIE) {
1833             width = (mode == "CSS1Compat") ?
1834                     document.documentElement.clientWidth :
1835                     document.body.clientWidth;
1836         }
1837         return width;
1838     },
1839
1840     isAncestor : function(p, c) {
1841         p = Roo.getDom(p);
1842         c = Roo.getDom(c);
1843         if (!p || !c) {
1844             return false;
1845         }
1846
1847         if (p.contains && !Roo.isSafari) {
1848             return p.contains(c);
1849         } else if (p.compareDocumentPosition) {
1850             return !!(p.compareDocumentPosition(c) & 16);
1851         } else {
1852             var parent = c.parentNode;
1853             while (parent) {
1854                 if (parent == p) {
1855                     return true;
1856                 }
1857                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1858                     return false;
1859                 }
1860                 parent = parent.parentNode;
1861             }
1862             return false;
1863         }
1864     },
1865
1866     getRegion : function(el) {
1867         return Roo.lib.Region.getRegion(el);
1868     },
1869
1870     getY : function(el) {
1871         return this.getXY(el)[1];
1872     },
1873
1874     getX : function(el) {
1875         return this.getXY(el)[0];
1876     },
1877
1878     getXY : function(el) {
1879         var p, pe, b, scroll, bd = document.body;
1880         el = Roo.getDom(el);
1881         var fly = Roo.lib.AnimBase.fly;
1882         if (el.getBoundingClientRect) {
1883             b = el.getBoundingClientRect();
1884             scroll = fly(document).getScroll();
1885             return [b.left + scroll.left, b.top + scroll.top];
1886         }
1887         var x = 0, y = 0;
1888
1889         p = el;
1890
1891         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1892
1893         while (p) {
1894
1895             x += p.offsetLeft;
1896             y += p.offsetTop;
1897
1898             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1899                 hasAbsolute = true;
1900             }
1901
1902             if (Roo.isGecko) {
1903                 pe = fly(p);
1904
1905                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1906                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1907
1908
1909                 x += bl;
1910                 y += bt;
1911
1912
1913                 if (p != el && pe.getStyle('overflow') != 'visible') {
1914                     x += bl;
1915                     y += bt;
1916                 }
1917             }
1918             p = p.offsetParent;
1919         }
1920
1921         if (Roo.isSafari && hasAbsolute) {
1922             x -= bd.offsetLeft;
1923             y -= bd.offsetTop;
1924         }
1925
1926         if (Roo.isGecko && !hasAbsolute) {
1927             var dbd = fly(bd);
1928             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1929             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1930         }
1931
1932         p = el.parentNode;
1933         while (p && p != bd) {
1934             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1935                 x -= p.scrollLeft;
1936                 y -= p.scrollTop;
1937             }
1938             p = p.parentNode;
1939         }
1940         return [x, y];
1941     },
1942  
1943   
1944
1945
1946     setXY : function(el, xy) {
1947         el = Roo.fly(el, '_setXY');
1948         el.position();
1949         var pts = el.translatePoints(xy);
1950         if (xy[0] !== false) {
1951             el.dom.style.left = pts.left + "px";
1952         }
1953         if (xy[1] !== false) {
1954             el.dom.style.top = pts.top + "px";
1955         }
1956     },
1957
1958     setX : function(el, x) {
1959         this.setXY(el, [x, false]);
1960     },
1961
1962     setY : function(el, y) {
1963         this.setXY(el, [false, y]);
1964     }
1965 };
1966 /*
1967  * Portions of this file are based on pieces of Yahoo User Interface Library
1968  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1969  * YUI licensed under the BSD License:
1970  * http://developer.yahoo.net/yui/license.txt
1971  * <script type="text/javascript">
1972  *
1973  */
1974
1975 Roo.lib.Event = function() {
1976     var loadComplete = false;
1977     var listeners = [];
1978     var unloadListeners = [];
1979     var retryCount = 0;
1980     var onAvailStack = [];
1981     var counter = 0;
1982     var lastError = null;
1983
1984     return {
1985         POLL_RETRYS: 200,
1986         POLL_INTERVAL: 20,
1987         EL: 0,
1988         TYPE: 1,
1989         FN: 2,
1990         WFN: 3,
1991         OBJ: 3,
1992         ADJ_SCOPE: 4,
1993         _interval: null,
1994
1995         startInterval: function() {
1996             if (!this._interval) {
1997                 var self = this;
1998                 var callback = function() {
1999                     self._tryPreloadAttach();
2000                 };
2001                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2002
2003             }
2004         },
2005
2006         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2007             onAvailStack.push({ id:         p_id,
2008                 fn:         p_fn,
2009                 obj:        p_obj,
2010                 override:   p_override,
2011                 checkReady: false    });
2012
2013             retryCount = this.POLL_RETRYS;
2014             this.startInterval();
2015         },
2016
2017
2018         addListener: function(el, eventName, fn) {
2019             el = Roo.getDom(el);
2020             if (!el || !fn) {
2021                 return false;
2022             }
2023
2024             if ("unload" == eventName) {
2025                 unloadListeners[unloadListeners.length] =
2026                 [el, eventName, fn];
2027                 return true;
2028             }
2029
2030             var wrappedFn = function(e) {
2031                 return fn(Roo.lib.Event.getEvent(e));
2032             };
2033
2034             var li = [el, eventName, fn, wrappedFn];
2035
2036             var index = listeners.length;
2037             listeners[index] = li;
2038
2039             this.doAdd(el, eventName, wrappedFn, false);
2040             return true;
2041
2042         },
2043
2044
2045         removeListener: function(el, eventName, fn) {
2046             var i, len;
2047
2048             el = Roo.getDom(el);
2049
2050             if(!fn) {
2051                 return this.purgeElement(el, false, eventName);
2052             }
2053
2054
2055             if ("unload" == eventName) {
2056
2057                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2058                     var li = unloadListeners[i];
2059                     if (li &&
2060                         li[0] == el &&
2061                         li[1] == eventName &&
2062                         li[2] == fn) {
2063                         unloadListeners.splice(i, 1);
2064                         return true;
2065                     }
2066                 }
2067
2068                 return false;
2069             }
2070
2071             var cacheItem = null;
2072
2073
2074             var index = arguments[3];
2075
2076             if ("undefined" == typeof index) {
2077                 index = this._getCacheIndex(el, eventName, fn);
2078             }
2079
2080             if (index >= 0) {
2081                 cacheItem = listeners[index];
2082             }
2083
2084             if (!el || !cacheItem) {
2085                 return false;
2086             }
2087
2088             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2089
2090             delete listeners[index][this.WFN];
2091             delete listeners[index][this.FN];
2092             listeners.splice(index, 1);
2093
2094             return true;
2095
2096         },
2097
2098
2099         getTarget: function(ev, resolveTextNode) {
2100             ev = ev.browserEvent || ev;
2101             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2102             var t = ev.target || ev.srcElement;
2103             return this.resolveTextNode(t);
2104         },
2105
2106
2107         resolveTextNode: function(node) {
2108             if (Roo.isSafari && node && 3 == node.nodeType) {
2109                 return node.parentNode;
2110             } else {
2111                 return node;
2112             }
2113         },
2114
2115
2116         getPageX: function(ev) {
2117             ev = ev.browserEvent || ev;
2118             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2119             var x = ev.pageX;
2120             if (!x && 0 !== x) {
2121                 x = ev.clientX || 0;
2122
2123                 if (Roo.isIE) {
2124                     x += this.getScroll()[1];
2125                 }
2126             }
2127
2128             return x;
2129         },
2130
2131
2132         getPageY: function(ev) {
2133             ev = ev.browserEvent || ev;
2134             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2135             var y = ev.pageY;
2136             if (!y && 0 !== y) {
2137                 y = ev.clientY || 0;
2138
2139                 if (Roo.isIE) {
2140                     y += this.getScroll()[0];
2141                 }
2142             }
2143
2144
2145             return y;
2146         },
2147
2148
2149         getXY: function(ev) {
2150             ev = ev.browserEvent || ev;
2151             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2152             return [this.getPageX(ev), this.getPageY(ev)];
2153         },
2154
2155
2156         getRelatedTarget: function(ev) {
2157             ev = ev.browserEvent || ev;
2158             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2159             var t = ev.relatedTarget;
2160             if (!t) {
2161                 if (ev.type == "mouseout") {
2162                     t = ev.toElement;
2163                 } else if (ev.type == "mouseover") {
2164                     t = ev.fromElement;
2165                 }
2166             }
2167
2168             return this.resolveTextNode(t);
2169         },
2170
2171
2172         getTime: function(ev) {
2173             ev = ev.browserEvent || ev;
2174             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2175             if (!ev.time) {
2176                 var t = new Date().getTime();
2177                 try {
2178                     ev.time = t;
2179                 } catch(ex) {
2180                     this.lastError = ex;
2181                     return t;
2182                 }
2183             }
2184
2185             return ev.time;
2186         },
2187
2188
2189         stopEvent: function(ev) {
2190             this.stopPropagation(ev);
2191             this.preventDefault(ev);
2192         },
2193
2194
2195         stopPropagation: function(ev) {
2196             ev = ev.browserEvent || ev;
2197             if (ev.stopPropagation) {
2198                 ev.stopPropagation();
2199             } else {
2200                 ev.cancelBubble = true;
2201             }
2202         },
2203
2204
2205         preventDefault: function(ev) {
2206             ev = ev.browserEvent || ev;
2207             if(ev.preventDefault) {
2208                 ev.preventDefault();
2209             } else {
2210                 ev.returnValue = false;
2211             }
2212         },
2213
2214
2215         getEvent: function(e) {
2216             var ev = e || window.event;
2217             if (!ev) {
2218                 var c = this.getEvent.caller;
2219                 while (c) {
2220                     ev = c.arguments[0];
2221                     if (ev && Event == ev.constructor) {
2222                         break;
2223                     }
2224                     c = c.caller;
2225                 }
2226             }
2227             return ev;
2228         },
2229
2230
2231         getCharCode: function(ev) {
2232             ev = ev.browserEvent || ev;
2233             return ev.charCode || ev.keyCode || 0;
2234         },
2235
2236
2237         _getCacheIndex: function(el, eventName, fn) {
2238             for (var i = 0,len = listeners.length; i < len; ++i) {
2239                 var li = listeners[i];
2240                 if (li &&
2241                     li[this.FN] == fn &&
2242                     li[this.EL] == el &&
2243                     li[this.TYPE] == eventName) {
2244                     return i;
2245                 }
2246             }
2247
2248             return -1;
2249         },
2250
2251
2252         elCache: {},
2253
2254
2255         getEl: function(id) {
2256             return document.getElementById(id);
2257         },
2258
2259
2260         clearCache: function() {
2261         },
2262
2263
2264         _load: function(e) {
2265             loadComplete = true;
2266             var EU = Roo.lib.Event;
2267
2268
2269             if (Roo.isIE) {
2270                 EU.doRemove(window, "load", EU._load);
2271             }
2272         },
2273
2274
2275         _tryPreloadAttach: function() {
2276
2277             if (this.locked) {
2278                 return false;
2279             }
2280
2281             this.locked = true;
2282
2283
2284             var tryAgain = !loadComplete;
2285             if (!tryAgain) {
2286                 tryAgain = (retryCount > 0);
2287             }
2288
2289
2290             var notAvail = [];
2291             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2292                 var item = onAvailStack[i];
2293                 if (item) {
2294                     var el = this.getEl(item.id);
2295
2296                     if (el) {
2297                         if (!item.checkReady ||
2298                             loadComplete ||
2299                             el.nextSibling ||
2300                             (document && document.body)) {
2301
2302                             var scope = el;
2303                             if (item.override) {
2304                                 if (item.override === true) {
2305                                     scope = item.obj;
2306                                 } else {
2307                                     scope = item.override;
2308                                 }
2309                             }
2310                             item.fn.call(scope, item.obj);
2311                             onAvailStack[i] = null;
2312                         }
2313                     } else {
2314                         notAvail.push(item);
2315                     }
2316                 }
2317             }
2318
2319             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2320
2321             if (tryAgain) {
2322
2323                 this.startInterval();
2324             } else {
2325                 clearInterval(this._interval);
2326                 this._interval = null;
2327             }
2328
2329             this.locked = false;
2330
2331             return true;
2332
2333         },
2334
2335
2336         purgeElement: function(el, recurse, eventName) {
2337             var elListeners = this.getListeners(el, eventName);
2338             if (elListeners) {
2339                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2340                     var l = elListeners[i];
2341                     this.removeListener(el, l.type, l.fn);
2342                 }
2343             }
2344
2345             if (recurse && el && el.childNodes) {
2346                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2347                     this.purgeElement(el.childNodes[i], recurse, eventName);
2348                 }
2349             }
2350         },
2351
2352
2353         getListeners: function(el, eventName) {
2354             var results = [], searchLists;
2355             if (!eventName) {
2356                 searchLists = [listeners, unloadListeners];
2357             } else if (eventName == "unload") {
2358                 searchLists = [unloadListeners];
2359             } else {
2360                 searchLists = [listeners];
2361             }
2362
2363             for (var j = 0; j < searchLists.length; ++j) {
2364                 var searchList = searchLists[j];
2365                 if (searchList && searchList.length > 0) {
2366                     for (var i = 0,len = searchList.length; i < len; ++i) {
2367                         var l = searchList[i];
2368                         if (l && l[this.EL] === el &&
2369                             (!eventName || eventName === l[this.TYPE])) {
2370                             results.push({
2371                                 type:   l[this.TYPE],
2372                                 fn:     l[this.FN],
2373                                 obj:    l[this.OBJ],
2374                                 adjust: l[this.ADJ_SCOPE],
2375                                 index:  i
2376                             });
2377                         }
2378                     }
2379                 }
2380             }
2381
2382             return (results.length) ? results : null;
2383         },
2384
2385
2386         _unload: function(e) {
2387
2388             var EU = Roo.lib.Event, i, j, l, len, index;
2389
2390             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2391                 l = unloadListeners[i];
2392                 if (l) {
2393                     var scope = window;
2394                     if (l[EU.ADJ_SCOPE]) {
2395                         if (l[EU.ADJ_SCOPE] === true) {
2396                             scope = l[EU.OBJ];
2397                         } else {
2398                             scope = l[EU.ADJ_SCOPE];
2399                         }
2400                     }
2401                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2402                     unloadListeners[i] = null;
2403                     l = null;
2404                     scope = null;
2405                 }
2406             }
2407
2408             unloadListeners = null;
2409
2410             if (listeners && listeners.length > 0) {
2411                 j = listeners.length;
2412                 while (j) {
2413                     index = j - 1;
2414                     l = listeners[index];
2415                     if (l) {
2416                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2417                                 l[EU.FN], index);
2418                     }
2419                     j = j - 1;
2420                 }
2421                 l = null;
2422
2423                 EU.clearCache();
2424             }
2425
2426             EU.doRemove(window, "unload", EU._unload);
2427
2428         },
2429
2430
2431         getScroll: function() {
2432             var dd = document.documentElement, db = document.body;
2433             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2434                 return [dd.scrollTop, dd.scrollLeft];
2435             } else if (db) {
2436                 return [db.scrollTop, db.scrollLeft];
2437             } else {
2438                 return [0, 0];
2439             }
2440         },
2441
2442
2443         doAdd: function () {
2444             if (window.addEventListener) {
2445                 return function(el, eventName, fn, capture) {
2446                     el.addEventListener(eventName, fn, (capture));
2447                 };
2448             } else if (window.attachEvent) {
2449                 return function(el, eventName, fn, capture) {
2450                     el.attachEvent("on" + eventName, fn);
2451                 };
2452             } else {
2453                 return function() {
2454                 };
2455             }
2456         }(),
2457
2458
2459         doRemove: function() {
2460             if (window.removeEventListener) {
2461                 return function (el, eventName, fn, capture) {
2462                     el.removeEventListener(eventName, fn, (capture));
2463                 };
2464             } else if (window.detachEvent) {
2465                 return function (el, eventName, fn) {
2466                     el.detachEvent("on" + eventName, fn);
2467                 };
2468             } else {
2469                 return function() {
2470                 };
2471             }
2472         }()
2473     };
2474     
2475 }();
2476 (function() {     
2477    
2478     var E = Roo.lib.Event;
2479     E.on = E.addListener;
2480     E.un = E.removeListener;
2481
2482     if (document && document.body) {
2483         E._load();
2484     } else {
2485         E.doAdd(window, "load", E._load);
2486     }
2487     E.doAdd(window, "unload", E._unload);
2488     E._tryPreloadAttach();
2489 })();
2490
2491 /*
2492  * Portions of this file are based on pieces of Yahoo User Interface Library
2493  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2494  * YUI licensed under the BSD License:
2495  * http://developer.yahoo.net/yui/license.txt
2496  * <script type="text/javascript">
2497  *
2498  */
2499
2500 (function() {
2501     /**
2502      * @class Roo.lib.Ajax
2503      *
2504      */
2505     Roo.lib.Ajax = {
2506         /**
2507          * @static 
2508          */
2509         request : function(method, uri, cb, data, options) {
2510             if(options){
2511                 var hs = options.headers;
2512                 if(hs){
2513                     for(var h in hs){
2514                         if(hs.hasOwnProperty(h)){
2515                             this.initHeader(h, hs[h], false);
2516                         }
2517                     }
2518                 }
2519                 if(options.xmlData){
2520                     this.initHeader('Content-Type', 'text/xml', false);
2521                     method = 'POST';
2522                     data = options.xmlData;
2523                 }
2524             }
2525
2526             return this.asyncRequest(method, uri, cb, data);
2527         },
2528
2529         serializeForm : function(form) {
2530             if(typeof form == 'string') {
2531                 form = (document.getElementById(form) || document.forms[form]);
2532             }
2533
2534             var el, name, val, disabled, data = '', hasSubmit = false;
2535             for (var i = 0; i < form.elements.length; i++) {
2536                 el = form.elements[i];
2537                 disabled = form.elements[i].disabled;
2538                 name = form.elements[i].name;
2539                 val = form.elements[i].value;
2540
2541                 if (!disabled && name){
2542                     switch (el.type)
2543                             {
2544                         case 'select-one':
2545                         case 'select-multiple':
2546                             for (var j = 0; j < el.options.length; j++) {
2547                                 if (el.options[j].selected) {
2548                                     if (Roo.isIE) {
2549                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2550                                     }
2551                                     else {
2552                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2553                                     }
2554                                 }
2555                             }
2556                             break;
2557                         case 'radio':
2558                         case 'checkbox':
2559                             if (el.checked) {
2560                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2561                             }
2562                             break;
2563                         case 'file':
2564
2565                         case undefined:
2566
2567                         case 'reset':
2568
2569                         case 'button':
2570
2571                             break;
2572                         case 'submit':
2573                             if(hasSubmit == false) {
2574                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2575                                 hasSubmit = true;
2576                             }
2577                             break;
2578                         default:
2579                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2580                             break;
2581                     }
2582                 }
2583             }
2584             data = data.substr(0, data.length - 1);
2585             return data;
2586         },
2587
2588         headers:{},
2589
2590         hasHeaders:false,
2591
2592         useDefaultHeader:true,
2593
2594         defaultPostHeader:'application/x-www-form-urlencoded',
2595
2596         useDefaultXhrHeader:true,
2597
2598         defaultXhrHeader:'XMLHttpRequest',
2599
2600         hasDefaultHeaders:true,
2601
2602         defaultHeaders:{},
2603
2604         poll:{},
2605
2606         timeout:{},
2607
2608         pollInterval:50,
2609
2610         transactionId:0,
2611
2612         setProgId:function(id)
2613         {
2614             this.activeX.unshift(id);
2615         },
2616
2617         setDefaultPostHeader:function(b)
2618         {
2619             this.useDefaultHeader = b;
2620         },
2621
2622         setDefaultXhrHeader:function(b)
2623         {
2624             this.useDefaultXhrHeader = b;
2625         },
2626
2627         setPollingInterval:function(i)
2628         {
2629             if (typeof i == 'number' && isFinite(i)) {
2630                 this.pollInterval = i;
2631             }
2632         },
2633
2634         createXhrObject:function(transactionId)
2635         {
2636             var obj,http;
2637             try
2638             {
2639
2640                 http = new XMLHttpRequest();
2641
2642                 obj = { conn:http, tId:transactionId };
2643             }
2644             catch(e)
2645             {
2646                 for (var i = 0; i < this.activeX.length; ++i) {
2647                     try
2648                     {
2649
2650                         http = new ActiveXObject(this.activeX[i]);
2651
2652                         obj = { conn:http, tId:transactionId };
2653                         break;
2654                     }
2655                     catch(e) {
2656                     }
2657                 }
2658             }
2659             finally
2660             {
2661                 return obj;
2662             }
2663         },
2664
2665         getConnectionObject:function()
2666         {
2667             var o;
2668             var tId = this.transactionId;
2669
2670             try
2671             {
2672                 o = this.createXhrObject(tId);
2673                 if (o) {
2674                     this.transactionId++;
2675                 }
2676             }
2677             catch(e) {
2678             }
2679             finally
2680             {
2681                 return o;
2682             }
2683         },
2684
2685         asyncRequest:function(method, uri, callback, postData)
2686         {
2687             var o = this.getConnectionObject();
2688
2689             if (!o) {
2690                 return null;
2691             }
2692             else {
2693                 o.conn.open(method, uri, true);
2694
2695                 if (this.useDefaultXhrHeader) {
2696                     if (!this.defaultHeaders['X-Requested-With']) {
2697                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2698                     }
2699                 }
2700
2701                 if(postData && this.useDefaultHeader){
2702                     this.initHeader('Content-Type', this.defaultPostHeader);
2703                 }
2704
2705                  if (this.hasDefaultHeaders || this.hasHeaders) {
2706                     this.setHeader(o);
2707                 }
2708
2709                 this.handleReadyState(o, callback);
2710                 o.conn.send(postData || null);
2711
2712                 return o;
2713             }
2714         },
2715
2716         handleReadyState:function(o, callback)
2717         {
2718             var oConn = this;
2719
2720             if (callback && callback.timeout) {
2721                 
2722                 this.timeout[o.tId] = window.setTimeout(function() {
2723                     oConn.abort(o, callback, true);
2724                 }, callback.timeout);
2725             }
2726
2727             this.poll[o.tId] = window.setInterval(
2728                     function() {
2729                         if (o.conn && o.conn.readyState == 4) {
2730                             window.clearInterval(oConn.poll[o.tId]);
2731                             delete oConn.poll[o.tId];
2732
2733                             if(callback && callback.timeout) {
2734                                 window.clearTimeout(oConn.timeout[o.tId]);
2735                                 delete oConn.timeout[o.tId];
2736                             }
2737
2738                             oConn.handleTransactionResponse(o, callback);
2739                         }
2740                     }
2741                     , this.pollInterval);
2742         },
2743
2744         handleTransactionResponse:function(o, callback, isAbort)
2745         {
2746
2747             if (!callback) {
2748                 this.releaseObject(o);
2749                 return;
2750             }
2751
2752             var httpStatus, responseObject;
2753
2754             try
2755             {
2756                 if (o.conn.status !== undefined && o.conn.status != 0) {
2757                     httpStatus = o.conn.status;
2758                 }
2759                 else {
2760                     httpStatus = 13030;
2761                 }
2762             }
2763             catch(e) {
2764
2765
2766                 httpStatus = 13030;
2767             }
2768
2769             if (httpStatus >= 200 && httpStatus < 300) {
2770                 responseObject = this.createResponseObject(o, callback.argument);
2771                 if (callback.success) {
2772                     if (!callback.scope) {
2773                         callback.success(responseObject);
2774                     }
2775                     else {
2776
2777
2778                         callback.success.apply(callback.scope, [responseObject]);
2779                     }
2780                 }
2781             }
2782             else {
2783                 switch (httpStatus) {
2784
2785                     case 12002:
2786                     case 12029:
2787                     case 12030:
2788                     case 12031:
2789                     case 12152:
2790                     case 13030:
2791                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2792                         if (callback.failure) {
2793                             if (!callback.scope) {
2794                                 callback.failure(responseObject);
2795                             }
2796                             else {
2797                                 callback.failure.apply(callback.scope, [responseObject]);
2798                             }
2799                         }
2800                         break;
2801                     default:
2802                         responseObject = this.createResponseObject(o, callback.argument);
2803                         if (callback.failure) {
2804                             if (!callback.scope) {
2805                                 callback.failure(responseObject);
2806                             }
2807                             else {
2808                                 callback.failure.apply(callback.scope, [responseObject]);
2809                             }
2810                         }
2811                 }
2812             }
2813
2814             this.releaseObject(o);
2815             responseObject = null;
2816         },
2817
2818         createResponseObject:function(o, callbackArg)
2819         {
2820             var obj = {};
2821             var headerObj = {};
2822
2823             try
2824             {
2825                 var headerStr = o.conn.getAllResponseHeaders();
2826                 var header = headerStr.split('\n');
2827                 for (var i = 0; i < header.length; i++) {
2828                     var delimitPos = header[i].indexOf(':');
2829                     if (delimitPos != -1) {
2830                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2831                     }
2832                 }
2833             }
2834             catch(e) {
2835             }
2836
2837             obj.tId = o.tId;
2838             obj.status = o.conn.status;
2839             obj.statusText = o.conn.statusText;
2840             obj.getResponseHeader = headerObj;
2841             obj.getAllResponseHeaders = headerStr;
2842             obj.responseText = o.conn.responseText;
2843             obj.responseXML = o.conn.responseXML;
2844
2845             if (typeof callbackArg !== undefined) {
2846                 obj.argument = callbackArg;
2847             }
2848
2849             return obj;
2850         },
2851
2852         createExceptionObject:function(tId, callbackArg, isAbort)
2853         {
2854             var COMM_CODE = 0;
2855             var COMM_ERROR = 'communication failure';
2856             var ABORT_CODE = -1;
2857             var ABORT_ERROR = 'transaction aborted';
2858
2859             var obj = {};
2860
2861             obj.tId = tId;
2862             if (isAbort) {
2863                 obj.status = ABORT_CODE;
2864                 obj.statusText = ABORT_ERROR;
2865             }
2866             else {
2867                 obj.status = COMM_CODE;
2868                 obj.statusText = COMM_ERROR;
2869             }
2870
2871             if (callbackArg) {
2872                 obj.argument = callbackArg;
2873             }
2874
2875             return obj;
2876         },
2877
2878         initHeader:function(label, value, isDefault)
2879         {
2880             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2881
2882             if (headerObj[label] === undefined) {
2883                 headerObj[label] = value;
2884             }
2885             else {
2886
2887
2888                 headerObj[label] = value + "," + headerObj[label];
2889             }
2890
2891             if (isDefault) {
2892                 this.hasDefaultHeaders = true;
2893             }
2894             else {
2895                 this.hasHeaders = true;
2896             }
2897         },
2898
2899
2900         setHeader:function(o)
2901         {
2902             if (this.hasDefaultHeaders) {
2903                 for (var prop in this.defaultHeaders) {
2904                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2905                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2906                     }
2907                 }
2908             }
2909
2910             if (this.hasHeaders) {
2911                 for (var prop in this.headers) {
2912                     if (this.headers.hasOwnProperty(prop)) {
2913                         o.conn.setRequestHeader(prop, this.headers[prop]);
2914                     }
2915                 }
2916                 this.headers = {};
2917                 this.hasHeaders = false;
2918             }
2919         },
2920
2921         resetDefaultHeaders:function() {
2922             delete this.defaultHeaders;
2923             this.defaultHeaders = {};
2924             this.hasDefaultHeaders = false;
2925         },
2926
2927         abort:function(o, callback, isTimeout)
2928         {
2929             if(this.isCallInProgress(o)) {
2930                 o.conn.abort();
2931                 window.clearInterval(this.poll[o.tId]);
2932                 delete this.poll[o.tId];
2933                 if (isTimeout) {
2934                     delete this.timeout[o.tId];
2935                 }
2936
2937                 this.handleTransactionResponse(o, callback, true);
2938
2939                 return true;
2940             }
2941             else {
2942                 return false;
2943             }
2944         },
2945
2946
2947         isCallInProgress:function(o)
2948         {
2949             if (o && o.conn) {
2950                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2951             }
2952             else {
2953
2954                 return false;
2955             }
2956         },
2957
2958
2959         releaseObject:function(o)
2960         {
2961
2962             o.conn = null;
2963
2964             o = null;
2965         },
2966
2967         activeX:[
2968         'MSXML2.XMLHTTP.3.0',
2969         'MSXML2.XMLHTTP',
2970         'Microsoft.XMLHTTP'
2971         ]
2972
2973
2974     };
2975 })();/*
2976  * Portions of this file are based on pieces of Yahoo User Interface Library
2977  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2978  * YUI licensed under the BSD License:
2979  * http://developer.yahoo.net/yui/license.txt
2980  * <script type="text/javascript">
2981  *
2982  */
2983
2984 Roo.lib.Region = function(t, r, b, l) {
2985     this.top = t;
2986     this[1] = t;
2987     this.right = r;
2988     this.bottom = b;
2989     this.left = l;
2990     this[0] = l;
2991 };
2992
2993
2994 Roo.lib.Region.prototype = {
2995     contains : function(region) {
2996         return ( region.left >= this.left &&
2997                  region.right <= this.right &&
2998                  region.top >= this.top &&
2999                  region.bottom <= this.bottom    );
3000
3001     },
3002
3003     getArea : function() {
3004         return ( (this.bottom - this.top) * (this.right - this.left) );
3005     },
3006
3007     intersect : function(region) {
3008         var t = Math.max(this.top, region.top);
3009         var r = Math.min(this.right, region.right);
3010         var b = Math.min(this.bottom, region.bottom);
3011         var l = Math.max(this.left, region.left);
3012
3013         if (b >= t && r >= l) {
3014             return new Roo.lib.Region(t, r, b, l);
3015         } else {
3016             return null;
3017         }
3018     },
3019     union : function(region) {
3020         var t = Math.min(this.top, region.top);
3021         var r = Math.max(this.right, region.right);
3022         var b = Math.max(this.bottom, region.bottom);
3023         var l = Math.min(this.left, region.left);
3024
3025         return new Roo.lib.Region(t, r, b, l);
3026     },
3027
3028     adjust : function(t, l, b, r) {
3029         this.top += t;
3030         this.left += l;
3031         this.right += r;
3032         this.bottom += b;
3033         return this;
3034     }
3035 };
3036
3037 Roo.lib.Region.getRegion = function(el) {
3038     var p = Roo.lib.Dom.getXY(el);
3039
3040     var t = p[1];
3041     var r = p[0] + el.offsetWidth;
3042     var b = p[1] + el.offsetHeight;
3043     var l = p[0];
3044
3045     return new Roo.lib.Region(t, r, b, l);
3046 };
3047 /*
3048  * Portions of this file are based on pieces of Yahoo User Interface Library
3049  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3050  * YUI licensed under the BSD License:
3051  * http://developer.yahoo.net/yui/license.txt
3052  * <script type="text/javascript">
3053  *
3054  */
3055 //@@dep Roo.lib.Region
3056
3057
3058 Roo.lib.Point = function(x, y) {
3059     if (x instanceof Array) {
3060         y = x[1];
3061         x = x[0];
3062     }
3063     this.x = this.right = this.left = this[0] = x;
3064     this.y = this.top = this.bottom = this[1] = y;
3065 };
3066
3067 Roo.lib.Point.prototype = new Roo.lib.Region();
3068 /*
3069  * Portions of this file are based on pieces of Yahoo User Interface Library
3070  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3071  * YUI licensed under the BSD License:
3072  * http://developer.yahoo.net/yui/license.txt
3073  * <script type="text/javascript">
3074  *
3075  */
3076  
3077 (function() {   
3078
3079     Roo.lib.Anim = {
3080         scroll : function(el, args, duration, easing, cb, scope) {
3081             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3082         },
3083
3084         motion : function(el, args, duration, easing, cb, scope) {
3085             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3086         },
3087
3088         color : function(el, args, duration, easing, cb, scope) {
3089             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3090         },
3091
3092         run : function(el, args, duration, easing, cb, scope, type) {
3093             type = type || Roo.lib.AnimBase;
3094             if (typeof easing == "string") {
3095                 easing = Roo.lib.Easing[easing];
3096             }
3097             var anim = new type(el, args, duration, easing);
3098             anim.animateX(function() {
3099                 Roo.callback(cb, scope);
3100             });
3101             return anim;
3102         }
3103     };
3104 })();/*
3105  * Portions of this file are based on pieces of Yahoo User Interface Library
3106  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3107  * YUI licensed under the BSD License:
3108  * http://developer.yahoo.net/yui/license.txt
3109  * <script type="text/javascript">
3110  *
3111  */
3112
3113 (function() {    
3114     var libFlyweight;
3115     
3116     function fly(el) {
3117         if (!libFlyweight) {
3118             libFlyweight = new Roo.Element.Flyweight();
3119         }
3120         libFlyweight.dom = el;
3121         return libFlyweight;
3122     }
3123
3124     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3125     
3126    
3127     
3128     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3129         if (el) {
3130             this.init(el, attributes, duration, method);
3131         }
3132     };
3133
3134     Roo.lib.AnimBase.fly = fly;
3135     
3136     
3137     
3138     Roo.lib.AnimBase.prototype = {
3139
3140         toString: function() {
3141             var el = this.getEl();
3142             var id = el.id || el.tagName;
3143             return ("Anim " + id);
3144         },
3145
3146         patterns: {
3147             noNegatives:        /width|height|opacity|padding/i,
3148             offsetAttribute:  /^((width|height)|(top|left))$/,
3149             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3150             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3151         },
3152
3153
3154         doMethod: function(attr, start, end) {
3155             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3156         },
3157
3158
3159         setAttribute: function(attr, val, unit) {
3160             if (this.patterns.noNegatives.test(attr)) {
3161                 val = (val > 0) ? val : 0;
3162             }
3163
3164             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3165         },
3166
3167
3168         getAttribute: function(attr) {
3169             var el = this.getEl();
3170             var val = fly(el).getStyle(attr);
3171
3172             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3173                 return parseFloat(val);
3174             }
3175
3176             var a = this.patterns.offsetAttribute.exec(attr) || [];
3177             var pos = !!( a[3] );
3178             var box = !!( a[2] );
3179
3180
3181             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3182                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3183             } else {
3184                 val = 0;
3185             }
3186
3187             return val;
3188         },
3189
3190
3191         getDefaultUnit: function(attr) {
3192             if (this.patterns.defaultUnit.test(attr)) {
3193                 return 'px';
3194             }
3195
3196             return '';
3197         },
3198
3199         animateX : function(callback, scope) {
3200             var f = function() {
3201                 this.onComplete.removeListener(f);
3202                 if (typeof callback == "function") {
3203                     callback.call(scope || this, this);
3204                 }
3205             };
3206             this.onComplete.addListener(f, this);
3207             this.animate();
3208         },
3209
3210
3211         setRuntimeAttribute: function(attr) {
3212             var start;
3213             var end;
3214             var attributes = this.attributes;
3215
3216             this.runtimeAttributes[attr] = {};
3217
3218             var isset = function(prop) {
3219                 return (typeof prop !== 'undefined');
3220             };
3221
3222             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3223                 return false;
3224             }
3225
3226             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3227
3228
3229             if (isset(attributes[attr]['to'])) {
3230                 end = attributes[attr]['to'];
3231             } else if (isset(attributes[attr]['by'])) {
3232                 if (start.constructor == Array) {
3233                     end = [];
3234                     for (var i = 0, len = start.length; i < len; ++i) {
3235                         end[i] = start[i] + attributes[attr]['by'][i];
3236                     }
3237                 } else {
3238                     end = start + attributes[attr]['by'];
3239                 }
3240             }
3241
3242             this.runtimeAttributes[attr].start = start;
3243             this.runtimeAttributes[attr].end = end;
3244
3245
3246             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3247         },
3248
3249
3250         init: function(el, attributes, duration, method) {
3251
3252             var isAnimated = false;
3253
3254
3255             var startTime = null;
3256
3257
3258             var actualFrames = 0;
3259
3260
3261             el = Roo.getDom(el);
3262
3263
3264             this.attributes = attributes || {};
3265
3266
3267             this.duration = duration || 1;
3268
3269
3270             this.method = method || Roo.lib.Easing.easeNone;
3271
3272
3273             this.useSeconds = true;
3274
3275
3276             this.currentFrame = 0;
3277
3278
3279             this.totalFrames = Roo.lib.AnimMgr.fps;
3280
3281
3282             this.getEl = function() {
3283                 return el;
3284             };
3285
3286
3287             this.isAnimated = function() {
3288                 return isAnimated;
3289             };
3290
3291
3292             this.getStartTime = function() {
3293                 return startTime;
3294             };
3295
3296             this.runtimeAttributes = {};
3297
3298
3299             this.animate = function() {
3300                 if (this.isAnimated()) {
3301                     return false;
3302                 }
3303
3304                 this.currentFrame = 0;
3305
3306                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3307
3308                 Roo.lib.AnimMgr.registerElement(this);
3309             };
3310
3311
3312             this.stop = function(finish) {
3313                 if (finish) {
3314                     this.currentFrame = this.totalFrames;
3315                     this._onTween.fire();
3316                 }
3317                 Roo.lib.AnimMgr.stop(this);
3318             };
3319
3320             var onStart = function() {
3321                 this.onStart.fire();
3322
3323                 this.runtimeAttributes = {};
3324                 for (var attr in this.attributes) {
3325                     this.setRuntimeAttribute(attr);
3326                 }
3327
3328                 isAnimated = true;
3329                 actualFrames = 0;
3330                 startTime = new Date();
3331             };
3332
3333
3334             var onTween = function() {
3335                 var data = {
3336                     duration: new Date() - this.getStartTime(),
3337                     currentFrame: this.currentFrame
3338                 };
3339
3340                 data.toString = function() {
3341                     return (
3342                             'duration: ' + data.duration +
3343                             ', currentFrame: ' + data.currentFrame
3344                             );
3345                 };
3346
3347                 this.onTween.fire(data);
3348
3349                 var runtimeAttributes = this.runtimeAttributes;
3350
3351                 for (var attr in runtimeAttributes) {
3352                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3353                 }
3354
3355                 actualFrames += 1;
3356             };
3357
3358             var onComplete = function() {
3359                 var actual_duration = (new Date() - startTime) / 1000 ;
3360
3361                 var data = {
3362                     duration: actual_duration,
3363                     frames: actualFrames,
3364                     fps: actualFrames / actual_duration
3365                 };
3366
3367                 data.toString = function() {
3368                     return (
3369                             'duration: ' + data.duration +
3370                             ', frames: ' + data.frames +
3371                             ', fps: ' + data.fps
3372                             );
3373                 };
3374
3375                 isAnimated = false;
3376                 actualFrames = 0;
3377                 this.onComplete.fire(data);
3378             };
3379
3380
3381             this._onStart = new Roo.util.Event(this);
3382             this.onStart = new Roo.util.Event(this);
3383             this.onTween = new Roo.util.Event(this);
3384             this._onTween = new Roo.util.Event(this);
3385             this.onComplete = new Roo.util.Event(this);
3386             this._onComplete = new Roo.util.Event(this);
3387             this._onStart.addListener(onStart);
3388             this._onTween.addListener(onTween);
3389             this._onComplete.addListener(onComplete);
3390         }
3391     };
3392 })();
3393 /*
3394  * Portions of this file are based on pieces of Yahoo User Interface Library
3395  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3396  * YUI licensed under the BSD License:
3397  * http://developer.yahoo.net/yui/license.txt
3398  * <script type="text/javascript">
3399  *
3400  */
3401
3402 Roo.lib.AnimMgr = new function() {
3403
3404     var thread = null;
3405
3406
3407     var queue = [];
3408
3409
3410     var tweenCount = 0;
3411
3412
3413     this.fps = 1000;
3414
3415
3416     this.delay = 1;
3417
3418
3419     this.registerElement = function(tween) {
3420         queue[queue.length] = tween;
3421         tweenCount += 1;
3422         tween._onStart.fire();
3423         this.start();
3424     };
3425
3426
3427     this.unRegister = function(tween, index) {
3428         tween._onComplete.fire();
3429         index = index || getIndex(tween);
3430         if (index != -1) {
3431             queue.splice(index, 1);
3432         }
3433
3434         tweenCount -= 1;
3435         if (tweenCount <= 0) {
3436             this.stop();
3437         }
3438     };
3439
3440
3441     this.start = function() {
3442         if (thread === null) {
3443             thread = setInterval(this.run, this.delay);
3444         }
3445     };
3446
3447
3448     this.stop = function(tween) {
3449         if (!tween) {
3450             clearInterval(thread);
3451
3452             for (var i = 0, len = queue.length; i < len; ++i) {
3453                 if (queue[0].isAnimated()) {
3454                     this.unRegister(queue[0], 0);
3455                 }
3456             }
3457
3458             queue = [];
3459             thread = null;
3460             tweenCount = 0;
3461         }
3462         else {
3463             this.unRegister(tween);
3464         }
3465     };
3466
3467
3468     this.run = function() {
3469         for (var i = 0, len = queue.length; i < len; ++i) {
3470             var tween = queue[i];
3471             if (!tween || !tween.isAnimated()) {
3472                 continue;
3473             }
3474
3475             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3476             {
3477                 tween.currentFrame += 1;
3478
3479                 if (tween.useSeconds) {
3480                     correctFrame(tween);
3481                 }
3482                 tween._onTween.fire();
3483             }
3484             else {
3485                 Roo.lib.AnimMgr.stop(tween, i);
3486             }
3487         }
3488     };
3489
3490     var getIndex = function(anim) {
3491         for (var i = 0, len = queue.length; i < len; ++i) {
3492             if (queue[i] == anim) {
3493                 return i;
3494             }
3495         }
3496         return -1;
3497     };
3498
3499
3500     var correctFrame = function(tween) {
3501         var frames = tween.totalFrames;
3502         var frame = tween.currentFrame;
3503         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3504         var elapsed = (new Date() - tween.getStartTime());
3505         var tweak = 0;
3506
3507         if (elapsed < tween.duration * 1000) {
3508             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3509         } else {
3510             tweak = frames - (frame + 1);
3511         }
3512         if (tweak > 0 && isFinite(tweak)) {
3513             if (tween.currentFrame + tweak >= frames) {
3514                 tweak = frames - (frame + 1);
3515             }
3516
3517             tween.currentFrame += tweak;
3518         }
3519     };
3520 };
3521
3522     /*
3523  * Portions of this file are based on pieces of Yahoo User Interface Library
3524  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3525  * YUI licensed under the BSD License:
3526  * http://developer.yahoo.net/yui/license.txt
3527  * <script type="text/javascript">
3528  *
3529  */
3530 Roo.lib.Bezier = new function() {
3531
3532         this.getPosition = function(points, t) {
3533             var n = points.length;
3534             var tmp = [];
3535
3536             for (var i = 0; i < n; ++i) {
3537                 tmp[i] = [points[i][0], points[i][1]];
3538             }
3539
3540             for (var j = 1; j < n; ++j) {
3541                 for (i = 0; i < n - j; ++i) {
3542                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3543                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3544                 }
3545             }
3546
3547             return [ tmp[0][0], tmp[0][1] ];
3548
3549         };
3550     };/*
3551  * Portions of this file are based on pieces of Yahoo User Interface Library
3552  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3553  * YUI licensed under the BSD License:
3554  * http://developer.yahoo.net/yui/license.txt
3555  * <script type="text/javascript">
3556  *
3557  */
3558 (function() {
3559
3560     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3561         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3562     };
3563
3564     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3565
3566     var fly = Roo.lib.AnimBase.fly;
3567     var Y = Roo.lib;
3568     var superclass = Y.ColorAnim.superclass;
3569     var proto = Y.ColorAnim.prototype;
3570
3571     proto.toString = function() {
3572         var el = this.getEl();
3573         var id = el.id || el.tagName;
3574         return ("ColorAnim " + id);
3575     };
3576
3577     proto.patterns.color = /color$/i;
3578     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3579     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3580     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3581     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3582
3583
3584     proto.parseColor = function(s) {
3585         if (s.length == 3) {
3586             return s;
3587         }
3588
3589         var c = this.patterns.hex.exec(s);
3590         if (c && c.length == 4) {
3591             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3592         }
3593
3594         c = this.patterns.rgb.exec(s);
3595         if (c && c.length == 4) {
3596             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3597         }
3598
3599         c = this.patterns.hex3.exec(s);
3600         if (c && c.length == 4) {
3601             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3602         }
3603
3604         return null;
3605     };
3606     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3607     proto.getAttribute = function(attr) {
3608         var el = this.getEl();
3609         if (this.patterns.color.test(attr)) {
3610             var val = fly(el).getStyle(attr);
3611
3612             if (this.patterns.transparent.test(val)) {
3613                 var parent = el.parentNode;
3614                 val = fly(parent).getStyle(attr);
3615
3616                 while (parent && this.patterns.transparent.test(val)) {
3617                     parent = parent.parentNode;
3618                     val = fly(parent).getStyle(attr);
3619                     if (parent.tagName.toUpperCase() == 'HTML') {
3620                         val = '#fff';
3621                     }
3622                 }
3623             }
3624         } else {
3625             val = superclass.getAttribute.call(this, attr);
3626         }
3627
3628         return val;
3629     };
3630     proto.getAttribute = function(attr) {
3631         var el = this.getEl();
3632         if (this.patterns.color.test(attr)) {
3633             var val = fly(el).getStyle(attr);
3634
3635             if (this.patterns.transparent.test(val)) {
3636                 var parent = el.parentNode;
3637                 val = fly(parent).getStyle(attr);
3638
3639                 while (parent && this.patterns.transparent.test(val)) {
3640                     parent = parent.parentNode;
3641                     val = fly(parent).getStyle(attr);
3642                     if (parent.tagName.toUpperCase() == 'HTML') {
3643                         val = '#fff';
3644                     }
3645                 }
3646             }
3647         } else {
3648             val = superclass.getAttribute.call(this, attr);
3649         }
3650
3651         return val;
3652     };
3653
3654     proto.doMethod = function(attr, start, end) {
3655         var val;
3656
3657         if (this.patterns.color.test(attr)) {
3658             val = [];
3659             for (var i = 0, len = start.length; i < len; ++i) {
3660                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3661             }
3662
3663             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3664         }
3665         else {
3666             val = superclass.doMethod.call(this, attr, start, end);
3667         }
3668
3669         return val;
3670     };
3671
3672     proto.setRuntimeAttribute = function(attr) {
3673         superclass.setRuntimeAttribute.call(this, attr);
3674
3675         if (this.patterns.color.test(attr)) {
3676             var attributes = this.attributes;
3677             var start = this.parseColor(this.runtimeAttributes[attr].start);
3678             var end = this.parseColor(this.runtimeAttributes[attr].end);
3679
3680             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3681                 end = this.parseColor(attributes[attr].by);
3682
3683                 for (var i = 0, len = start.length; i < len; ++i) {
3684                     end[i] = start[i] + end[i];
3685                 }
3686             }
3687
3688             this.runtimeAttributes[attr].start = start;
3689             this.runtimeAttributes[attr].end = end;
3690         }
3691     };
3692 })();
3693
3694 /*
3695  * Portions of this file are based on pieces of Yahoo User Interface Library
3696  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3697  * YUI licensed under the BSD License:
3698  * http://developer.yahoo.net/yui/license.txt
3699  * <script type="text/javascript">
3700  *
3701  */
3702 Roo.lib.Easing = {
3703
3704
3705     easeNone: function (t, b, c, d) {
3706         return c * t / d + b;
3707     },
3708
3709
3710     easeIn: function (t, b, c, d) {
3711         return c * (t /= d) * t + b;
3712     },
3713
3714
3715     easeOut: function (t, b, c, d) {
3716         return -c * (t /= d) * (t - 2) + b;
3717     },
3718
3719
3720     easeBoth: function (t, b, c, d) {
3721         if ((t /= d / 2) < 1) {
3722             return c / 2 * t * t + b;
3723         }
3724
3725         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3726     },
3727
3728
3729     easeInStrong: function (t, b, c, d) {
3730         return c * (t /= d) * t * t * t + b;
3731     },
3732
3733
3734     easeOutStrong: function (t, b, c, d) {
3735         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3736     },
3737
3738
3739     easeBothStrong: function (t, b, c, d) {
3740         if ((t /= d / 2) < 1) {
3741             return c / 2 * t * t * t * t + b;
3742         }
3743
3744         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3745     },
3746
3747
3748
3749     elasticIn: function (t, b, c, d, a, p) {
3750         if (t == 0) {
3751             return b;
3752         }
3753         if ((t /= d) == 1) {
3754             return b + c;
3755         }
3756         if (!p) {
3757             p = d * .3;
3758         }
3759
3760         if (!a || a < Math.abs(c)) {
3761             a = c;
3762             var s = p / 4;
3763         }
3764         else {
3765             var s = p / (2 * Math.PI) * Math.asin(c / a);
3766         }
3767
3768         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3769     },
3770
3771
3772     elasticOut: function (t, b, c, d, a, p) {
3773         if (t == 0) {
3774             return b;
3775         }
3776         if ((t /= d) == 1) {
3777             return b + c;
3778         }
3779         if (!p) {
3780             p = d * .3;
3781         }
3782
3783         if (!a || a < Math.abs(c)) {
3784             a = c;
3785             var s = p / 4;
3786         }
3787         else {
3788             var s = p / (2 * Math.PI) * Math.asin(c / a);
3789         }
3790
3791         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3792     },
3793
3794
3795     elasticBoth: function (t, b, c, d, a, p) {
3796         if (t == 0) {
3797             return b;
3798         }
3799
3800         if ((t /= d / 2) == 2) {
3801             return b + c;
3802         }
3803
3804         if (!p) {
3805             p = d * (.3 * 1.5);
3806         }
3807
3808         if (!a || a < Math.abs(c)) {
3809             a = c;
3810             var s = p / 4;
3811         }
3812         else {
3813             var s = p / (2 * Math.PI) * Math.asin(c / a);
3814         }
3815
3816         if (t < 1) {
3817             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3818                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3819         }
3820         return a * Math.pow(2, -10 * (t -= 1)) *
3821                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3822     },
3823
3824
3825
3826     backIn: function (t, b, c, d, s) {
3827         if (typeof s == 'undefined') {
3828             s = 1.70158;
3829         }
3830         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3831     },
3832
3833
3834     backOut: function (t, b, c, d, s) {
3835         if (typeof s == 'undefined') {
3836             s = 1.70158;
3837         }
3838         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3839     },
3840
3841
3842     backBoth: function (t, b, c, d, s) {
3843         if (typeof s == 'undefined') {
3844             s = 1.70158;
3845         }
3846
3847         if ((t /= d / 2 ) < 1) {
3848             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3849         }
3850         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3851     },
3852
3853
3854     bounceIn: function (t, b, c, d) {
3855         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3856     },
3857
3858
3859     bounceOut: function (t, b, c, d) {
3860         if ((t /= d) < (1 / 2.75)) {
3861             return c * (7.5625 * t * t) + b;
3862         } else if (t < (2 / 2.75)) {
3863             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3864         } else if (t < (2.5 / 2.75)) {
3865             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3866         }
3867         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3868     },
3869
3870
3871     bounceBoth: function (t, b, c, d) {
3872         if (t < d / 2) {
3873             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3874         }
3875         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3876     }
3877 };/*
3878  * Portions of this file are based on pieces of Yahoo User Interface Library
3879  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3880  * YUI licensed under the BSD License:
3881  * http://developer.yahoo.net/yui/license.txt
3882  * <script type="text/javascript">
3883  *
3884  */
3885     (function() {
3886         Roo.lib.Motion = function(el, attributes, duration, method) {
3887             if (el) {
3888                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3889             }
3890         };
3891
3892         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3893
3894
3895         var Y = Roo.lib;
3896         var superclass = Y.Motion.superclass;
3897         var proto = Y.Motion.prototype;
3898
3899         proto.toString = function() {
3900             var el = this.getEl();
3901             var id = el.id || el.tagName;
3902             return ("Motion " + id);
3903         };
3904
3905         proto.patterns.points = /^points$/i;
3906
3907         proto.setAttribute = function(attr, val, unit) {
3908             if (this.patterns.points.test(attr)) {
3909                 unit = unit || 'px';
3910                 superclass.setAttribute.call(this, 'left', val[0], unit);
3911                 superclass.setAttribute.call(this, 'top', val[1], unit);
3912             } else {
3913                 superclass.setAttribute.call(this, attr, val, unit);
3914             }
3915         };
3916
3917         proto.getAttribute = function(attr) {
3918             if (this.patterns.points.test(attr)) {
3919                 var val = [
3920                         superclass.getAttribute.call(this, 'left'),
3921                         superclass.getAttribute.call(this, 'top')
3922                         ];
3923             } else {
3924                 val = superclass.getAttribute.call(this, attr);
3925             }
3926
3927             return val;
3928         };
3929
3930         proto.doMethod = function(attr, start, end) {
3931             var val = null;
3932
3933             if (this.patterns.points.test(attr)) {
3934                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3935                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3936             } else {
3937                 val = superclass.doMethod.call(this, attr, start, end);
3938             }
3939             return val;
3940         };
3941
3942         proto.setRuntimeAttribute = function(attr) {
3943             if (this.patterns.points.test(attr)) {
3944                 var el = this.getEl();
3945                 var attributes = this.attributes;
3946                 var start;
3947                 var control = attributes['points']['control'] || [];
3948                 var end;
3949                 var i, len;
3950
3951                 if (control.length > 0 && !(control[0] instanceof Array)) {
3952                     control = [control];
3953                 } else {
3954                     var tmp = [];
3955                     for (i = 0,len = control.length; i < len; ++i) {
3956                         tmp[i] = control[i];
3957                     }
3958                     control = tmp;
3959                 }
3960
3961                 Roo.fly(el).position();
3962
3963                 if (isset(attributes['points']['from'])) {
3964                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3965                 }
3966                 else {
3967                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3968                 }
3969
3970                 start = this.getAttribute('points');
3971
3972
3973                 if (isset(attributes['points']['to'])) {
3974                     end = translateValues.call(this, attributes['points']['to'], start);
3975
3976                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3977                     for (i = 0,len = control.length; i < len; ++i) {
3978                         control[i] = translateValues.call(this, control[i], start);
3979                     }
3980
3981
3982                 } else if (isset(attributes['points']['by'])) {
3983                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3984
3985                     for (i = 0,len = control.length; i < len; ++i) {
3986                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3987                     }
3988                 }
3989
3990                 this.runtimeAttributes[attr] = [start];
3991
3992                 if (control.length > 0) {
3993                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
3994                 }
3995
3996                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
3997             }
3998             else {
3999                 superclass.setRuntimeAttribute.call(this, attr);
4000             }
4001         };
4002
4003         var translateValues = function(val, start) {
4004             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4005             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4006
4007             return val;
4008         };
4009
4010         var isset = function(prop) {
4011             return (typeof prop !== 'undefined');
4012         };
4013     })();
4014 /*
4015  * Portions of this file are based on pieces of Yahoo User Interface Library
4016  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4017  * YUI licensed under the BSD License:
4018  * http://developer.yahoo.net/yui/license.txt
4019  * <script type="text/javascript">
4020  *
4021  */
4022     (function() {
4023         Roo.lib.Scroll = function(el, attributes, duration, method) {
4024             if (el) {
4025                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4026             }
4027         };
4028
4029         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4030
4031
4032         var Y = Roo.lib;
4033         var superclass = Y.Scroll.superclass;
4034         var proto = Y.Scroll.prototype;
4035
4036         proto.toString = function() {
4037             var el = this.getEl();
4038             var id = el.id || el.tagName;
4039             return ("Scroll " + id);
4040         };
4041
4042         proto.doMethod = function(attr, start, end) {
4043             var val = null;
4044
4045             if (attr == 'scroll') {
4046                 val = [
4047                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4048                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4049                         ];
4050
4051             } else {
4052                 val = superclass.doMethod.call(this, attr, start, end);
4053             }
4054             return val;
4055         };
4056
4057         proto.getAttribute = function(attr) {
4058             var val = null;
4059             var el = this.getEl();
4060
4061             if (attr == 'scroll') {
4062                 val = [ el.scrollLeft, el.scrollTop ];
4063             } else {
4064                 val = superclass.getAttribute.call(this, attr);
4065             }
4066
4067             return val;
4068         };
4069
4070         proto.setAttribute = function(attr, val, unit) {
4071             var el = this.getEl();
4072
4073             if (attr == 'scroll') {
4074                 el.scrollLeft = val[0];
4075                 el.scrollTop = val[1];
4076             } else {
4077                 superclass.setAttribute.call(this, attr, val, unit);
4078             }
4079         };
4080     })();
4081 /*
4082  * Based on:
4083  * Ext JS Library 1.1.1
4084  * Copyright(c) 2006-2007, Ext JS, LLC.
4085  *
4086  * Originally Released Under LGPL - original licence link has changed is not relivant.
4087  *
4088  * Fork - LGPL
4089  * <script type="text/javascript">
4090  */
4091
4092
4093 // nasty IE9 hack - what a pile of crap that is..
4094
4095  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4096     Range.prototype.createContextualFragment = function (html) {
4097         var doc = window.document;
4098         var container = doc.createElement("div");
4099         container.innerHTML = html;
4100         var frag = doc.createDocumentFragment(), n;
4101         while ((n = container.firstChild)) {
4102             frag.appendChild(n);
4103         }
4104         return frag;
4105     };
4106 }
4107
4108 /**
4109  * @class Roo.DomHelper
4110  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4111  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4112  * @singleton
4113  */
4114 Roo.DomHelper = function(){
4115     var tempTableEl = null;
4116     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4117     var tableRe = /^table|tbody|tr|td$/i;
4118     var xmlns = {};
4119     // build as innerHTML where available
4120     /** @ignore */
4121     var createHtml = function(o){
4122         if(typeof o == 'string'){
4123             return o;
4124         }
4125         var b = "";
4126         if(!o.tag){
4127             o.tag = "div";
4128         }
4129         b += "<" + o.tag;
4130         for(var attr in o){
4131             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4132             if(attr == "style"){
4133                 var s = o["style"];
4134                 if(typeof s == "function"){
4135                     s = s.call();
4136                 }
4137                 if(typeof s == "string"){
4138                     b += ' style="' + s + '"';
4139                 }else if(typeof s == "object"){
4140                     b += ' style="';
4141                     for(var key in s){
4142                         if(typeof s[key] != "function"){
4143                             b += key + ":" + s[key] + ";";
4144                         }
4145                     }
4146                     b += '"';
4147                 }
4148             }else{
4149                 if(attr == "cls"){
4150                     b += ' class="' + o["cls"] + '"';
4151                 }else if(attr == "htmlFor"){
4152                     b += ' for="' + o["htmlFor"] + '"';
4153                 }else{
4154                     b += " " + attr + '="' + o[attr] + '"';
4155                 }
4156             }
4157         }
4158         if(emptyTags.test(o.tag)){
4159             b += "/>";
4160         }else{
4161             b += ">";
4162             var cn = o.children || o.cn;
4163             if(cn){
4164                 //http://bugs.kde.org/show_bug.cgi?id=71506
4165                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4166                     for(var i = 0, len = cn.length; i < len; i++) {
4167                         b += createHtml(cn[i], b);
4168                     }
4169                 }else{
4170                     b += createHtml(cn, b);
4171                 }
4172             }
4173             if(o.html){
4174                 b += o.html;
4175             }
4176             b += "</" + o.tag + ">";
4177         }
4178         return b;
4179     };
4180
4181     // build as dom
4182     /** @ignore */
4183     var createDom = function(o, parentNode){
4184          
4185         // defininition craeted..
4186         var ns = false;
4187         if (o.ns && o.ns != 'html') {
4188                
4189             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4190                 xmlns[o.ns] = o.xmlns;
4191                 ns = o.xmlns;
4192             }
4193             if (typeof(xmlns[o.ns]) == 'undefined') {
4194                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4195             }
4196             ns = xmlns[o.ns];
4197         }
4198         
4199         
4200         if (typeof(o) == 'string') {
4201             return parentNode.appendChild(document.createTextNode(o));
4202         }
4203         o.tag = o.tag || div;
4204         if (o.ns && Roo.isIE) {
4205             ns = false;
4206             o.tag = o.ns + ':' + o.tag;
4207             
4208         }
4209         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4210         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4211         for(var attr in o){
4212             
4213             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4214                     attr == "style" || typeof o[attr] == "function") continue;
4215                     
4216             if(attr=="cls" && Roo.isIE){
4217                 el.className = o["cls"];
4218             }else{
4219                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4220                 else el[attr] = o[attr];
4221             }
4222         }
4223         Roo.DomHelper.applyStyles(el, o.style);
4224         var cn = o.children || o.cn;
4225         if(cn){
4226             //http://bugs.kde.org/show_bug.cgi?id=71506
4227              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4228                 for(var i = 0, len = cn.length; i < len; i++) {
4229                     createDom(cn[i], el);
4230                 }
4231             }else{
4232                 createDom(cn, el);
4233             }
4234         }
4235         if(o.html){
4236             el.innerHTML = o.html;
4237         }
4238         if(parentNode){
4239            parentNode.appendChild(el);
4240         }
4241         return el;
4242     };
4243
4244     var ieTable = function(depth, s, h, e){
4245         tempTableEl.innerHTML = [s, h, e].join('');
4246         var i = -1, el = tempTableEl;
4247         while(++i < depth){
4248             el = el.firstChild;
4249         }
4250         return el;
4251     };
4252
4253     // kill repeat to save bytes
4254     var ts = '<table>',
4255         te = '</table>',
4256         tbs = ts+'<tbody>',
4257         tbe = '</tbody>'+te,
4258         trs = tbs + '<tr>',
4259         tre = '</tr>'+tbe;
4260
4261     /**
4262      * @ignore
4263      * Nasty code for IE's broken table implementation
4264      */
4265     var insertIntoTable = function(tag, where, el, html){
4266         if(!tempTableEl){
4267             tempTableEl = document.createElement('div');
4268         }
4269         var node;
4270         var before = null;
4271         if(tag == 'td'){
4272             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4273                 return;
4274             }
4275             if(where == 'beforebegin'){
4276                 before = el;
4277                 el = el.parentNode;
4278             } else{
4279                 before = el.nextSibling;
4280                 el = el.parentNode;
4281             }
4282             node = ieTable(4, trs, html, tre);
4283         }
4284         else if(tag == 'tr'){
4285             if(where == 'beforebegin'){
4286                 before = el;
4287                 el = el.parentNode;
4288                 node = ieTable(3, tbs, html, tbe);
4289             } else if(where == 'afterend'){
4290                 before = el.nextSibling;
4291                 el = el.parentNode;
4292                 node = ieTable(3, tbs, html, tbe);
4293             } else{ // INTO a TR
4294                 if(where == 'afterbegin'){
4295                     before = el.firstChild;
4296                 }
4297                 node = ieTable(4, trs, html, tre);
4298             }
4299         } else if(tag == 'tbody'){
4300             if(where == 'beforebegin'){
4301                 before = el;
4302                 el = el.parentNode;
4303                 node = ieTable(2, ts, html, te);
4304             } else if(where == 'afterend'){
4305                 before = el.nextSibling;
4306                 el = el.parentNode;
4307                 node = ieTable(2, ts, html, te);
4308             } else{
4309                 if(where == 'afterbegin'){
4310                     before = el.firstChild;
4311                 }
4312                 node = ieTable(3, tbs, html, tbe);
4313             }
4314         } else{ // TABLE
4315             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4316                 return;
4317             }
4318             if(where == 'afterbegin'){
4319                 before = el.firstChild;
4320             }
4321             node = ieTable(2, ts, html, te);
4322         }
4323         el.insertBefore(node, before);
4324         return node;
4325     };
4326
4327     return {
4328     /** True to force the use of DOM instead of html fragments @type Boolean */
4329     useDom : false,
4330
4331     /**
4332      * Returns the markup for the passed Element(s) config
4333      * @param {Object} o The Dom object spec (and children)
4334      * @return {String}
4335      */
4336     markup : function(o){
4337         return createHtml(o);
4338     },
4339
4340     /**
4341      * Applies a style specification to an element
4342      * @param {String/HTMLElement} el The element to apply styles to
4343      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4344      * a function which returns such a specification.
4345      */
4346     applyStyles : function(el, styles){
4347         if(styles){
4348            el = Roo.fly(el);
4349            if(typeof styles == "string"){
4350                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4351                var matches;
4352                while ((matches = re.exec(styles)) != null){
4353                    el.setStyle(matches[1], matches[2]);
4354                }
4355            }else if (typeof styles == "object"){
4356                for (var style in styles){
4357                   el.setStyle(style, styles[style]);
4358                }
4359            }else if (typeof styles == "function"){
4360                 Roo.DomHelper.applyStyles(el, styles.call());
4361            }
4362         }
4363     },
4364
4365     /**
4366      * Inserts an HTML fragment into the Dom
4367      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4368      * @param {HTMLElement} el The context element
4369      * @param {String} html The HTML fragmenet
4370      * @return {HTMLElement} The new node
4371      */
4372     insertHtml : function(where, el, html){
4373         where = where.toLowerCase();
4374         if(el.insertAdjacentHTML){
4375             if(tableRe.test(el.tagName)){
4376                 var rs;
4377                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4378                     return rs;
4379                 }
4380             }
4381             switch(where){
4382                 case "beforebegin":
4383                     el.insertAdjacentHTML('BeforeBegin', html);
4384                     return el.previousSibling;
4385                 case "afterbegin":
4386                     el.insertAdjacentHTML('AfterBegin', html);
4387                     return el.firstChild;
4388                 case "beforeend":
4389                     el.insertAdjacentHTML('BeforeEnd', html);
4390                     return el.lastChild;
4391                 case "afterend":
4392                     el.insertAdjacentHTML('AfterEnd', html);
4393                     return el.nextSibling;
4394             }
4395             throw 'Illegal insertion point -> "' + where + '"';
4396         }
4397         var range = el.ownerDocument.createRange();
4398         var frag;
4399         switch(where){
4400              case "beforebegin":
4401                 range.setStartBefore(el);
4402                 frag = range.createContextualFragment(html);
4403                 el.parentNode.insertBefore(frag, el);
4404                 return el.previousSibling;
4405              case "afterbegin":
4406                 if(el.firstChild){
4407                     range.setStartBefore(el.firstChild);
4408                     frag = range.createContextualFragment(html);
4409                     el.insertBefore(frag, el.firstChild);
4410                     return el.firstChild;
4411                 }else{
4412                     el.innerHTML = html;
4413                     return el.firstChild;
4414                 }
4415             case "beforeend":
4416                 if(el.lastChild){
4417                     range.setStartAfter(el.lastChild);
4418                     frag = range.createContextualFragment(html);
4419                     el.appendChild(frag);
4420                     return el.lastChild;
4421                 }else{
4422                     el.innerHTML = html;
4423                     return el.lastChild;
4424                 }
4425             case "afterend":
4426                 range.setStartAfter(el);
4427                 frag = range.createContextualFragment(html);
4428                 el.parentNode.insertBefore(frag, el.nextSibling);
4429                 return el.nextSibling;
4430             }
4431             throw 'Illegal insertion point -> "' + where + '"';
4432     },
4433
4434     /**
4435      * Creates new Dom element(s) and inserts them before el
4436      * @param {String/HTMLElement/Element} el The context element
4437      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4438      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4439      * @return {HTMLElement/Roo.Element} The new node
4440      */
4441     insertBefore : function(el, o, returnElement){
4442         return this.doInsert(el, o, returnElement, "beforeBegin");
4443     },
4444
4445     /**
4446      * Creates new Dom element(s) and inserts them after el
4447      * @param {String/HTMLElement/Element} el The context element
4448      * @param {Object} o The Dom object spec (and children)
4449      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4450      * @return {HTMLElement/Roo.Element} The new node
4451      */
4452     insertAfter : function(el, o, returnElement){
4453         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4454     },
4455
4456     /**
4457      * Creates new Dom element(s) and inserts them as the first child of el
4458      * @param {String/HTMLElement/Element} el The context element
4459      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4460      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4461      * @return {HTMLElement/Roo.Element} The new node
4462      */
4463     insertFirst : function(el, o, returnElement){
4464         return this.doInsert(el, o, returnElement, "afterBegin");
4465     },
4466
4467     // private
4468     doInsert : function(el, o, returnElement, pos, sibling){
4469         el = Roo.getDom(el);
4470         var newNode;
4471         if(this.useDom || o.ns){
4472             newNode = createDom(o, null);
4473             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4474         }else{
4475             var html = createHtml(o);
4476             newNode = this.insertHtml(pos, el, html);
4477         }
4478         return returnElement ? Roo.get(newNode, true) : newNode;
4479     },
4480
4481     /**
4482      * Creates new Dom element(s) and appends them to el
4483      * @param {String/HTMLElement/Element} el The context element
4484      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486      * @return {HTMLElement/Roo.Element} The new node
4487      */
4488     append : function(el, o, returnElement){
4489         el = Roo.getDom(el);
4490         var newNode;
4491         if(this.useDom || o.ns){
4492             newNode = createDom(o, null);
4493             el.appendChild(newNode);
4494         }else{
4495             var html = createHtml(o);
4496             newNode = this.insertHtml("beforeEnd", el, html);
4497         }
4498         return returnElement ? Roo.get(newNode, true) : newNode;
4499     },
4500
4501     /**
4502      * Creates new Dom element(s) and overwrites the contents of el with them
4503      * @param {String/HTMLElement/Element} el The context element
4504      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4505      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4506      * @return {HTMLElement/Roo.Element} The new node
4507      */
4508     overwrite : function(el, o, returnElement){
4509         el = Roo.getDom(el);
4510         if (o.ns) {
4511           
4512             while (el.childNodes.length) {
4513                 el.removeChild(el.firstChild);
4514             }
4515             createDom(o, el);
4516         } else {
4517             el.innerHTML = createHtml(o);   
4518         }
4519         
4520         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4521     },
4522
4523     /**
4524      * Creates a new Roo.DomHelper.Template from the Dom object spec
4525      * @param {Object} o The Dom object spec (and children)
4526      * @return {Roo.DomHelper.Template} The new template
4527      */
4528     createTemplate : function(o){
4529         var html = createHtml(o);
4530         return new Roo.Template(html);
4531     }
4532     };
4533 }();
4534 /*
4535  * Based on:
4536  * Ext JS Library 1.1.1
4537  * Copyright(c) 2006-2007, Ext JS, LLC.
4538  *
4539  * Originally Released Under LGPL - original licence link has changed is not relivant.
4540  *
4541  * Fork - LGPL
4542  * <script type="text/javascript">
4543  */
4544  
4545 /**
4546 * @class Roo.Template
4547 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4548 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4549 * Usage:
4550 <pre><code>
4551 var t = new Roo.Template({
4552     html :  '&lt;div name="{id}"&gt;' + 
4553         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4554         '&lt;/div&gt;',
4555     myformat: function (value, allValues) {
4556         return 'XX' + value;
4557     }
4558 });
4559 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4560 </code></pre>
4561 * For more information see this blog post with examples:
4562 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4563      - Create Elements using DOM, HTML fragments and Templates</a>. 
4564 * @constructor
4565 * @param {Object} cfg - Configuration object.
4566 */
4567 Roo.Template = function(cfg){
4568     // BC!
4569     if(cfg instanceof Array){
4570         cfg = cfg.join("");
4571     }else if(arguments.length > 1){
4572         cfg = Array.prototype.join.call(arguments, "");
4573     }
4574     
4575     
4576     if (typeof(cfg) == 'object') {
4577         Roo.apply(this,cfg)
4578     } else {
4579         // bc
4580         this.html = cfg;
4581     }
4582     if (this.url) {
4583         this.load();
4584     }
4585     
4586 };
4587 Roo.Template.prototype = {
4588     
4589     /**
4590      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4591      *                    it should be fixed so that template is observable...
4592      */
4593     url : false,
4594     /**
4595      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4596      */
4597     html : '',
4598     /**
4599      * Returns an HTML fragment of this template with the specified values applied.
4600      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4601      * @return {String} The HTML fragment
4602      */
4603     applyTemplate : function(values){
4604         try {
4605            
4606             if(this.compiled){
4607                 return this.compiled(values);
4608             }
4609             var useF = this.disableFormats !== true;
4610             var fm = Roo.util.Format, tpl = this;
4611             var fn = function(m, name, format, args){
4612                 if(format && useF){
4613                     if(format.substr(0, 5) == "this."){
4614                         return tpl.call(format.substr(5), values[name], values);
4615                     }else{
4616                         if(args){
4617                             // quoted values are required for strings in compiled templates, 
4618                             // but for non compiled we need to strip them
4619                             // quoted reversed for jsmin
4620                             var re = /^\s*['"](.*)["']\s*$/;
4621                             args = args.split(',');
4622                             for(var i = 0, len = args.length; i < len; i++){
4623                                 args[i] = args[i].replace(re, "$1");
4624                             }
4625                             args = [values[name]].concat(args);
4626                         }else{
4627                             args = [values[name]];
4628                         }
4629                         return fm[format].apply(fm, args);
4630                     }
4631                 }else{
4632                     return values[name] !== undefined ? values[name] : "";
4633                 }
4634             };
4635             return this.html.replace(this.re, fn);
4636         } catch (e) {
4637             Roo.log(e);
4638             throw e;
4639         }
4640          
4641     },
4642     
4643     loading : false,
4644       
4645     load : function ()
4646     {
4647          
4648         if (this.loading) {
4649             return;
4650         }
4651         var _t = this;
4652         
4653         this.loading = true;
4654         this.compiled = false;
4655         
4656         var cx = new Roo.data.Connection();
4657         cx.request({
4658             url : this.url,
4659             method : 'GET',
4660             success : function (response) {
4661                 _t.loading = false;
4662                 _t.html = response.responseText;
4663                 _t.url = false;
4664                 _t.compile();
4665              },
4666             failure : function(response) {
4667                 Roo.log("Template failed to load from " + _t.url);
4668                 _t.loading = false;
4669             }
4670         });
4671     },
4672
4673     /**
4674      * Sets the HTML used as the template and optionally compiles it.
4675      * @param {String} html
4676      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4677      * @return {Roo.Template} this
4678      */
4679     set : function(html, compile){
4680         this.html = html;
4681         this.compiled = null;
4682         if(compile){
4683             this.compile();
4684         }
4685         return this;
4686     },
4687     
4688     /**
4689      * True to disable format functions (defaults to false)
4690      * @type Boolean
4691      */
4692     disableFormats : false,
4693     
4694     /**
4695     * The regular expression used to match template variables 
4696     * @type RegExp
4697     * @property 
4698     */
4699     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4700     
4701     /**
4702      * Compiles the template into an internal function, eliminating the RegEx overhead.
4703      * @return {Roo.Template} this
4704      */
4705     compile : function(){
4706         var fm = Roo.util.Format;
4707         var useF = this.disableFormats !== true;
4708         var sep = Roo.isGecko ? "+" : ",";
4709         var fn = function(m, name, format, args){
4710             if(format && useF){
4711                 args = args ? ',' + args : "";
4712                 if(format.substr(0, 5) != "this."){
4713                     format = "fm." + format + '(';
4714                 }else{
4715                     format = 'this.call("'+ format.substr(5) + '", ';
4716                     args = ", values";
4717                 }
4718             }else{
4719                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4720             }
4721             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4722         };
4723         var body;
4724         // branched to use + in gecko and [].join() in others
4725         if(Roo.isGecko){
4726             body = "this.compiled = function(values){ return '" +
4727                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4728                     "';};";
4729         }else{
4730             body = ["this.compiled = function(values){ return ['"];
4731             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4732             body.push("'].join('');};");
4733             body = body.join('');
4734         }
4735         /**
4736          * eval:var:values
4737          * eval:var:fm
4738          */
4739         eval(body);
4740         return this;
4741     },
4742     
4743     // private function used to call members
4744     call : function(fnName, value, allValues){
4745         return this[fnName](value, allValues);
4746     },
4747     
4748     /**
4749      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4750      * @param {String/HTMLElement/Roo.Element} el The context element
4751      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4752      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4753      * @return {HTMLElement/Roo.Element} The new node or Element
4754      */
4755     insertFirst: function(el, values, returnElement){
4756         return this.doInsert('afterBegin', el, values, returnElement);
4757     },
4758
4759     /**
4760      * Applies the supplied values to the template and inserts the new node(s) before el.
4761      * @param {String/HTMLElement/Roo.Element} el The context element
4762      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4763      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4764      * @return {HTMLElement/Roo.Element} The new node or Element
4765      */
4766     insertBefore: function(el, values, returnElement){
4767         return this.doInsert('beforeBegin', el, values, returnElement);
4768     },
4769
4770     /**
4771      * Applies the supplied values to the template and inserts the new node(s) after el.
4772      * @param {String/HTMLElement/Roo.Element} el The context element
4773      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4774      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4775      * @return {HTMLElement/Roo.Element} The new node or Element
4776      */
4777     insertAfter : function(el, values, returnElement){
4778         return this.doInsert('afterEnd', el, values, returnElement);
4779     },
4780     
4781     /**
4782      * Applies the supplied values to the template and appends the new node(s) to el.
4783      * @param {String/HTMLElement/Roo.Element} el The context element
4784      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4785      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4786      * @return {HTMLElement/Roo.Element} The new node or Element
4787      */
4788     append : function(el, values, returnElement){
4789         return this.doInsert('beforeEnd', el, values, returnElement);
4790     },
4791
4792     doInsert : function(where, el, values, returnEl){
4793         el = Roo.getDom(el);
4794         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4795         return returnEl ? Roo.get(newNode, true) : newNode;
4796     },
4797
4798     /**
4799      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4800      * @param {String/HTMLElement/Roo.Element} el The context element
4801      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4802      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4803      * @return {HTMLElement/Roo.Element} The new node or Element
4804      */
4805     overwrite : function(el, values, returnElement){
4806         el = Roo.getDom(el);
4807         el.innerHTML = this.applyTemplate(values);
4808         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4809     }
4810 };
4811 /**
4812  * Alias for {@link #applyTemplate}
4813  * @method
4814  */
4815 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4816
4817 // backwards compat
4818 Roo.DomHelper.Template = Roo.Template;
4819
4820 /**
4821  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4822  * @param {String/HTMLElement} el A DOM element or its id
4823  * @returns {Roo.Template} The created template
4824  * @static
4825  */
4826 Roo.Template.from = function(el){
4827     el = Roo.getDom(el);
4828     return new Roo.Template(el.value || el.innerHTML);
4829 };/*
4830  * Based on:
4831  * Ext JS Library 1.1.1
4832  * Copyright(c) 2006-2007, Ext JS, LLC.
4833  *
4834  * Originally Released Under LGPL - original licence link has changed is not relivant.
4835  *
4836  * Fork - LGPL
4837  * <script type="text/javascript">
4838  */
4839  
4840
4841 /*
4842  * This is code is also distributed under MIT license for use
4843  * with jQuery and prototype JavaScript libraries.
4844  */
4845 /**
4846  * @class Roo.DomQuery
4847 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4848 <p>
4849 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4850
4851 <p>
4852 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4853 </p>
4854 <h4>Element Selectors:</h4>
4855 <ul class="list">
4856     <li> <b>*</b> any element</li>
4857     <li> <b>E</b> an element with the tag E</li>
4858     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4859     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4860     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4861     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4862 </ul>
4863 <h4>Attribute Selectors:</h4>
4864 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4865 <ul class="list">
4866     <li> <b>E[foo]</b> has an attribute "foo"</li>
4867     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4868     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4869     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4870     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4871     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4872     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4873 </ul>
4874 <h4>Pseudo Classes:</h4>
4875 <ul class="list">
4876     <li> <b>E:first-child</b> E is the first child of its parent</li>
4877     <li> <b>E:last-child</b> E is the last child of its parent</li>
4878     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4879     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4880     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4881     <li> <b>E:only-child</b> E is the only child of its parent</li>
4882     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4883     <li> <b>E:first</b> the first E in the resultset</li>
4884     <li> <b>E:last</b> the last E in the resultset</li>
4885     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4886     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4887     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4888     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4889     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4890     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4891     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4892     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4893     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4894 </ul>
4895 <h4>CSS Value Selectors:</h4>
4896 <ul class="list">
4897     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4898     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4899     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4900     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4901     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4902     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4903 </ul>
4904  * @singleton
4905  */
4906 Roo.DomQuery = function(){
4907     var cache = {}, simpleCache = {}, valueCache = {};
4908     var nonSpace = /\S/;
4909     var trimRe = /^\s+|\s+$/g;
4910     var tplRe = /\{(\d+)\}/g;
4911     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4912     var tagTokenRe = /^(#)?([\w-\*]+)/;
4913     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4914
4915     function child(p, index){
4916         var i = 0;
4917         var n = p.firstChild;
4918         while(n){
4919             if(n.nodeType == 1){
4920                if(++i == index){
4921                    return n;
4922                }
4923             }
4924             n = n.nextSibling;
4925         }
4926         return null;
4927     };
4928
4929     function next(n){
4930         while((n = n.nextSibling) && n.nodeType != 1);
4931         return n;
4932     };
4933
4934     function prev(n){
4935         while((n = n.previousSibling) && n.nodeType != 1);
4936         return n;
4937     };
4938
4939     function children(d){
4940         var n = d.firstChild, ni = -1;
4941             while(n){
4942                 var nx = n.nextSibling;
4943                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4944                     d.removeChild(n);
4945                 }else{
4946                     n.nodeIndex = ++ni;
4947                 }
4948                 n = nx;
4949             }
4950             return this;
4951         };
4952
4953     function byClassName(c, a, v){
4954         if(!v){
4955             return c;
4956         }
4957         var r = [], ri = -1, cn;
4958         for(var i = 0, ci; ci = c[i]; i++){
4959             if((' '+ci.className+' ').indexOf(v) != -1){
4960                 r[++ri] = ci;
4961             }
4962         }
4963         return r;
4964     };
4965
4966     function attrValue(n, attr){
4967         if(!n.tagName && typeof n.length != "undefined"){
4968             n = n[0];
4969         }
4970         if(!n){
4971             return null;
4972         }
4973         if(attr == "for"){
4974             return n.htmlFor;
4975         }
4976         if(attr == "class" || attr == "className"){
4977             return n.className;
4978         }
4979         return n.getAttribute(attr) || n[attr];
4980
4981     };
4982
4983     function getNodes(ns, mode, tagName){
4984         var result = [], ri = -1, cs;
4985         if(!ns){
4986             return result;
4987         }
4988         tagName = tagName || "*";
4989         if(typeof ns.getElementsByTagName != "undefined"){
4990             ns = [ns];
4991         }
4992         if(!mode){
4993             for(var i = 0, ni; ni = ns[i]; i++){
4994                 cs = ni.getElementsByTagName(tagName);
4995                 for(var j = 0, ci; ci = cs[j]; j++){
4996                     result[++ri] = ci;
4997                 }
4998             }
4999         }else if(mode == "/" || mode == ">"){
5000             var utag = tagName.toUpperCase();
5001             for(var i = 0, ni, cn; ni = ns[i]; i++){
5002                 cn = ni.children || ni.childNodes;
5003                 for(var j = 0, cj; cj = cn[j]; j++){
5004                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5005                         result[++ri] = cj;
5006                     }
5007                 }
5008             }
5009         }else if(mode == "+"){
5010             var utag = tagName.toUpperCase();
5011             for(var i = 0, n; n = ns[i]; i++){
5012                 while((n = n.nextSibling) && n.nodeType != 1);
5013                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5014                     result[++ri] = n;
5015                 }
5016             }
5017         }else if(mode == "~"){
5018             for(var i = 0, n; n = ns[i]; i++){
5019                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5020                 if(n){
5021                     result[++ri] = n;
5022                 }
5023             }
5024         }
5025         return result;
5026     };
5027
5028     function concat(a, b){
5029         if(b.slice){
5030             return a.concat(b);
5031         }
5032         for(var i = 0, l = b.length; i < l; i++){
5033             a[a.length] = b[i];
5034         }
5035         return a;
5036     }
5037
5038     function byTag(cs, tagName){
5039         if(cs.tagName || cs == document){
5040             cs = [cs];
5041         }
5042         if(!tagName){
5043             return cs;
5044         }
5045         var r = [], ri = -1;
5046         tagName = tagName.toLowerCase();
5047         for(var i = 0, ci; ci = cs[i]; i++){
5048             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5049                 r[++ri] = ci;
5050             }
5051         }
5052         return r;
5053     };
5054
5055     function byId(cs, attr, id){
5056         if(cs.tagName || cs == document){
5057             cs = [cs];
5058         }
5059         if(!id){
5060             return cs;
5061         }
5062         var r = [], ri = -1;
5063         for(var i = 0,ci; ci = cs[i]; i++){
5064             if(ci && ci.id == id){
5065                 r[++ri] = ci;
5066                 return r;
5067             }
5068         }
5069         return r;
5070     };
5071
5072     function byAttribute(cs, attr, value, op, custom){
5073         var r = [], ri = -1, st = custom=="{";
5074         var f = Roo.DomQuery.operators[op];
5075         for(var i = 0, ci; ci = cs[i]; i++){
5076             var a;
5077             if(st){
5078                 a = Roo.DomQuery.getStyle(ci, attr);
5079             }
5080             else if(attr == "class" || attr == "className"){
5081                 a = ci.className;
5082             }else if(attr == "for"){
5083                 a = ci.htmlFor;
5084             }else if(attr == "href"){
5085                 a = ci.getAttribute("href", 2);
5086             }else{
5087                 a = ci.getAttribute(attr);
5088             }
5089             if((f && f(a, value)) || (!f && a)){
5090                 r[++ri] = ci;
5091             }
5092         }
5093         return r;
5094     };
5095
5096     function byPseudo(cs, name, value){
5097         return Roo.DomQuery.pseudos[name](cs, value);
5098     };
5099
5100     // This is for IE MSXML which does not support expandos.
5101     // IE runs the same speed using setAttribute, however FF slows way down
5102     // and Safari completely fails so they need to continue to use expandos.
5103     var isIE = window.ActiveXObject ? true : false;
5104
5105     // this eval is stop the compressor from
5106     // renaming the variable to something shorter
5107     
5108     /** eval:var:batch */
5109     var batch = 30803; 
5110
5111     var key = 30803;
5112
5113     function nodupIEXml(cs){
5114         var d = ++key;
5115         cs[0].setAttribute("_nodup", d);
5116         var r = [cs[0]];
5117         for(var i = 1, len = cs.length; i < len; i++){
5118             var c = cs[i];
5119             if(!c.getAttribute("_nodup") != d){
5120                 c.setAttribute("_nodup", d);
5121                 r[r.length] = c;
5122             }
5123         }
5124         for(var i = 0, len = cs.length; i < len; i++){
5125             cs[i].removeAttribute("_nodup");
5126         }
5127         return r;
5128     }
5129
5130     function nodup(cs){
5131         if(!cs){
5132             return [];
5133         }
5134         var len = cs.length, c, i, r = cs, cj, ri = -1;
5135         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5136             return cs;
5137         }
5138         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5139             return nodupIEXml(cs);
5140         }
5141         var d = ++key;
5142         cs[0]._nodup = d;
5143         for(i = 1; c = cs[i]; i++){
5144             if(c._nodup != d){
5145                 c._nodup = d;
5146             }else{
5147                 r = [];
5148                 for(var j = 0; j < i; j++){
5149                     r[++ri] = cs[j];
5150                 }
5151                 for(j = i+1; cj = cs[j]; j++){
5152                     if(cj._nodup != d){
5153                         cj._nodup = d;
5154                         r[++ri] = cj;
5155                     }
5156                 }
5157                 return r;
5158             }
5159         }
5160         return r;
5161     }
5162
5163     function quickDiffIEXml(c1, c2){
5164         var d = ++key;
5165         for(var i = 0, len = c1.length; i < len; i++){
5166             c1[i].setAttribute("_qdiff", d);
5167         }
5168         var r = [];
5169         for(var i = 0, len = c2.length; i < len; i++){
5170             if(c2[i].getAttribute("_qdiff") != d){
5171                 r[r.length] = c2[i];
5172             }
5173         }
5174         for(var i = 0, len = c1.length; i < len; i++){
5175            c1[i].removeAttribute("_qdiff");
5176         }
5177         return r;
5178     }
5179
5180     function quickDiff(c1, c2){
5181         var len1 = c1.length;
5182         if(!len1){
5183             return c2;
5184         }
5185         if(isIE && c1[0].selectSingleNode){
5186             return quickDiffIEXml(c1, c2);
5187         }
5188         var d = ++key;
5189         for(var i = 0; i < len1; i++){
5190             c1[i]._qdiff = d;
5191         }
5192         var r = [];
5193         for(var i = 0, len = c2.length; i < len; i++){
5194             if(c2[i]._qdiff != d){
5195                 r[r.length] = c2[i];
5196             }
5197         }
5198         return r;
5199     }
5200
5201     function quickId(ns, mode, root, id){
5202         if(ns == root){
5203            var d = root.ownerDocument || root;
5204            return d.getElementById(id);
5205         }
5206         ns = getNodes(ns, mode, "*");
5207         return byId(ns, null, id);
5208     }
5209
5210     return {
5211         getStyle : function(el, name){
5212             return Roo.fly(el).getStyle(name);
5213         },
5214         /**
5215          * Compiles a selector/xpath query into a reusable function. The returned function
5216          * takes one parameter "root" (optional), which is the context node from where the query should start.
5217          * @param {String} selector The selector/xpath query
5218          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5219          * @return {Function}
5220          */
5221         compile : function(path, type){
5222             type = type || "select";
5223             
5224             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5225             var q = path, mode, lq;
5226             var tk = Roo.DomQuery.matchers;
5227             var tklen = tk.length;
5228             var mm;
5229             Roo.log('path!!!');
5230             Roo.log(path)
5231             
5232             Roo.log('compile!!!');
5233             Roo.log(q);
5234             // accept leading mode switch
5235             Roo.log('modeRe');
5236             Roo.log(modeRe);
5237             var lmode = q.match(modeRe);
5238             
5239             Roo.log('lmode');
5240             Roo.log(lmode);
5241             
5242             if(lmode && lmode[1]){
5243                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5244                 q = q.replace(lmode[1], "");
5245             }
5246             // strip leading slashes
5247             while(path.substr(0, 1)=="/"){
5248                 path = path.substr(1);
5249             }
5250             Roo.log('lg!!!');
5251             Roo.log(lq);
5252             while(q && lq != q){
5253                 lq = q;
5254                 var tm = q.match(tagTokenRe);
5255                 Roo.log('tm');
5256                 Roo.log(tm);
5257                 if(type == "select"){
5258                     if(tm){
5259                         if(tm[1] == "#"){
5260                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5261                         }else{
5262                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5263                         }
5264                         q = q.replace(tm[0], "");
5265                     }else if(q.substr(0, 1) != '@'){
5266                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5267                     }
5268                 }else{
5269                     if(tm){
5270                         if(tm[1] == "#"){
5271                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5272                         }else{
5273                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5274                         }
5275                         q = q.replace(tm[0], "");
5276                     }
5277                 }
5278                 while(!(mm = q.match(modeRe))){
5279                     var matched = false;
5280                     for(var j = 0; j < tklen; j++){
5281                         var t = tk[j];
5282                         var m = q.match(t.re);
5283                         if(m){
5284                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5285                                                     return m[i];
5286                                                 });
5287                             q = q.replace(m[0], "");
5288                             matched = true;
5289                             break;
5290                         }
5291                     }
5292                     // prevent infinite loop on bad selector
5293                     if(!matched){
5294                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5295                     }
5296                 }
5297                 if(mm[1]){
5298                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5299                     q = q.replace(mm[1], "");
5300                 }
5301             }
5302             fn[fn.length] = "return nodup(n);\n}";
5303             
5304              /** 
5305               * list of variables that need from compression as they are used by eval.
5306              *  eval:var:batch 
5307              *  eval:var:nodup
5308              *  eval:var:byTag
5309              *  eval:var:ById
5310              *  eval:var:getNodes
5311              *  eval:var:quickId
5312              *  eval:var:mode
5313              *  eval:var:root
5314              *  eval:var:n
5315              *  eval:var:byClassName
5316              *  eval:var:byPseudo
5317              *  eval:var:byAttribute
5318              *  eval:var:attrValue
5319              * 
5320              **/ 
5321             eval(fn.join(""));
5322             return f;
5323         },
5324
5325         /**
5326          * Selects a group of elements.
5327          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5328          * @param {Node} root (optional) The start of the query (defaults to document).
5329          * @return {Array}
5330          */
5331         select : function(path, root, type){
5332             if(!root || root == document){
5333                 root = document;
5334             }
5335             if(typeof root == "string"){
5336                 root = document.getElementById(root);
5337             }
5338             var paths = path.split(",");
5339             var results = [];
5340             for(var i = 0, len = paths.length; i < len; i++){
5341                 var p = paths[i].replace(trimRe, "");
5342                 if(!cache[p]){
5343                     Roo.log('p!!!');
5344                     Roo.log(p);
5345                     cache[p] = Roo.DomQuery.compile(p);
5346                     if(!cache[p]){
5347                         throw p + " is not a valid selector";
5348                     }
5349                 }
5350                 var result = cache[p](root);
5351                 if(result && result != document){
5352                     results = results.concat(result);
5353                 }
5354             }
5355             if(paths.length > 1){
5356                 return nodup(results);
5357             }
5358             return results;
5359         },
5360
5361         /**
5362          * Selects a single element.
5363          * @param {String} selector The selector/xpath query
5364          * @param {Node} root (optional) The start of the query (defaults to document).
5365          * @return {Element}
5366          */
5367         selectNode : function(path, root){
5368             return Roo.DomQuery.select(path, root)[0];
5369         },
5370
5371         /**
5372          * Selects the value of a node, optionally replacing null with the defaultValue.
5373          * @param {String} selector The selector/xpath query
5374          * @param {Node} root (optional) The start of the query (defaults to document).
5375          * @param {String} defaultValue
5376          */
5377         selectValue : function(path, root, defaultValue){
5378             path = path.replace(trimRe, "");
5379             if(!valueCache[path]){
5380                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5381             }
5382             var n = valueCache[path](root);
5383             n = n[0] ? n[0] : n;
5384             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5385             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5386         },
5387
5388         /**
5389          * Selects the value of a node, parsing integers and floats.
5390          * @param {String} selector The selector/xpath query
5391          * @param {Node} root (optional) The start of the query (defaults to document).
5392          * @param {Number} defaultValue
5393          * @return {Number}
5394          */
5395         selectNumber : function(path, root, defaultValue){
5396             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5397             return parseFloat(v);
5398         },
5399
5400         /**
5401          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5402          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5403          * @param {String} selector The simple selector to test
5404          * @return {Boolean}
5405          */
5406         is : function(el, ss){
5407             if(typeof el == "string"){
5408                 el = document.getElementById(el);
5409             }
5410             var isArray = (el instanceof Array);
5411             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5412             return isArray ? (result.length == el.length) : (result.length > 0);
5413         },
5414
5415         /**
5416          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5417          * @param {Array} el An array of elements to filter
5418          * @param {String} selector The simple selector to test
5419          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5420          * the selector instead of the ones that match
5421          * @return {Array}
5422          */
5423         filter : function(els, ss, nonMatches){
5424             ss = ss.replace(trimRe, "");
5425             if(!simpleCache[ss]){
5426                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5427             }
5428             var result = simpleCache[ss](els);
5429             return nonMatches ? quickDiff(result, els) : result;
5430         },
5431
5432         /**
5433          * Collection of matching regular expressions and code snippets.
5434          */
5435         matchers : [{
5436                 re: /^\.([\w-]+)/,
5437                 select: 'n = byClassName(n, null, " {1} ");'
5438             }, {
5439                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5440                 select: 'n = byPseudo(n, "{1}", "{2}");'
5441             },{
5442                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5443                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5444             }, {
5445                 re: /^#([\w-]+)/,
5446                 select: 'n = byId(n, null, "{1}");'
5447             },{
5448                 re: /^@([\w-]+)/,
5449                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5450             }
5451         ],
5452
5453         /**
5454          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5455          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
5456          */
5457         operators : {
5458             "=" : function(a, v){
5459                 return a == v;
5460             },
5461             "!=" : function(a, v){
5462                 return a != v;
5463             },
5464             "^=" : function(a, v){
5465                 return a && a.substr(0, v.length) == v;
5466             },
5467             "$=" : function(a, v){
5468                 return a && a.substr(a.length-v.length) == v;
5469             },
5470             "*=" : function(a, v){
5471                 return a && a.indexOf(v) !== -1;
5472             },
5473             "%=" : function(a, v){
5474                 return (a % v) == 0;
5475             },
5476             "|=" : function(a, v){
5477                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5478             },
5479             "~=" : function(a, v){
5480                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5481             }
5482         },
5483
5484         /**
5485          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5486          * and the argument (if any) supplied in the selector.
5487          */
5488         pseudos : {
5489             "first-child" : function(c){
5490                 var r = [], ri = -1, n;
5491                 for(var i = 0, ci; ci = n = c[i]; i++){
5492                     while((n = n.previousSibling) && n.nodeType != 1);
5493                     if(!n){
5494                         r[++ri] = ci;
5495                     }
5496                 }
5497                 return r;
5498             },
5499
5500             "last-child" : function(c){
5501                 var r = [], ri = -1, n;
5502                 for(var i = 0, ci; ci = n = c[i]; i++){
5503                     while((n = n.nextSibling) && n.nodeType != 1);
5504                     if(!n){
5505                         r[++ri] = ci;
5506                     }
5507                 }
5508                 return r;
5509             },
5510
5511             "nth-child" : function(c, a) {
5512                 var r = [], ri = -1;
5513                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5514                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5515                 for(var i = 0, n; n = c[i]; i++){
5516                     var pn = n.parentNode;
5517                     if (batch != pn._batch) {
5518                         var j = 0;
5519                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5520                             if(cn.nodeType == 1){
5521                                cn.nodeIndex = ++j;
5522                             }
5523                         }
5524                         pn._batch = batch;
5525                     }
5526                     if (f == 1) {
5527                         if (l == 0 || n.nodeIndex == l){
5528                             r[++ri] = n;
5529                         }
5530                     } else if ((n.nodeIndex + l) % f == 0){
5531                         r[++ri] = n;
5532                     }
5533                 }
5534
5535                 return r;
5536             },
5537
5538             "only-child" : function(c){
5539                 var r = [], ri = -1;;
5540                 for(var i = 0, ci; ci = c[i]; i++){
5541                     if(!prev(ci) && !next(ci)){
5542                         r[++ri] = ci;
5543                     }
5544                 }
5545                 return r;
5546             },
5547
5548             "empty" : function(c){
5549                 var r = [], ri = -1;
5550                 for(var i = 0, ci; ci = c[i]; i++){
5551                     var cns = ci.childNodes, j = 0, cn, empty = true;
5552                     while(cn = cns[j]){
5553                         ++j;
5554                         if(cn.nodeType == 1 || cn.nodeType == 3){
5555                             empty = false;
5556                             break;
5557                         }
5558                     }
5559                     if(empty){
5560                         r[++ri] = ci;
5561                     }
5562                 }
5563                 return r;
5564             },
5565
5566             "contains" : function(c, v){
5567                 var r = [], ri = -1;
5568                 for(var i = 0, ci; ci = c[i]; i++){
5569                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5570                         r[++ri] = ci;
5571                     }
5572                 }
5573                 return r;
5574             },
5575
5576             "nodeValue" : function(c, v){
5577                 var r = [], ri = -1;
5578                 for(var i = 0, ci; ci = c[i]; i++){
5579                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5580                         r[++ri] = ci;
5581                     }
5582                 }
5583                 return r;
5584             },
5585
5586             "checked" : function(c){
5587                 var r = [], ri = -1;
5588                 for(var i = 0, ci; ci = c[i]; i++){
5589                     if(ci.checked == true){
5590                         r[++ri] = ci;
5591                     }
5592                 }
5593                 return r;
5594             },
5595
5596             "not" : function(c, ss){
5597                 return Roo.DomQuery.filter(c, ss, true);
5598             },
5599
5600             "odd" : function(c){
5601                 return this["nth-child"](c, "odd");
5602             },
5603
5604             "even" : function(c){
5605                 return this["nth-child"](c, "even");
5606             },
5607
5608             "nth" : function(c, a){
5609                 return c[a-1] || [];
5610             },
5611
5612             "first" : function(c){
5613                 return c[0] || [];
5614             },
5615
5616             "last" : function(c){
5617                 return c[c.length-1] || [];
5618             },
5619
5620             "has" : function(c, ss){
5621                 var s = Roo.DomQuery.select;
5622                 var r = [], ri = -1;
5623                 for(var i = 0, ci; ci = c[i]; i++){
5624                     if(s(ss, ci).length > 0){
5625                         r[++ri] = ci;
5626                     }
5627                 }
5628                 return r;
5629             },
5630
5631             "next" : function(c, ss){
5632                 var is = Roo.DomQuery.is;
5633                 var r = [], ri = -1;
5634                 for(var i = 0, ci; ci = c[i]; i++){
5635                     var n = next(ci);
5636                     if(n && is(n, ss)){
5637                         r[++ri] = ci;
5638                     }
5639                 }
5640                 return r;
5641             },
5642
5643             "prev" : function(c, ss){
5644                 var is = Roo.DomQuery.is;
5645                 var r = [], ri = -1;
5646                 for(var i = 0, ci; ci = c[i]; i++){
5647                     var n = prev(ci);
5648                     if(n && is(n, ss)){
5649                         r[++ri] = ci;
5650                     }
5651                 }
5652                 return r;
5653             }
5654         }
5655     };
5656 }();
5657
5658 /**
5659  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5660  * @param {String} path The selector/xpath query
5661  * @param {Node} root (optional) The start of the query (defaults to document).
5662  * @return {Array}
5663  * @member Roo
5664  * @method query
5665  */
5666 Roo.query = Roo.DomQuery.select;
5667 /*
5668  * Based on:
5669  * Ext JS Library 1.1.1
5670  * Copyright(c) 2006-2007, Ext JS, LLC.
5671  *
5672  * Originally Released Under LGPL - original licence link has changed is not relivant.
5673  *
5674  * Fork - LGPL
5675  * <script type="text/javascript">
5676  */
5677
5678 /**
5679  * @class Roo.util.Observable
5680  * Base class that provides a common interface for publishing events. Subclasses are expected to
5681  * to have a property "events" with all the events defined.<br>
5682  * For example:
5683  * <pre><code>
5684  Employee = function(name){
5685     this.name = name;
5686     this.addEvents({
5687         "fired" : true,
5688         "quit" : true
5689     });
5690  }
5691  Roo.extend(Employee, Roo.util.Observable);
5692 </code></pre>
5693  * @param {Object} config properties to use (incuding events / listeners)
5694  */
5695
5696 Roo.util.Observable = function(cfg){
5697     
5698     cfg = cfg|| {};
5699     this.addEvents(cfg.events || {});
5700     if (cfg.events) {
5701         delete cfg.events; // make sure
5702     }
5703      
5704     Roo.apply(this, cfg);
5705     
5706     if(this.listeners){
5707         this.on(this.listeners);
5708         delete this.listeners;
5709     }
5710 };
5711 Roo.util.Observable.prototype = {
5712     /** 
5713  * @cfg {Object} listeners  list of events and functions to call for this object, 
5714  * For example :
5715  * <pre><code>
5716     listeners :  { 
5717        'click' : function(e) {
5718            ..... 
5719         } ,
5720         .... 
5721     } 
5722   </code></pre>
5723  */
5724     
5725     
5726     /**
5727      * Fires the specified event with the passed parameters (minus the event name).
5728      * @param {String} eventName
5729      * @param {Object...} args Variable number of parameters are passed to handlers
5730      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5731      */
5732     fireEvent : function(){
5733         var ce = this.events[arguments[0].toLowerCase()];
5734         if(typeof ce == "object"){
5735             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5736         }else{
5737             return true;
5738         }
5739     },
5740
5741     // private
5742     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5743
5744     /**
5745      * Appends an event handler to this component
5746      * @param {String}   eventName The type of event to listen for
5747      * @param {Function} handler The method the event invokes
5748      * @param {Object}   scope (optional) The scope in which to execute the handler
5749      * function. The handler function's "this" context.
5750      * @param {Object}   options (optional) An object containing handler configuration
5751      * properties. This may contain any of the following properties:<ul>
5752      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5753      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5754      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5755      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5756      * by the specified number of milliseconds. If the event fires again within that time, the original
5757      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5758      * </ul><br>
5759      * <p>
5760      * <b>Combining Options</b><br>
5761      * Using the options argument, it is possible to combine different types of listeners:<br>
5762      * <br>
5763      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5764                 <pre><code>
5765                 el.on('click', this.onClick, this, {
5766                         single: true,
5767                 delay: 100,
5768                 forumId: 4
5769                 });
5770                 </code></pre>
5771      * <p>
5772      * <b>Attaching multiple handlers in 1 call</b><br>
5773      * The method also allows for a single argument to be passed which is a config object containing properties
5774      * which specify multiple handlers.
5775      * <pre><code>
5776                 el.on({
5777                         'click': {
5778                         fn: this.onClick,
5779                         scope: this,
5780                         delay: 100
5781                 }, 
5782                 'mouseover': {
5783                         fn: this.onMouseOver,
5784                         scope: this
5785                 },
5786                 'mouseout': {
5787                         fn: this.onMouseOut,
5788                         scope: this
5789                 }
5790                 });
5791                 </code></pre>
5792      * <p>
5793      * Or a shorthand syntax which passes the same scope object to all handlers:
5794         <pre><code>
5795                 el.on({
5796                         'click': this.onClick,
5797                 'mouseover': this.onMouseOver,
5798                 'mouseout': this.onMouseOut,
5799                 scope: this
5800                 });
5801                 </code></pre>
5802      */
5803     addListener : function(eventName, fn, scope, o){
5804         if(typeof eventName == "object"){
5805             o = eventName;
5806             for(var e in o){
5807                 if(this.filterOptRe.test(e)){
5808                     continue;
5809                 }
5810                 if(typeof o[e] == "function"){
5811                     // shared options
5812                     this.addListener(e, o[e], o.scope,  o);
5813                 }else{
5814                     // individual options
5815                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5816                 }
5817             }
5818             return;
5819         }
5820         o = (!o || typeof o == "boolean") ? {} : o;
5821         eventName = eventName.toLowerCase();
5822         var ce = this.events[eventName] || true;
5823         if(typeof ce == "boolean"){
5824             ce = new Roo.util.Event(this, eventName);
5825             this.events[eventName] = ce;
5826         }
5827         ce.addListener(fn, scope, o);
5828     },
5829
5830     /**
5831      * Removes a listener
5832      * @param {String}   eventName     The type of event to listen for
5833      * @param {Function} handler        The handler to remove
5834      * @param {Object}   scope  (optional) The scope (this object) for the handler
5835      */
5836     removeListener : function(eventName, fn, scope){
5837         var ce = this.events[eventName.toLowerCase()];
5838         if(typeof ce == "object"){
5839             ce.removeListener(fn, scope);
5840         }
5841     },
5842
5843     /**
5844      * Removes all listeners for this object
5845      */
5846     purgeListeners : function(){
5847         for(var evt in this.events){
5848             if(typeof this.events[evt] == "object"){
5849                  this.events[evt].clearListeners();
5850             }
5851         }
5852     },
5853
5854     relayEvents : function(o, events){
5855         var createHandler = function(ename){
5856             return function(){
5857                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5858             };
5859         };
5860         for(var i = 0, len = events.length; i < len; i++){
5861             var ename = events[i];
5862             if(!this.events[ename]){ this.events[ename] = true; };
5863             o.on(ename, createHandler(ename), this);
5864         }
5865     },
5866
5867     /**
5868      * Used to define events on this Observable
5869      * @param {Object} object The object with the events defined
5870      */
5871     addEvents : function(o){
5872         if(!this.events){
5873             this.events = {};
5874         }
5875         Roo.applyIf(this.events, o);
5876     },
5877
5878     /**
5879      * Checks to see if this object has any listeners for a specified event
5880      * @param {String} eventName The name of the event to check for
5881      * @return {Boolean} True if the event is being listened for, else false
5882      */
5883     hasListener : function(eventName){
5884         var e = this.events[eventName];
5885         return typeof e == "object" && e.listeners.length > 0;
5886     }
5887 };
5888 /**
5889  * Appends an event handler to this element (shorthand for addListener)
5890  * @param {String}   eventName     The type of event to listen for
5891  * @param {Function} handler        The method the event invokes
5892  * @param {Object}   scope (optional) The scope in which to execute the handler
5893  * function. The handler function's "this" context.
5894  * @param {Object}   options  (optional)
5895  * @method
5896  */
5897 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5898 /**
5899  * Removes a listener (shorthand for removeListener)
5900  * @param {String}   eventName     The type of event to listen for
5901  * @param {Function} handler        The handler to remove
5902  * @param {Object}   scope  (optional) The scope (this object) for the handler
5903  * @method
5904  */
5905 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5906
5907 /**
5908  * Starts capture on the specified Observable. All events will be passed
5909  * to the supplied function with the event name + standard signature of the event
5910  * <b>before</b> the event is fired. If the supplied function returns false,
5911  * the event will not fire.
5912  * @param {Observable} o The Observable to capture
5913  * @param {Function} fn The function to call
5914  * @param {Object} scope (optional) The scope (this object) for the fn
5915  * @static
5916  */
5917 Roo.util.Observable.capture = function(o, fn, scope){
5918     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5919 };
5920
5921 /**
5922  * Removes <b>all</b> added captures from the Observable.
5923  * @param {Observable} o The Observable to release
5924  * @static
5925  */
5926 Roo.util.Observable.releaseCapture = function(o){
5927     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5928 };
5929
5930 (function(){
5931
5932     var createBuffered = function(h, o, scope){
5933         var task = new Roo.util.DelayedTask();
5934         return function(){
5935             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5936         };
5937     };
5938
5939     var createSingle = function(h, e, fn, scope){
5940         return function(){
5941             e.removeListener(fn, scope);
5942             return h.apply(scope, arguments);
5943         };
5944     };
5945
5946     var createDelayed = function(h, o, scope){
5947         return function(){
5948             var args = Array.prototype.slice.call(arguments, 0);
5949             setTimeout(function(){
5950                 h.apply(scope, args);
5951             }, o.delay || 10);
5952         };
5953     };
5954
5955     Roo.util.Event = function(obj, name){
5956         this.name = name;
5957         this.obj = obj;
5958         this.listeners = [];
5959     };
5960
5961     Roo.util.Event.prototype = {
5962         addListener : function(fn, scope, options){
5963             var o = options || {};
5964             scope = scope || this.obj;
5965             if(!this.isListening(fn, scope)){
5966                 var l = {fn: fn, scope: scope, options: o};
5967                 var h = fn;
5968                 if(o.delay){
5969                     h = createDelayed(h, o, scope);
5970                 }
5971                 if(o.single){
5972                     h = createSingle(h, this, fn, scope);
5973                 }
5974                 if(o.buffer){
5975                     h = createBuffered(h, o, scope);
5976                 }
5977                 l.fireFn = h;
5978                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5979                     this.listeners.push(l);
5980                 }else{
5981                     this.listeners = this.listeners.slice(0);
5982                     this.listeners.push(l);
5983                 }
5984             }
5985         },
5986
5987         findListener : function(fn, scope){
5988             scope = scope || this.obj;
5989             var ls = this.listeners;
5990             for(var i = 0, len = ls.length; i < len; i++){
5991                 var l = ls[i];
5992                 if(l.fn == fn && l.scope == scope){
5993                     return i;
5994                 }
5995             }
5996             return -1;
5997         },
5998
5999         isListening : function(fn, scope){
6000             return this.findListener(fn, scope) != -1;
6001         },
6002
6003         removeListener : function(fn, scope){
6004             var index;
6005             if((index = this.findListener(fn, scope)) != -1){
6006                 if(!this.firing){
6007                     this.listeners.splice(index, 1);
6008                 }else{
6009                     this.listeners = this.listeners.slice(0);
6010                     this.listeners.splice(index, 1);
6011                 }
6012                 return true;
6013             }
6014             return false;
6015         },
6016
6017         clearListeners : function(){
6018             this.listeners = [];
6019         },
6020
6021         fire : function(){
6022             var ls = this.listeners, scope, len = ls.length;
6023             if(len > 0){
6024                 this.firing = true;
6025                 var args = Array.prototype.slice.call(arguments, 0);
6026                 for(var i = 0; i < len; i++){
6027                     var l = ls[i];
6028                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6029                         this.firing = false;
6030                         return false;
6031                     }
6032                 }
6033                 this.firing = false;
6034             }
6035             return true;
6036         }
6037     };
6038 })();/*
6039  * Based on:
6040  * Ext JS Library 1.1.1
6041  * Copyright(c) 2006-2007, Ext JS, LLC.
6042  *
6043  * Originally Released Under LGPL - original licence link has changed is not relivant.
6044  *
6045  * Fork - LGPL
6046  * <script type="text/javascript">
6047  */
6048
6049 /**
6050  * @class Roo.EventManager
6051  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6052  * several useful events directly.
6053  * See {@link Roo.EventObject} for more details on normalized event objects.
6054  * @singleton
6055  */
6056 Roo.EventManager = function(){
6057     var docReadyEvent, docReadyProcId, docReadyState = false;
6058     var resizeEvent, resizeTask, textEvent, textSize;
6059     var E = Roo.lib.Event;
6060     var D = Roo.lib.Dom;
6061
6062
6063     var fireDocReady = function(){
6064         if(!docReadyState){
6065             docReadyState = true;
6066             Roo.isReady = true;
6067             if(docReadyProcId){
6068                 clearInterval(docReadyProcId);
6069             }
6070             if(Roo.isGecko || Roo.isOpera) {
6071                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6072             }
6073             if(Roo.isIE){
6074                 var defer = document.getElementById("ie-deferred-loader");
6075                 if(defer){
6076                     defer.onreadystatechange = null;
6077                     defer.parentNode.removeChild(defer);
6078                 }
6079             }
6080             if(docReadyEvent){
6081                 docReadyEvent.fire();
6082                 docReadyEvent.clearListeners();
6083             }
6084         }
6085     };
6086     
6087     var initDocReady = function(){
6088         docReadyEvent = new Roo.util.Event();
6089         if(Roo.isGecko || Roo.isOpera) {
6090             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6091         }else if(Roo.isIE){
6092             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6093             var defer = document.getElementById("ie-deferred-loader");
6094             defer.onreadystatechange = function(){
6095                 if(this.readyState == "complete"){
6096                     fireDocReady();
6097                 }
6098             };
6099         }else if(Roo.isSafari){ 
6100             docReadyProcId = setInterval(function(){
6101                 var rs = document.readyState;
6102                 if(rs == "complete") {
6103                     fireDocReady();     
6104                  }
6105             }, 10);
6106         }
6107         // no matter what, make sure it fires on load
6108         E.on(window, "load", fireDocReady);
6109     };
6110
6111     var createBuffered = function(h, o){
6112         var task = new Roo.util.DelayedTask(h);
6113         return function(e){
6114             // create new event object impl so new events don't wipe out properties
6115             e = new Roo.EventObjectImpl(e);
6116             task.delay(o.buffer, h, null, [e]);
6117         };
6118     };
6119
6120     var createSingle = function(h, el, ename, fn){
6121         return function(e){
6122             Roo.EventManager.removeListener(el, ename, fn);
6123             h(e);
6124         };
6125     };
6126
6127     var createDelayed = function(h, o){
6128         return function(e){
6129             // create new event object impl so new events don't wipe out properties
6130             e = new Roo.EventObjectImpl(e);
6131             setTimeout(function(){
6132                 h(e);
6133             }, o.delay || 10);
6134         };
6135     };
6136
6137     var listen = function(element, ename, opt, fn, scope){
6138         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6139         fn = fn || o.fn; scope = scope || o.scope;
6140         var el = Roo.getDom(element);
6141         if(!el){
6142             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6143         }
6144         var h = function(e){
6145             e = Roo.EventObject.setEvent(e);
6146             var t;
6147             if(o.delegate){
6148                 t = e.getTarget(o.delegate, el);
6149                 if(!t){
6150                     return;
6151                 }
6152             }else{
6153                 t = e.target;
6154             }
6155             if(o.stopEvent === true){
6156                 e.stopEvent();
6157             }
6158             if(o.preventDefault === true){
6159                e.preventDefault();
6160             }
6161             if(o.stopPropagation === true){
6162                 e.stopPropagation();
6163             }
6164
6165             if(o.normalized === false){
6166                 e = e.browserEvent;
6167             }
6168
6169             fn.call(scope || el, e, t, o);
6170         };
6171         if(o.delay){
6172             h = createDelayed(h, o);
6173         }
6174         if(o.single){
6175             h = createSingle(h, el, ename, fn);
6176         }
6177         if(o.buffer){
6178             h = createBuffered(h, o);
6179         }
6180         fn._handlers = fn._handlers || [];
6181         fn._handlers.push([Roo.id(el), ename, h]);
6182
6183         E.on(el, ename, h);
6184         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6185             el.addEventListener("DOMMouseScroll", h, false);
6186             E.on(window, 'unload', function(){
6187                 el.removeEventListener("DOMMouseScroll", h, false);
6188             });
6189         }
6190         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6191             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6192         }
6193         return h;
6194     };
6195
6196     var stopListening = function(el, ename, fn){
6197         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6198         if(hds){
6199             for(var i = 0, len = hds.length; i < len; i++){
6200                 var h = hds[i];
6201                 if(h[0] == id && h[1] == ename){
6202                     hd = h[2];
6203                     hds.splice(i, 1);
6204                     break;
6205                 }
6206             }
6207         }
6208         E.un(el, ename, hd);
6209         el = Roo.getDom(el);
6210         if(ename == "mousewheel" && el.addEventListener){
6211             el.removeEventListener("DOMMouseScroll", hd, false);
6212         }
6213         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6214             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6215         }
6216     };
6217
6218     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6219     
6220     var pub = {
6221         
6222         
6223         /** 
6224          * Fix for doc tools
6225          * @scope Roo.EventManager
6226          */
6227         
6228         
6229         /** 
6230          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6231          * object with a Roo.EventObject
6232          * @param {Function} fn        The method the event invokes
6233          * @param {Object}   scope    An object that becomes the scope of the handler
6234          * @param {boolean}  override If true, the obj passed in becomes
6235          *                             the execution scope of the listener
6236          * @return {Function} The wrapped function
6237          * @deprecated
6238          */
6239         wrap : function(fn, scope, override){
6240             return function(e){
6241                 Roo.EventObject.setEvent(e);
6242                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6243             };
6244         },
6245         
6246         /**
6247      * Appends an event handler to an element (shorthand for addListener)
6248      * @param {String/HTMLElement}   element        The html element or id to assign the
6249      * @param {String}   eventName The type of event to listen for
6250      * @param {Function} handler The method the event invokes
6251      * @param {Object}   scope (optional) The scope in which to execute the handler
6252      * function. The handler function's "this" context.
6253      * @param {Object}   options (optional) An object containing handler configuration
6254      * properties. This may contain any of the following properties:<ul>
6255      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6256      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6257      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6258      * <li>preventDefault {Boolean} True to prevent the default action</li>
6259      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6260      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6261      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6262      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6263      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6264      * by the specified number of milliseconds. If the event fires again within that time, the original
6265      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6266      * </ul><br>
6267      * <p>
6268      * <b>Combining Options</b><br>
6269      * Using the options argument, it is possible to combine different types of listeners:<br>
6270      * <br>
6271      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6272      * Code:<pre><code>
6273 el.on('click', this.onClick, this, {
6274     single: true,
6275     delay: 100,
6276     stopEvent : true,
6277     forumId: 4
6278 });</code></pre>
6279      * <p>
6280      * <b>Attaching multiple handlers in 1 call</b><br>
6281       * The method also allows for a single argument to be passed which is a config object containing properties
6282      * which specify multiple handlers.
6283      * <p>
6284      * Code:<pre><code>
6285 el.on({
6286     'click' : {
6287         fn: this.onClick
6288         scope: this,
6289         delay: 100
6290     },
6291     'mouseover' : {
6292         fn: this.onMouseOver
6293         scope: this
6294     },
6295     'mouseout' : {
6296         fn: this.onMouseOut
6297         scope: this
6298     }
6299 });</code></pre>
6300      * <p>
6301      * Or a shorthand syntax:<br>
6302      * Code:<pre><code>
6303 el.on({
6304     'click' : this.onClick,
6305     'mouseover' : this.onMouseOver,
6306     'mouseout' : this.onMouseOut
6307     scope: this
6308 });</code></pre>
6309      */
6310         addListener : function(element, eventName, fn, scope, options){
6311             if(typeof eventName == "object"){
6312                 var o = eventName;
6313                 for(var e in o){
6314                     if(propRe.test(e)){
6315                         continue;
6316                     }
6317                     if(typeof o[e] == "function"){
6318                         // shared options
6319                         listen(element, e, o, o[e], o.scope);
6320                     }else{
6321                         // individual options
6322                         listen(element, e, o[e]);
6323                     }
6324                 }
6325                 return;
6326             }
6327             return listen(element, eventName, options, fn, scope);
6328         },
6329         
6330         /**
6331          * Removes an event handler
6332          *
6333          * @param {String/HTMLElement}   element        The id or html element to remove the 
6334          *                             event from
6335          * @param {String}   eventName     The type of event
6336          * @param {Function} fn
6337          * @return {Boolean} True if a listener was actually removed
6338          */
6339         removeListener : function(element, eventName, fn){
6340             return stopListening(element, eventName, fn);
6341         },
6342         
6343         /**
6344          * Fires when the document is ready (before onload and before images are loaded). Can be 
6345          * accessed shorthanded Roo.onReady().
6346          * @param {Function} fn        The method the event invokes
6347          * @param {Object}   scope    An  object that becomes the scope of the handler
6348          * @param {boolean}  options
6349          */
6350         onDocumentReady : function(fn, scope, options){
6351             if(docReadyState){ // if it already fired
6352                 docReadyEvent.addListener(fn, scope, options);
6353                 docReadyEvent.fire();
6354                 docReadyEvent.clearListeners();
6355                 return;
6356             }
6357             if(!docReadyEvent){
6358                 initDocReady();
6359             }
6360             docReadyEvent.addListener(fn, scope, options);
6361         },
6362         
6363         /**
6364          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6365          * @param {Function} fn        The method the event invokes
6366          * @param {Object}   scope    An object that becomes the scope of the handler
6367          * @param {boolean}  options
6368          */
6369         onWindowResize : function(fn, scope, options){
6370             if(!resizeEvent){
6371                 resizeEvent = new Roo.util.Event();
6372                 resizeTask = new Roo.util.DelayedTask(function(){
6373                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6374                 });
6375                 E.on(window, "resize", function(){
6376                     if(Roo.isIE){
6377                         resizeTask.delay(50);
6378                     }else{
6379                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6380                     }
6381                 });
6382             }
6383             resizeEvent.addListener(fn, scope, options);
6384         },
6385
6386         /**
6387          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6388          * @param {Function} fn        The method the event invokes
6389          * @param {Object}   scope    An object that becomes the scope of the handler
6390          * @param {boolean}  options
6391          */
6392         onTextResize : function(fn, scope, options){
6393             if(!textEvent){
6394                 textEvent = new Roo.util.Event();
6395                 var textEl = new Roo.Element(document.createElement('div'));
6396                 textEl.dom.className = 'x-text-resize';
6397                 textEl.dom.innerHTML = 'X';
6398                 textEl.appendTo(document.body);
6399                 textSize = textEl.dom.offsetHeight;
6400                 setInterval(function(){
6401                     if(textEl.dom.offsetHeight != textSize){
6402                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6403                     }
6404                 }, this.textResizeInterval);
6405             }
6406             textEvent.addListener(fn, scope, options);
6407         },
6408
6409         /**
6410          * Removes the passed window resize listener.
6411          * @param {Function} fn        The method the event invokes
6412          * @param {Object}   scope    The scope of handler
6413          */
6414         removeResizeListener : function(fn, scope){
6415             if(resizeEvent){
6416                 resizeEvent.removeListener(fn, scope);
6417             }
6418         },
6419
6420         // private
6421         fireResize : function(){
6422             if(resizeEvent){
6423                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6424             }   
6425         },
6426         /**
6427          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6428          */
6429         ieDeferSrc : false,
6430         /**
6431          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6432          */
6433         textResizeInterval : 50
6434     };
6435     
6436     /**
6437      * Fix for doc tools
6438      * @scopeAlias pub=Roo.EventManager
6439      */
6440     
6441      /**
6442      * Appends an event handler to an element (shorthand for addListener)
6443      * @param {String/HTMLElement}   element        The html element or id to assign the
6444      * @param {String}   eventName The type of event to listen for
6445      * @param {Function} handler The method the event invokes
6446      * @param {Object}   scope (optional) The scope in which to execute the handler
6447      * function. The handler function's "this" context.
6448      * @param {Object}   options (optional) An object containing handler configuration
6449      * properties. This may contain any of the following properties:<ul>
6450      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6451      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6452      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6453      * <li>preventDefault {Boolean} True to prevent the default action</li>
6454      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6455      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6456      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6457      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6458      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6459      * by the specified number of milliseconds. If the event fires again within that time, the original
6460      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6461      * </ul><br>
6462      * <p>
6463      * <b>Combining Options</b><br>
6464      * Using the options argument, it is possible to combine different types of listeners:<br>
6465      * <br>
6466      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6467      * Code:<pre><code>
6468 el.on('click', this.onClick, this, {
6469     single: true,
6470     delay: 100,
6471     stopEvent : true,
6472     forumId: 4
6473 });</code></pre>
6474      * <p>
6475      * <b>Attaching multiple handlers in 1 call</b><br>
6476       * The method also allows for a single argument to be passed which is a config object containing properties
6477      * which specify multiple handlers.
6478      * <p>
6479      * Code:<pre><code>
6480 el.on({
6481     'click' : {
6482         fn: this.onClick
6483         scope: this,
6484         delay: 100
6485     },
6486     'mouseover' : {
6487         fn: this.onMouseOver
6488         scope: this
6489     },
6490     'mouseout' : {
6491         fn: this.onMouseOut
6492         scope: this
6493     }
6494 });</code></pre>
6495      * <p>
6496      * Or a shorthand syntax:<br>
6497      * Code:<pre><code>
6498 el.on({
6499     'click' : this.onClick,
6500     'mouseover' : this.onMouseOver,
6501     'mouseout' : this.onMouseOut
6502     scope: this
6503 });</code></pre>
6504      */
6505     pub.on = pub.addListener;
6506     pub.un = pub.removeListener;
6507
6508     pub.stoppedMouseDownEvent = new Roo.util.Event();
6509     return pub;
6510 }();
6511 /**
6512   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6513   * @param {Function} fn        The method the event invokes
6514   * @param {Object}   scope    An  object that becomes the scope of the handler
6515   * @param {boolean}  override If true, the obj passed in becomes
6516   *                             the execution scope of the listener
6517   * @member Roo
6518   * @method onReady
6519  */
6520 Roo.onReady = Roo.EventManager.onDocumentReady;
6521
6522 Roo.onReady(function(){
6523     var bd = Roo.get(document.body);
6524     if(!bd){ return; }
6525
6526     var cls = [
6527             Roo.isIE ? "roo-ie"
6528             : Roo.isGecko ? "roo-gecko"
6529             : Roo.isOpera ? "roo-opera"
6530             : Roo.isSafari ? "roo-safari" : ""];
6531
6532     if(Roo.isMac){
6533         cls.push("roo-mac");
6534     }
6535     if(Roo.isLinux){
6536         cls.push("roo-linux");
6537     }
6538     if(Roo.isBorderBox){
6539         cls.push('roo-border-box');
6540     }
6541     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6542         var p = bd.dom.parentNode;
6543         if(p){
6544             p.className += ' roo-strict';
6545         }
6546     }
6547     bd.addClass(cls.join(' '));
6548 });
6549
6550 /**
6551  * @class Roo.EventObject
6552  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6553  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6554  * Example:
6555  * <pre><code>
6556  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6557     e.preventDefault();
6558     var target = e.getTarget();
6559     ...
6560  }
6561  var myDiv = Roo.get("myDiv");
6562  myDiv.on("click", handleClick);
6563  //or
6564  Roo.EventManager.on("myDiv", 'click', handleClick);
6565  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6566  </code></pre>
6567  * @singleton
6568  */
6569 Roo.EventObject = function(){
6570     
6571     var E = Roo.lib.Event;
6572     
6573     // safari keypress events for special keys return bad keycodes
6574     var safariKeys = {
6575         63234 : 37, // left
6576         63235 : 39, // right
6577         63232 : 38, // up
6578         63233 : 40, // down
6579         63276 : 33, // page up
6580         63277 : 34, // page down
6581         63272 : 46, // delete
6582         63273 : 36, // home
6583         63275 : 35  // end
6584     };
6585
6586     // normalize button clicks
6587     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6588                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6589
6590     Roo.EventObjectImpl = function(e){
6591         if(e){
6592             this.setEvent(e.browserEvent || e);
6593         }
6594     };
6595     Roo.EventObjectImpl.prototype = {
6596         /**
6597          * Used to fix doc tools.
6598          * @scope Roo.EventObject.prototype
6599          */
6600             
6601
6602         
6603         
6604         /** The normal browser event */
6605         browserEvent : null,
6606         /** The button pressed in a mouse event */
6607         button : -1,
6608         /** True if the shift key was down during the event */
6609         shiftKey : false,
6610         /** True if the control key was down during the event */
6611         ctrlKey : false,
6612         /** True if the alt key was down during the event */
6613         altKey : false,
6614
6615         /** Key constant 
6616         * @type Number */
6617         BACKSPACE : 8,
6618         /** Key constant 
6619         * @type Number */
6620         TAB : 9,
6621         /** Key constant 
6622         * @type Number */
6623         RETURN : 13,
6624         /** Key constant 
6625         * @type Number */
6626         ENTER : 13,
6627         /** Key constant 
6628         * @type Number */
6629         SHIFT : 16,
6630         /** Key constant 
6631         * @type Number */
6632         CONTROL : 17,
6633         /** Key constant 
6634         * @type Number */
6635         ESC : 27,
6636         /** Key constant 
6637         * @type Number */
6638         SPACE : 32,
6639         /** Key constant 
6640         * @type Number */
6641         PAGEUP : 33,
6642         /** Key constant 
6643         * @type Number */
6644         PAGEDOWN : 34,
6645         /** Key constant 
6646         * @type Number */
6647         END : 35,
6648         /** Key constant 
6649         * @type Number */
6650         HOME : 36,
6651         /** Key constant 
6652         * @type Number */
6653         LEFT : 37,
6654         /** Key constant 
6655         * @type Number */
6656         UP : 38,
6657         /** Key constant 
6658         * @type Number */
6659         RIGHT : 39,
6660         /** Key constant 
6661         * @type Number */
6662         DOWN : 40,
6663         /** Key constant 
6664         * @type Number */
6665         DELETE : 46,
6666         /** Key constant 
6667         * @type Number */
6668         F5 : 116,
6669
6670            /** @private */
6671         setEvent : function(e){
6672             if(e == this || (e && e.browserEvent)){ // already wrapped
6673                 return e;
6674             }
6675             this.browserEvent = e;
6676             if(e){
6677                 // normalize buttons
6678                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6679                 if(e.type == 'click' && this.button == -1){
6680                     this.button = 0;
6681                 }
6682                 this.type = e.type;
6683                 this.shiftKey = e.shiftKey;
6684                 // mac metaKey behaves like ctrlKey
6685                 this.ctrlKey = e.ctrlKey || e.metaKey;
6686                 this.altKey = e.altKey;
6687                 // in getKey these will be normalized for the mac
6688                 this.keyCode = e.keyCode;
6689                 // keyup warnings on firefox.
6690                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6691                 // cache the target for the delayed and or buffered events
6692                 this.target = E.getTarget(e);
6693                 // same for XY
6694                 this.xy = E.getXY(e);
6695             }else{
6696                 this.button = -1;
6697                 this.shiftKey = false;
6698                 this.ctrlKey = false;
6699                 this.altKey = false;
6700                 this.keyCode = 0;
6701                 this.charCode =0;
6702                 this.target = null;
6703                 this.xy = [0, 0];
6704             }
6705             return this;
6706         },
6707
6708         /**
6709          * Stop the event (preventDefault and stopPropagation)
6710          */
6711         stopEvent : function(){
6712             if(this.browserEvent){
6713                 if(this.browserEvent.type == 'mousedown'){
6714                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6715                 }
6716                 E.stopEvent(this.browserEvent);
6717             }
6718         },
6719
6720         /**
6721          * Prevents the browsers default handling of the event.
6722          */
6723         preventDefault : function(){
6724             if(this.browserEvent){
6725                 E.preventDefault(this.browserEvent);
6726             }
6727         },
6728
6729         /** @private */
6730         isNavKeyPress : function(){
6731             var k = this.keyCode;
6732             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6733             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6734         },
6735
6736         isSpecialKey : function(){
6737             var k = this.keyCode;
6738             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6739             (k == 16) || (k == 17) ||
6740             (k >= 18 && k <= 20) ||
6741             (k >= 33 && k <= 35) ||
6742             (k >= 36 && k <= 39) ||
6743             (k >= 44 && k <= 45);
6744         },
6745         /**
6746          * Cancels bubbling of the event.
6747          */
6748         stopPropagation : function(){
6749             if(this.browserEvent){
6750                 if(this.type == 'mousedown'){
6751                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6752                 }
6753                 E.stopPropagation(this.browserEvent);
6754             }
6755         },
6756
6757         /**
6758          * Gets the key code for the event.
6759          * @return {Number}
6760          */
6761         getCharCode : function(){
6762             return this.charCode || this.keyCode;
6763         },
6764
6765         /**
6766          * Returns a normalized keyCode for the event.
6767          * @return {Number} The key code
6768          */
6769         getKey : function(){
6770             var k = this.keyCode || this.charCode;
6771             return Roo.isSafari ? (safariKeys[k] || k) : k;
6772         },
6773
6774         /**
6775          * Gets the x coordinate of the event.
6776          * @return {Number}
6777          */
6778         getPageX : function(){
6779             return this.xy[0];
6780         },
6781
6782         /**
6783          * Gets the y coordinate of the event.
6784          * @return {Number}
6785          */
6786         getPageY : function(){
6787             return this.xy[1];
6788         },
6789
6790         /**
6791          * Gets the time of the event.
6792          * @return {Number}
6793          */
6794         getTime : function(){
6795             if(this.browserEvent){
6796                 return E.getTime(this.browserEvent);
6797             }
6798             return null;
6799         },
6800
6801         /**
6802          * Gets the page coordinates of the event.
6803          * @return {Array} The xy values like [x, y]
6804          */
6805         getXY : function(){
6806             return this.xy;
6807         },
6808
6809         /**
6810          * Gets the target for the event.
6811          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6812          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6813                 search as a number or element (defaults to 10 || document.body)
6814          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6815          * @return {HTMLelement}
6816          */
6817         getTarget : function(selector, maxDepth, returnEl){
6818             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6819         },
6820         /**
6821          * Gets the related target.
6822          * @return {HTMLElement}
6823          */
6824         getRelatedTarget : function(){
6825             if(this.browserEvent){
6826                 return E.getRelatedTarget(this.browserEvent);
6827             }
6828             return null;
6829         },
6830
6831         /**
6832          * Normalizes mouse wheel delta across browsers
6833          * @return {Number} The delta
6834          */
6835         getWheelDelta : function(){
6836             var e = this.browserEvent;
6837             var delta = 0;
6838             if(e.wheelDelta){ /* IE/Opera. */
6839                 delta = e.wheelDelta/120;
6840             }else if(e.detail){ /* Mozilla case. */
6841                 delta = -e.detail/3;
6842             }
6843             return delta;
6844         },
6845
6846         /**
6847          * Returns true if the control, meta, shift or alt key was pressed during this event.
6848          * @return {Boolean}
6849          */
6850         hasModifier : function(){
6851             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6852         },
6853
6854         /**
6855          * Returns true if the target of this event equals el or is a child of el
6856          * @param {String/HTMLElement/Element} el
6857          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6858          * @return {Boolean}
6859          */
6860         within : function(el, related){
6861             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6862             return t && Roo.fly(el).contains(t);
6863         },
6864
6865         getPoint : function(){
6866             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6867         }
6868     };
6869
6870     return new Roo.EventObjectImpl();
6871 }();
6872             
6873     /*
6874  * Based on:
6875  * Ext JS Library 1.1.1
6876  * Copyright(c) 2006-2007, Ext JS, LLC.
6877  *
6878  * Originally Released Under LGPL - original licence link has changed is not relivant.
6879  *
6880  * Fork - LGPL
6881  * <script type="text/javascript">
6882  */
6883
6884  
6885 // was in Composite Element!??!?!
6886  
6887 (function(){
6888     var D = Roo.lib.Dom;
6889     var E = Roo.lib.Event;
6890     var A = Roo.lib.Anim;
6891
6892     // local style camelizing for speed
6893     var propCache = {};
6894     var camelRe = /(-[a-z])/gi;
6895     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6896     var view = document.defaultView;
6897
6898 /**
6899  * @class Roo.Element
6900  * Represents an Element in the DOM.<br><br>
6901  * Usage:<br>
6902 <pre><code>
6903 var el = Roo.get("my-div");
6904
6905 // or with getEl
6906 var el = getEl("my-div");
6907
6908 // or with a DOM element
6909 var el = Roo.get(myDivElement);
6910 </code></pre>
6911  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6912  * each call instead of constructing a new one.<br><br>
6913  * <b>Animations</b><br />
6914  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6915  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6916 <pre>
6917 Option    Default   Description
6918 --------- --------  ---------------------------------------------
6919 duration  .35       The duration of the animation in seconds
6920 easing    easeOut   The YUI easing method
6921 callback  none      A function to execute when the anim completes
6922 scope     this      The scope (this) of the callback function
6923 </pre>
6924 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6925 * manipulate the animation. Here's an example:
6926 <pre><code>
6927 var el = Roo.get("my-div");
6928
6929 // no animation
6930 el.setWidth(100);
6931
6932 // default animation
6933 el.setWidth(100, true);
6934
6935 // animation with some options set
6936 el.setWidth(100, {
6937     duration: 1,
6938     callback: this.foo,
6939     scope: this
6940 });
6941
6942 // using the "anim" property to get the Anim object
6943 var opt = {
6944     duration: 1,
6945     callback: this.foo,
6946     scope: this
6947 };
6948 el.setWidth(100, opt);
6949 ...
6950 if(opt.anim.isAnimated()){
6951     opt.anim.stop();
6952 }
6953 </code></pre>
6954 * <b> Composite (Collections of) Elements</b><br />
6955  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6956  * @constructor Create a new Element directly.
6957  * @param {String/HTMLElement} element
6958  * @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).
6959  */
6960     Roo.Element = function(element, forceNew){
6961         var dom = typeof element == "string" ?
6962                 document.getElementById(element) : element;
6963         if(!dom){ // invalid id/element
6964             return null;
6965         }
6966         var id = dom.id;
6967         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
6968             return Roo.Element.cache[id];
6969         }
6970
6971         /**
6972          * The DOM element
6973          * @type HTMLElement
6974          */
6975         this.dom = dom;
6976
6977         /**
6978          * The DOM element ID
6979          * @type String
6980          */
6981         this.id = id || Roo.id(dom);
6982     };
6983
6984     var El = Roo.Element;
6985
6986     El.prototype = {
6987         /**
6988          * The element's default display mode  (defaults to "")
6989          * @type String
6990          */
6991         originalDisplay : "",
6992
6993         visibilityMode : 1,
6994         /**
6995          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
6996          * @type String
6997          */
6998         defaultUnit : "px",
6999         /**
7000          * Sets the element's visibility mode. When setVisible() is called it
7001          * will use this to determine whether to set the visibility or the display property.
7002          * @param visMode Element.VISIBILITY or Element.DISPLAY
7003          * @return {Roo.Element} this
7004          */
7005         setVisibilityMode : function(visMode){
7006             this.visibilityMode = visMode;
7007             return this;
7008         },
7009         /**
7010          * Convenience method for setVisibilityMode(Element.DISPLAY)
7011          * @param {String} display (optional) What to set display to when visible
7012          * @return {Roo.Element} this
7013          */
7014         enableDisplayMode : function(display){
7015             this.setVisibilityMode(El.DISPLAY);
7016             if(typeof display != "undefined") this.originalDisplay = display;
7017             return this;
7018         },
7019
7020         /**
7021          * 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)
7022          * @param {String} selector The simple selector to test
7023          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7024                 search as a number or element (defaults to 10 || document.body)
7025          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7026          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7027          */
7028         findParent : function(simpleSelector, maxDepth, returnEl){
7029             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7030             maxDepth = maxDepth || 50;
7031             if(typeof maxDepth != "number"){
7032                 stopEl = Roo.getDom(maxDepth);
7033                 maxDepth = 10;
7034             }
7035             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7036                 if(dq.is(p, simpleSelector)){
7037                     return returnEl ? Roo.get(p) : p;
7038                 }
7039                 depth++;
7040                 p = p.parentNode;
7041             }
7042             return null;
7043         },
7044
7045
7046         /**
7047          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7048          * @param {String} selector The simple selector to test
7049          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7050                 search as a number or element (defaults to 10 || document.body)
7051          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7052          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7053          */
7054         findParentNode : function(simpleSelector, maxDepth, returnEl){
7055             var p = Roo.fly(this.dom.parentNode, '_internal');
7056             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7057         },
7058
7059         /**
7060          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7061          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7062          * @param {String} selector The simple selector to test
7063          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7064                 search as a number or element (defaults to 10 || document.body)
7065          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7066          */
7067         up : function(simpleSelector, maxDepth){
7068             return this.findParentNode(simpleSelector, maxDepth, true);
7069         },
7070
7071
7072
7073         /**
7074          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7075          * @param {String} selector The simple selector to test
7076          * @return {Boolean} True if this element matches the selector, else false
7077          */
7078         is : function(simpleSelector){
7079             return Roo.DomQuery.is(this.dom, simpleSelector);
7080         },
7081
7082         /**
7083          * Perform animation on this element.
7084          * @param {Object} args The YUI animation control args
7085          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7086          * @param {Function} onComplete (optional) Function to call when animation completes
7087          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7088          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7089          * @return {Roo.Element} this
7090          */
7091         animate : function(args, duration, onComplete, easing, animType){
7092             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7093             return this;
7094         },
7095
7096         /*
7097          * @private Internal animation call
7098          */
7099         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7100             animType = animType || 'run';
7101             opt = opt || {};
7102             var anim = Roo.lib.Anim[animType](
7103                 this.dom, args,
7104                 (opt.duration || defaultDur) || .35,
7105                 (opt.easing || defaultEase) || 'easeOut',
7106                 function(){
7107                     Roo.callback(cb, this);
7108                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7109                 },
7110                 this
7111             );
7112             opt.anim = anim;
7113             return anim;
7114         },
7115
7116         // private legacy anim prep
7117         preanim : function(a, i){
7118             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7119         },
7120
7121         /**
7122          * Removes worthless text nodes
7123          * @param {Boolean} forceReclean (optional) By default the element
7124          * keeps track if it has been cleaned already so
7125          * you can call this over and over. However, if you update the element and
7126          * need to force a reclean, you can pass true.
7127          */
7128         clean : function(forceReclean){
7129             if(this.isCleaned && forceReclean !== true){
7130                 return this;
7131             }
7132             var ns = /\S/;
7133             var d = this.dom, n = d.firstChild, ni = -1;
7134             while(n){
7135                 var nx = n.nextSibling;
7136                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7137                     d.removeChild(n);
7138                 }else{
7139                     n.nodeIndex = ++ni;
7140                 }
7141                 n = nx;
7142             }
7143             this.isCleaned = true;
7144             return this;
7145         },
7146
7147         // private
7148         calcOffsetsTo : function(el){
7149             el = Roo.get(el);
7150             var d = el.dom;
7151             var restorePos = false;
7152             if(el.getStyle('position') == 'static'){
7153                 el.position('relative');
7154                 restorePos = true;
7155             }
7156             var x = 0, y =0;
7157             var op = this.dom;
7158             while(op && op != d && op.tagName != 'HTML'){
7159                 x+= op.offsetLeft;
7160                 y+= op.offsetTop;
7161                 op = op.offsetParent;
7162             }
7163             if(restorePos){
7164                 el.position('static');
7165             }
7166             return [x, y];
7167         },
7168
7169         /**
7170          * Scrolls this element into view within the passed container.
7171          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7172          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7173          * @return {Roo.Element} this
7174          */
7175         scrollIntoView : function(container, hscroll){
7176             var c = Roo.getDom(container) || document.body;
7177             var el = this.dom;
7178
7179             var o = this.calcOffsetsTo(c),
7180                 l = o[0],
7181                 t = o[1],
7182                 b = t+el.offsetHeight,
7183                 r = l+el.offsetWidth;
7184
7185             var ch = c.clientHeight;
7186             var ct = parseInt(c.scrollTop, 10);
7187             var cl = parseInt(c.scrollLeft, 10);
7188             var cb = ct + ch;
7189             var cr = cl + c.clientWidth;
7190
7191             if(t < ct){
7192                 c.scrollTop = t;
7193             }else if(b > cb){
7194                 c.scrollTop = b-ch;
7195             }
7196
7197             if(hscroll !== false){
7198                 if(l < cl){
7199                     c.scrollLeft = l;
7200                 }else if(r > cr){
7201                     c.scrollLeft = r-c.clientWidth;
7202                 }
7203             }
7204             return this;
7205         },
7206
7207         // private
7208         scrollChildIntoView : function(child, hscroll){
7209             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7210         },
7211
7212         /**
7213          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7214          * the new height may not be available immediately.
7215          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7216          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7217          * @param {Function} onComplete (optional) Function to call when animation completes
7218          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7219          * @return {Roo.Element} this
7220          */
7221         autoHeight : function(animate, duration, onComplete, easing){
7222             var oldHeight = this.getHeight();
7223             this.clip();
7224             this.setHeight(1); // force clipping
7225             setTimeout(function(){
7226                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7227                 if(!animate){
7228                     this.setHeight(height);
7229                     this.unclip();
7230                     if(typeof onComplete == "function"){
7231                         onComplete();
7232                     }
7233                 }else{
7234                     this.setHeight(oldHeight); // restore original height
7235                     this.setHeight(height, animate, duration, function(){
7236                         this.unclip();
7237                         if(typeof onComplete == "function") onComplete();
7238                     }.createDelegate(this), easing);
7239                 }
7240             }.createDelegate(this), 0);
7241             return this;
7242         },
7243
7244         /**
7245          * Returns true if this element is an ancestor of the passed element
7246          * @param {HTMLElement/String} el The element to check
7247          * @return {Boolean} True if this element is an ancestor of el, else false
7248          */
7249         contains : function(el){
7250             if(!el){return false;}
7251             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7252         },
7253
7254         /**
7255          * Checks whether the element is currently visible using both visibility and display properties.
7256          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7257          * @return {Boolean} True if the element is currently visible, else false
7258          */
7259         isVisible : function(deep) {
7260             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7261             if(deep !== true || !vis){
7262                 return vis;
7263             }
7264             var p = this.dom.parentNode;
7265             while(p && p.tagName.toLowerCase() != "body"){
7266                 if(!Roo.fly(p, '_isVisible').isVisible()){
7267                     return false;
7268                 }
7269                 p = p.parentNode;
7270             }
7271             return true;
7272         },
7273
7274         /**
7275          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7276          * @param {String} selector The CSS selector
7277          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7278          * @return {CompositeElement/CompositeElementLite} The composite element
7279          */
7280         select : function(selector, unique){
7281             return El.select(selector, unique, this.dom);
7282         },
7283
7284         /**
7285          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7286          * @param {String} selector The CSS selector
7287          * @return {Array} An array of the matched nodes
7288          */
7289         query : function(selector, unique){
7290             return Roo.DomQuery.select(selector, this.dom);
7291         },
7292
7293         /**
7294          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7295          * @param {String} selector The CSS selector
7296          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7297          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7298          */
7299         child : function(selector, returnDom){
7300             var n = Roo.DomQuery.selectNode(selector, this.dom);
7301             return returnDom ? n : Roo.get(n);
7302         },
7303
7304         /**
7305          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7306          * @param {String} selector The CSS selector
7307          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7308          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7309          */
7310         down : function(selector, returnDom){
7311             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7312             return returnDom ? n : Roo.get(n);
7313         },
7314
7315         /**
7316          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7317          * @param {String} group The group the DD object is member of
7318          * @param {Object} config The DD config object
7319          * @param {Object} overrides An object containing methods to override/implement on the DD object
7320          * @return {Roo.dd.DD} The DD object
7321          */
7322         initDD : function(group, config, overrides){
7323             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7324             return Roo.apply(dd, overrides);
7325         },
7326
7327         /**
7328          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7329          * @param {String} group The group the DDProxy object is member of
7330          * @param {Object} config The DDProxy config object
7331          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7332          * @return {Roo.dd.DDProxy} The DDProxy object
7333          */
7334         initDDProxy : function(group, config, overrides){
7335             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7336             return Roo.apply(dd, overrides);
7337         },
7338
7339         /**
7340          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7341          * @param {String} group The group the DDTarget object is member of
7342          * @param {Object} config The DDTarget config object
7343          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7344          * @return {Roo.dd.DDTarget} The DDTarget object
7345          */
7346         initDDTarget : function(group, config, overrides){
7347             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7348             return Roo.apply(dd, overrides);
7349         },
7350
7351         /**
7352          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7353          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7354          * @param {Boolean} visible Whether the element is visible
7355          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7356          * @return {Roo.Element} this
7357          */
7358          setVisible : function(visible, animate){
7359             if(!animate || !A){
7360                 if(this.visibilityMode == El.DISPLAY){
7361                     this.setDisplayed(visible);
7362                 }else{
7363                     this.fixDisplay();
7364                     this.dom.style.visibility = visible ? "visible" : "hidden";
7365                 }
7366             }else{
7367                 // closure for composites
7368                 var dom = this.dom;
7369                 var visMode = this.visibilityMode;
7370                 if(visible){
7371                     this.setOpacity(.01);
7372                     this.setVisible(true);
7373                 }
7374                 this.anim({opacity: { to: (visible?1:0) }},
7375                       this.preanim(arguments, 1),
7376                       null, .35, 'easeIn', function(){
7377                          if(!visible){
7378                              if(visMode == El.DISPLAY){
7379                                  dom.style.display = "none";
7380                              }else{
7381                                  dom.style.visibility = "hidden";
7382                              }
7383                              Roo.get(dom).setOpacity(1);
7384                          }
7385                      });
7386             }
7387             return this;
7388         },
7389
7390         /**
7391          * Returns true if display is not "none"
7392          * @return {Boolean}
7393          */
7394         isDisplayed : function() {
7395             return this.getStyle("display") != "none";
7396         },
7397
7398         /**
7399          * Toggles the element's visibility or display, depending on visibility mode.
7400          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7401          * @return {Roo.Element} this
7402          */
7403         toggle : function(animate){
7404             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7405             return this;
7406         },
7407
7408         /**
7409          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7410          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7411          * @return {Roo.Element} this
7412          */
7413         setDisplayed : function(value) {
7414             if(typeof value == "boolean"){
7415                value = value ? this.originalDisplay : "none";
7416             }
7417             this.setStyle("display", value);
7418             return this;
7419         },
7420
7421         /**
7422          * Tries to focus the element. Any exceptions are caught and ignored.
7423          * @return {Roo.Element} this
7424          */
7425         focus : function() {
7426             try{
7427                 this.dom.focus();
7428             }catch(e){}
7429             return this;
7430         },
7431
7432         /**
7433          * Tries to blur the element. Any exceptions are caught and ignored.
7434          * @return {Roo.Element} this
7435          */
7436         blur : function() {
7437             try{
7438                 this.dom.blur();
7439             }catch(e){}
7440             return this;
7441         },
7442
7443         /**
7444          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7445          * @param {String/Array} className The CSS class to add, or an array of classes
7446          * @return {Roo.Element} this
7447          */
7448         addClass : function(className){
7449             if(className instanceof Array){
7450                 for(var i = 0, len = className.length; i < len; i++) {
7451                     this.addClass(className[i]);
7452                 }
7453             }else{
7454                 if(className && !this.hasClass(className)){
7455                     this.dom.className = this.dom.className + " " + className;
7456                 }
7457             }
7458             return this;
7459         },
7460
7461         /**
7462          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7463          * @param {String/Array} className The CSS class to add, or an array of classes
7464          * @return {Roo.Element} this
7465          */
7466         radioClass : function(className){
7467             var siblings = this.dom.parentNode.childNodes;
7468             for(var i = 0; i < siblings.length; i++) {
7469                 var s = siblings[i];
7470                 if(s.nodeType == 1){
7471                     Roo.get(s).removeClass(className);
7472                 }
7473             }
7474             this.addClass(className);
7475             return this;
7476         },
7477
7478         /**
7479          * Removes one or more CSS classes from the element.
7480          * @param {String/Array} className The CSS class to remove, or an array of classes
7481          * @return {Roo.Element} this
7482          */
7483         removeClass : function(className){
7484             if(!className || !this.dom.className){
7485                 return this;
7486             }
7487             if(className instanceof Array){
7488                 for(var i = 0, len = className.length; i < len; i++) {
7489                     this.removeClass(className[i]);
7490                 }
7491             }else{
7492                 if(this.hasClass(className)){
7493                     var re = this.classReCache[className];
7494                     if (!re) {
7495                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7496                        this.classReCache[className] = re;
7497                     }
7498                     this.dom.className =
7499                         this.dom.className.replace(re, " ");
7500                 }
7501             }
7502             return this;
7503         },
7504
7505         // private
7506         classReCache: {},
7507
7508         /**
7509          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7510          * @param {String} className The CSS class to toggle
7511          * @return {Roo.Element} this
7512          */
7513         toggleClass : function(className){
7514             if(this.hasClass(className)){
7515                 this.removeClass(className);
7516             }else{
7517                 this.addClass(className);
7518             }
7519             return this;
7520         },
7521
7522         /**
7523          * Checks if the specified CSS class exists on this element's DOM node.
7524          * @param {String} className The CSS class to check for
7525          * @return {Boolean} True if the class exists, else false
7526          */
7527         hasClass : function(className){
7528             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7529         },
7530
7531         /**
7532          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7533          * @param {String} oldClassName The CSS class to replace
7534          * @param {String} newClassName The replacement CSS class
7535          * @return {Roo.Element} this
7536          */
7537         replaceClass : function(oldClassName, newClassName){
7538             this.removeClass(oldClassName);
7539             this.addClass(newClassName);
7540             return this;
7541         },
7542
7543         /**
7544          * Returns an object with properties matching the styles requested.
7545          * For example, el.getStyles('color', 'font-size', 'width') might return
7546          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7547          * @param {String} style1 A style name
7548          * @param {String} style2 A style name
7549          * @param {String} etc.
7550          * @return {Object} The style object
7551          */
7552         getStyles : function(){
7553             var a = arguments, len = a.length, r = {};
7554             for(var i = 0; i < len; i++){
7555                 r[a[i]] = this.getStyle(a[i]);
7556             }
7557             return r;
7558         },
7559
7560         /**
7561          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7562          * @param {String} property The style property whose value is returned.
7563          * @return {String} The current value of the style property for this element.
7564          */
7565         getStyle : function(){
7566             return view && view.getComputedStyle ?
7567                 function(prop){
7568                     var el = this.dom, v, cs, camel;
7569                     if(prop == 'float'){
7570                         prop = "cssFloat";
7571                     }
7572                     if(el.style && (v = el.style[prop])){
7573                         return v;
7574                     }
7575                     if(cs = view.getComputedStyle(el, "")){
7576                         if(!(camel = propCache[prop])){
7577                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7578                         }
7579                         return cs[camel];
7580                     }
7581                     return null;
7582                 } :
7583                 function(prop){
7584                     var el = this.dom, v, cs, camel;
7585                     if(prop == 'opacity'){
7586                         if(typeof el.style.filter == 'string'){
7587                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7588                             if(m){
7589                                 var fv = parseFloat(m[1]);
7590                                 if(!isNaN(fv)){
7591                                     return fv ? fv / 100 : 0;
7592                                 }
7593                             }
7594                         }
7595                         return 1;
7596                     }else if(prop == 'float'){
7597                         prop = "styleFloat";
7598                     }
7599                     if(!(camel = propCache[prop])){
7600                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7601                     }
7602                     if(v = el.style[camel]){
7603                         return v;
7604                     }
7605                     if(cs = el.currentStyle){
7606                         return cs[camel];
7607                     }
7608                     return null;
7609                 };
7610         }(),
7611
7612         /**
7613          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7614          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7615          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7616          * @return {Roo.Element} this
7617          */
7618         setStyle : function(prop, value){
7619             if(typeof prop == "string"){
7620                 
7621                 if (prop == 'float') {
7622                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7623                     return this;
7624                 }
7625                 
7626                 var camel;
7627                 if(!(camel = propCache[prop])){
7628                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7629                 }
7630                 
7631                 if(camel == 'opacity') {
7632                     this.setOpacity(value);
7633                 }else{
7634                     this.dom.style[camel] = value;
7635                 }
7636             }else{
7637                 for(var style in prop){
7638                     if(typeof prop[style] != "function"){
7639                        this.setStyle(style, prop[style]);
7640                     }
7641                 }
7642             }
7643             return this;
7644         },
7645
7646         /**
7647          * More flexible version of {@link #setStyle} for setting style properties.
7648          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7649          * a function which returns such a specification.
7650          * @return {Roo.Element} this
7651          */
7652         applyStyles : function(style){
7653             Roo.DomHelper.applyStyles(this.dom, style);
7654             return this;
7655         },
7656
7657         /**
7658           * 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).
7659           * @return {Number} The X position of the element
7660           */
7661         getX : function(){
7662             return D.getX(this.dom);
7663         },
7664
7665         /**
7666           * 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).
7667           * @return {Number} The Y position of the element
7668           */
7669         getY : function(){
7670             return D.getY(this.dom);
7671         },
7672
7673         /**
7674           * 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).
7675           * @return {Array} The XY position of the element
7676           */
7677         getXY : function(){
7678             return D.getXY(this.dom);
7679         },
7680
7681         /**
7682          * 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).
7683          * @param {Number} The X position of the element
7684          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7685          * @return {Roo.Element} this
7686          */
7687         setX : function(x, animate){
7688             if(!animate || !A){
7689                 D.setX(this.dom, x);
7690             }else{
7691                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7692             }
7693             return this;
7694         },
7695
7696         /**
7697          * 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).
7698          * @param {Number} The Y position of the element
7699          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7700          * @return {Roo.Element} this
7701          */
7702         setY : function(y, animate){
7703             if(!animate || !A){
7704                 D.setY(this.dom, y);
7705             }else{
7706                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7707             }
7708             return this;
7709         },
7710
7711         /**
7712          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7713          * @param {String} left The left CSS property value
7714          * @return {Roo.Element} this
7715          */
7716         setLeft : function(left){
7717             this.setStyle("left", this.addUnits(left));
7718             return this;
7719         },
7720
7721         /**
7722          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7723          * @param {String} top The top CSS property value
7724          * @return {Roo.Element} this
7725          */
7726         setTop : function(top){
7727             this.setStyle("top", this.addUnits(top));
7728             return this;
7729         },
7730
7731         /**
7732          * Sets the element's CSS right style.
7733          * @param {String} right The right CSS property value
7734          * @return {Roo.Element} this
7735          */
7736         setRight : function(right){
7737             this.setStyle("right", this.addUnits(right));
7738             return this;
7739         },
7740
7741         /**
7742          * Sets the element's CSS bottom style.
7743          * @param {String} bottom The bottom CSS property value
7744          * @return {Roo.Element} this
7745          */
7746         setBottom : function(bottom){
7747             this.setStyle("bottom", this.addUnits(bottom));
7748             return this;
7749         },
7750
7751         /**
7752          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7753          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7754          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7755          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7756          * @return {Roo.Element} this
7757          */
7758         setXY : function(pos, animate){
7759             if(!animate || !A){
7760                 D.setXY(this.dom, pos);
7761             }else{
7762                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7763             }
7764             return this;
7765         },
7766
7767         /**
7768          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7769          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7770          * @param {Number} x X value for new position (coordinates are page-based)
7771          * @param {Number} y Y value for new position (coordinates are page-based)
7772          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7773          * @return {Roo.Element} this
7774          */
7775         setLocation : function(x, y, animate){
7776             this.setXY([x, y], this.preanim(arguments, 2));
7777             return this;
7778         },
7779
7780         /**
7781          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7782          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7783          * @param {Number} x X value for new position (coordinates are page-based)
7784          * @param {Number} y Y value for new position (coordinates are page-based)
7785          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7786          * @return {Roo.Element} this
7787          */
7788         moveTo : function(x, y, animate){
7789             this.setXY([x, y], this.preanim(arguments, 2));
7790             return this;
7791         },
7792
7793         /**
7794          * Returns the region of the given element.
7795          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7796          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7797          */
7798         getRegion : function(){
7799             return D.getRegion(this.dom);
7800         },
7801
7802         /**
7803          * Returns the offset height of the element
7804          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7805          * @return {Number} The element's height
7806          */
7807         getHeight : function(contentHeight){
7808             var h = this.dom.offsetHeight || 0;
7809             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7810         },
7811
7812         /**
7813          * Returns the offset width of the element
7814          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7815          * @return {Number} The element's width
7816          */
7817         getWidth : function(contentWidth){
7818             var w = this.dom.offsetWidth || 0;
7819             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7820         },
7821
7822         /**
7823          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7824          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7825          * if a height has not been set using CSS.
7826          * @return {Number}
7827          */
7828         getComputedHeight : function(){
7829             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7830             if(!h){
7831                 h = parseInt(this.getStyle('height'), 10) || 0;
7832                 if(!this.isBorderBox()){
7833                     h += this.getFrameWidth('tb');
7834                 }
7835             }
7836             return h;
7837         },
7838
7839         /**
7840          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7841          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7842          * if a width has not been set using CSS.
7843          * @return {Number}
7844          */
7845         getComputedWidth : function(){
7846             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7847             if(!w){
7848                 w = parseInt(this.getStyle('width'), 10) || 0;
7849                 if(!this.isBorderBox()){
7850                     w += this.getFrameWidth('lr');
7851                 }
7852             }
7853             return w;
7854         },
7855
7856         /**
7857          * Returns the size of the element.
7858          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7859          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7860          */
7861         getSize : function(contentSize){
7862             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7863         },
7864
7865         /**
7866          * Returns the width and height of the viewport.
7867          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7868          */
7869         getViewSize : function(){
7870             var d = this.dom, doc = document, aw = 0, ah = 0;
7871             if(d == doc || d == doc.body){
7872                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7873             }else{
7874                 return {
7875                     width : d.clientWidth,
7876                     height: d.clientHeight
7877                 };
7878             }
7879         },
7880
7881         /**
7882          * Returns the value of the "value" attribute
7883          * @param {Boolean} asNumber true to parse the value as a number
7884          * @return {String/Number}
7885          */
7886         getValue : function(asNumber){
7887             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7888         },
7889
7890         // private
7891         adjustWidth : function(width){
7892             if(typeof width == "number"){
7893                 if(this.autoBoxAdjust && !this.isBorderBox()){
7894                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7895                 }
7896                 if(width < 0){
7897                     width = 0;
7898                 }
7899             }
7900             return width;
7901         },
7902
7903         // private
7904         adjustHeight : function(height){
7905             if(typeof height == "number"){
7906                if(this.autoBoxAdjust && !this.isBorderBox()){
7907                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7908                }
7909                if(height < 0){
7910                    height = 0;
7911                }
7912             }
7913             return height;
7914         },
7915
7916         /**
7917          * Set the width of the element
7918          * @param {Number} width The new width
7919          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7920          * @return {Roo.Element} this
7921          */
7922         setWidth : function(width, animate){
7923             width = this.adjustWidth(width);
7924             if(!animate || !A){
7925                 this.dom.style.width = this.addUnits(width);
7926             }else{
7927                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7928             }
7929             return this;
7930         },
7931
7932         /**
7933          * Set the height of the element
7934          * @param {Number} height The new height
7935          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7936          * @return {Roo.Element} this
7937          */
7938          setHeight : function(height, animate){
7939             height = this.adjustHeight(height);
7940             if(!animate || !A){
7941                 this.dom.style.height = this.addUnits(height);
7942             }else{
7943                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7944             }
7945             return this;
7946         },
7947
7948         /**
7949          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7950          * @param {Number} width The new width
7951          * @param {Number} height The new height
7952          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7953          * @return {Roo.Element} this
7954          */
7955          setSize : function(width, height, animate){
7956             if(typeof width == "object"){ // in case of object from getSize()
7957                 height = width.height; width = width.width;
7958             }
7959             width = this.adjustWidth(width); height = this.adjustHeight(height);
7960             if(!animate || !A){
7961                 this.dom.style.width = this.addUnits(width);
7962                 this.dom.style.height = this.addUnits(height);
7963             }else{
7964                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7965             }
7966             return this;
7967         },
7968
7969         /**
7970          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
7971          * @param {Number} x X value for new position (coordinates are page-based)
7972          * @param {Number} y Y value for new position (coordinates are page-based)
7973          * @param {Number} width The new width
7974          * @param {Number} height The new height
7975          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7976          * @return {Roo.Element} this
7977          */
7978         setBounds : function(x, y, width, height, animate){
7979             if(!animate || !A){
7980                 this.setSize(width, height);
7981                 this.setLocation(x, y);
7982             }else{
7983                 width = this.adjustWidth(width); height = this.adjustHeight(height);
7984                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
7985                               this.preanim(arguments, 4), 'motion');
7986             }
7987             return this;
7988         },
7989
7990         /**
7991          * 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.
7992          * @param {Roo.lib.Region} region The region to fill
7993          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7994          * @return {Roo.Element} this
7995          */
7996         setRegion : function(region, animate){
7997             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
7998             return this;
7999         },
8000
8001         /**
8002          * Appends an event handler
8003          *
8004          * @param {String}   eventName     The type of event to append
8005          * @param {Function} fn        The method the event invokes
8006          * @param {Object} scope       (optional) The scope (this object) of the fn
8007          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8008          */
8009         addListener : function(eventName, fn, scope, options){
8010             if (this.dom) {
8011                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8012             }
8013         },
8014
8015         /**
8016          * Removes an event handler from this element
8017          * @param {String} eventName the type of event to remove
8018          * @param {Function} fn the method the event invokes
8019          * @return {Roo.Element} this
8020          */
8021         removeListener : function(eventName, fn){
8022             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8023             return this;
8024         },
8025
8026         /**
8027          * Removes all previous added listeners from this element
8028          * @return {Roo.Element} this
8029          */
8030         removeAllListeners : function(){
8031             E.purgeElement(this.dom);
8032             return this;
8033         },
8034
8035         relayEvent : function(eventName, observable){
8036             this.on(eventName, function(e){
8037                 observable.fireEvent(eventName, e);
8038             });
8039         },
8040
8041         /**
8042          * Set the opacity of the element
8043          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8044          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8045          * @return {Roo.Element} this
8046          */
8047          setOpacity : function(opacity, animate){
8048             if(!animate || !A){
8049                 var s = this.dom.style;
8050                 if(Roo.isIE){
8051                     s.zoom = 1;
8052                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8053                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8054                 }else{
8055                     s.opacity = opacity;
8056                 }
8057             }else{
8058                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8059             }
8060             return this;
8061         },
8062
8063         /**
8064          * Gets the left X coordinate
8065          * @param {Boolean} local True to get the local css position instead of page coordinate
8066          * @return {Number}
8067          */
8068         getLeft : function(local){
8069             if(!local){
8070                 return this.getX();
8071             }else{
8072                 return parseInt(this.getStyle("left"), 10) || 0;
8073             }
8074         },
8075
8076         /**
8077          * Gets the right X coordinate of the element (element X position + element width)
8078          * @param {Boolean} local True to get the local css position instead of page coordinate
8079          * @return {Number}
8080          */
8081         getRight : function(local){
8082             if(!local){
8083                 return this.getX() + this.getWidth();
8084             }else{
8085                 return (this.getLeft(true) + this.getWidth()) || 0;
8086             }
8087         },
8088
8089         /**
8090          * Gets the top Y coordinate
8091          * @param {Boolean} local True to get the local css position instead of page coordinate
8092          * @return {Number}
8093          */
8094         getTop : function(local) {
8095             if(!local){
8096                 return this.getY();
8097             }else{
8098                 return parseInt(this.getStyle("top"), 10) || 0;
8099             }
8100         },
8101
8102         /**
8103          * Gets the bottom Y coordinate of the element (element Y position + element height)
8104          * @param {Boolean} local True to get the local css position instead of page coordinate
8105          * @return {Number}
8106          */
8107         getBottom : function(local){
8108             if(!local){
8109                 return this.getY() + this.getHeight();
8110             }else{
8111                 return (this.getTop(true) + this.getHeight()) || 0;
8112             }
8113         },
8114
8115         /**
8116         * Initializes positioning on this element. If a desired position is not passed, it will make the
8117         * the element positioned relative IF it is not already positioned.
8118         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8119         * @param {Number} zIndex (optional) The zIndex to apply
8120         * @param {Number} x (optional) Set the page X position
8121         * @param {Number} y (optional) Set the page Y position
8122         */
8123         position : function(pos, zIndex, x, y){
8124             if(!pos){
8125                if(this.getStyle('position') == 'static'){
8126                    this.setStyle('position', 'relative');
8127                }
8128             }else{
8129                 this.setStyle("position", pos);
8130             }
8131             if(zIndex){
8132                 this.setStyle("z-index", zIndex);
8133             }
8134             if(x !== undefined && y !== undefined){
8135                 this.setXY([x, y]);
8136             }else if(x !== undefined){
8137                 this.setX(x);
8138             }else if(y !== undefined){
8139                 this.setY(y);
8140             }
8141         },
8142
8143         /**
8144         * Clear positioning back to the default when the document was loaded
8145         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8146         * @return {Roo.Element} this
8147          */
8148         clearPositioning : function(value){
8149             value = value ||'';
8150             this.setStyle({
8151                 "left": value,
8152                 "right": value,
8153                 "top": value,
8154                 "bottom": value,
8155                 "z-index": "",
8156                 "position" : "static"
8157             });
8158             return this;
8159         },
8160
8161         /**
8162         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8163         * snapshot before performing an update and then restoring the element.
8164         * @return {Object}
8165         */
8166         getPositioning : function(){
8167             var l = this.getStyle("left");
8168             var t = this.getStyle("top");
8169             return {
8170                 "position" : this.getStyle("position"),
8171                 "left" : l,
8172                 "right" : l ? "" : this.getStyle("right"),
8173                 "top" : t,
8174                 "bottom" : t ? "" : this.getStyle("bottom"),
8175                 "z-index" : this.getStyle("z-index")
8176             };
8177         },
8178
8179         /**
8180          * Gets the width of the border(s) for the specified side(s)
8181          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8182          * passing lr would get the border (l)eft width + the border (r)ight width.
8183          * @return {Number} The width of the sides passed added together
8184          */
8185         getBorderWidth : function(side){
8186             return this.addStyles(side, El.borders);
8187         },
8188
8189         /**
8190          * Gets the width of the padding(s) for the specified side(s)
8191          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8192          * passing lr would get the padding (l)eft + the padding (r)ight.
8193          * @return {Number} The padding of the sides passed added together
8194          */
8195         getPadding : function(side){
8196             return this.addStyles(side, El.paddings);
8197         },
8198
8199         /**
8200         * Set positioning with an object returned by getPositioning().
8201         * @param {Object} posCfg
8202         * @return {Roo.Element} this
8203          */
8204         setPositioning : function(pc){
8205             this.applyStyles(pc);
8206             if(pc.right == "auto"){
8207                 this.dom.style.right = "";
8208             }
8209             if(pc.bottom == "auto"){
8210                 this.dom.style.bottom = "";
8211             }
8212             return this;
8213         },
8214
8215         // private
8216         fixDisplay : function(){
8217             if(this.getStyle("display") == "none"){
8218                 this.setStyle("visibility", "hidden");
8219                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8220                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8221                     this.setStyle("display", "block");
8222                 }
8223             }
8224         },
8225
8226         /**
8227          * Quick set left and top adding default units
8228          * @param {String} left The left CSS property value
8229          * @param {String} top The top CSS property value
8230          * @return {Roo.Element} this
8231          */
8232          setLeftTop : function(left, top){
8233             this.dom.style.left = this.addUnits(left);
8234             this.dom.style.top = this.addUnits(top);
8235             return this;
8236         },
8237
8238         /**
8239          * Move this element relative to its current position.
8240          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8241          * @param {Number} distance How far to move the element in pixels
8242          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8243          * @return {Roo.Element} this
8244          */
8245          move : function(direction, distance, animate){
8246             var xy = this.getXY();
8247             direction = direction.toLowerCase();
8248             switch(direction){
8249                 case "l":
8250                 case "left":
8251                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8252                     break;
8253                case "r":
8254                case "right":
8255                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8256                     break;
8257                case "t":
8258                case "top":
8259                case "up":
8260                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8261                     break;
8262                case "b":
8263                case "bottom":
8264                case "down":
8265                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8266                     break;
8267             }
8268             return this;
8269         },
8270
8271         /**
8272          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8273          * @return {Roo.Element} this
8274          */
8275         clip : function(){
8276             if(!this.isClipped){
8277                this.isClipped = true;
8278                this.originalClip = {
8279                    "o": this.getStyle("overflow"),
8280                    "x": this.getStyle("overflow-x"),
8281                    "y": this.getStyle("overflow-y")
8282                };
8283                this.setStyle("overflow", "hidden");
8284                this.setStyle("overflow-x", "hidden");
8285                this.setStyle("overflow-y", "hidden");
8286             }
8287             return this;
8288         },
8289
8290         /**
8291          *  Return clipping (overflow) to original clipping before clip() was called
8292          * @return {Roo.Element} this
8293          */
8294         unclip : function(){
8295             if(this.isClipped){
8296                 this.isClipped = false;
8297                 var o = this.originalClip;
8298                 if(o.o){this.setStyle("overflow", o.o);}
8299                 if(o.x){this.setStyle("overflow-x", o.x);}
8300                 if(o.y){this.setStyle("overflow-y", o.y);}
8301             }
8302             return this;
8303         },
8304
8305
8306         /**
8307          * Gets the x,y coordinates specified by the anchor position on the element.
8308          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8309          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8310          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8311          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8312          * @return {Array} [x, y] An array containing the element's x and y coordinates
8313          */
8314         getAnchorXY : function(anchor, local, s){
8315             //Passing a different size is useful for pre-calculating anchors,
8316             //especially for anchored animations that change the el size.
8317
8318             var w, h, vp = false;
8319             if(!s){
8320                 var d = this.dom;
8321                 if(d == document.body || d == document){
8322                     vp = true;
8323                     w = D.getViewWidth(); h = D.getViewHeight();
8324                 }else{
8325                     w = this.getWidth(); h = this.getHeight();
8326                 }
8327             }else{
8328                 w = s.width;  h = s.height;
8329             }
8330             var x = 0, y = 0, r = Math.round;
8331             switch((anchor || "tl").toLowerCase()){
8332                 case "c":
8333                     x = r(w*.5);
8334                     y = r(h*.5);
8335                 break;
8336                 case "t":
8337                     x = r(w*.5);
8338                     y = 0;
8339                 break;
8340                 case "l":
8341                     x = 0;
8342                     y = r(h*.5);
8343                 break;
8344                 case "r":
8345                     x = w;
8346                     y = r(h*.5);
8347                 break;
8348                 case "b":
8349                     x = r(w*.5);
8350                     y = h;
8351                 break;
8352                 case "tl":
8353                     x = 0;
8354                     y = 0;
8355                 break;
8356                 case "bl":
8357                     x = 0;
8358                     y = h;
8359                 break;
8360                 case "br":
8361                     x = w;
8362                     y = h;
8363                 break;
8364                 case "tr":
8365                     x = w;
8366                     y = 0;
8367                 break;
8368             }
8369             if(local === true){
8370                 return [x, y];
8371             }
8372             if(vp){
8373                 var sc = this.getScroll();
8374                 return [x + sc.left, y + sc.top];
8375             }
8376             //Add the element's offset xy
8377             var o = this.getXY();
8378             return [x+o[0], y+o[1]];
8379         },
8380
8381         /**
8382          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8383          * supported position values.
8384          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8385          * @param {String} position The position to align to.
8386          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8387          * @return {Array} [x, y]
8388          */
8389         getAlignToXY : function(el, p, o){
8390             el = Roo.get(el);
8391             var d = this.dom;
8392             if(!el.dom){
8393                 throw "Element.alignTo with an element that doesn't exist";
8394             }
8395             var c = false; //constrain to viewport
8396             var p1 = "", p2 = "";
8397             o = o || [0,0];
8398
8399             if(!p){
8400                 p = "tl-bl";
8401             }else if(p == "?"){
8402                 p = "tl-bl?";
8403             }else if(p.indexOf("-") == -1){
8404                 p = "tl-" + p;
8405             }
8406             p = p.toLowerCase();
8407             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8408             if(!m){
8409                throw "Element.alignTo with an invalid alignment " + p;
8410             }
8411             p1 = m[1]; p2 = m[2]; c = !!m[3];
8412
8413             //Subtract the aligned el's internal xy from the target's offset xy
8414             //plus custom offset to get the aligned el's new offset xy
8415             var a1 = this.getAnchorXY(p1, true);
8416             var a2 = el.getAnchorXY(p2, false);
8417             var x = a2[0] - a1[0] + o[0];
8418             var y = a2[1] - a1[1] + o[1];
8419             if(c){
8420                 //constrain the aligned el to viewport if necessary
8421                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8422                 // 5px of margin for ie
8423                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8424
8425                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8426                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8427                 //otherwise swap the aligned el to the opposite border of the target.
8428                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8429                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8430                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8431                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8432
8433                var doc = document;
8434                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8435                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8436
8437                if((x+w) > dw + scrollX){
8438                     x = swapX ? r.left-w : dw+scrollX-w;
8439                 }
8440                if(x < scrollX){
8441                    x = swapX ? r.right : scrollX;
8442                }
8443                if((y+h) > dh + scrollY){
8444                     y = swapY ? r.top-h : dh+scrollY-h;
8445                 }
8446                if (y < scrollY){
8447                    y = swapY ? r.bottom : scrollY;
8448                }
8449             }
8450             return [x,y];
8451         },
8452
8453         // private
8454         getConstrainToXY : function(){
8455             var os = {top:0, left:0, bottom:0, right: 0};
8456
8457             return function(el, local, offsets, proposedXY){
8458                 el = Roo.get(el);
8459                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8460
8461                 var vw, vh, vx = 0, vy = 0;
8462                 if(el.dom == document.body || el.dom == document){
8463                     vw = Roo.lib.Dom.getViewWidth();
8464                     vh = Roo.lib.Dom.getViewHeight();
8465                 }else{
8466                     vw = el.dom.clientWidth;
8467                     vh = el.dom.clientHeight;
8468                     if(!local){
8469                         var vxy = el.getXY();
8470                         vx = vxy[0];
8471                         vy = vxy[1];
8472                     }
8473                 }
8474
8475                 var s = el.getScroll();
8476
8477                 vx += offsets.left + s.left;
8478                 vy += offsets.top + s.top;
8479
8480                 vw -= offsets.right;
8481                 vh -= offsets.bottom;
8482
8483                 var vr = vx+vw;
8484                 var vb = vy+vh;
8485
8486                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8487                 var x = xy[0], y = xy[1];
8488                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8489
8490                 // only move it if it needs it
8491                 var moved = false;
8492
8493                 // first validate right/bottom
8494                 if((x + w) > vr){
8495                     x = vr - w;
8496                     moved = true;
8497                 }
8498                 if((y + h) > vb){
8499                     y = vb - h;
8500                     moved = true;
8501                 }
8502                 // then make sure top/left isn't negative
8503                 if(x < vx){
8504                     x = vx;
8505                     moved = true;
8506                 }
8507                 if(y < vy){
8508                     y = vy;
8509                     moved = true;
8510                 }
8511                 return moved ? [x, y] : false;
8512             };
8513         }(),
8514
8515         // private
8516         adjustForConstraints : function(xy, parent, offsets){
8517             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8518         },
8519
8520         /**
8521          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8522          * document it aligns it to the viewport.
8523          * The position parameter is optional, and can be specified in any one of the following formats:
8524          * <ul>
8525          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8526          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8527          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8528          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8529          *   <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
8530          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8531          * </ul>
8532          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8533          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8534          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8535          * that specified in order to enforce the viewport constraints.
8536          * Following are all of the supported anchor positions:
8537     <pre>
8538     Value  Description
8539     -----  -----------------------------
8540     tl     The top left corner (default)
8541     t      The center of the top edge
8542     tr     The top right corner
8543     l      The center of the left edge
8544     c      In the center of the element
8545     r      The center of the right edge
8546     bl     The bottom left corner
8547     b      The center of the bottom edge
8548     br     The bottom right corner
8549     </pre>
8550     Example Usage:
8551     <pre><code>
8552     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8553     el.alignTo("other-el");
8554
8555     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8556     el.alignTo("other-el", "tr?");
8557
8558     // align the bottom right corner of el with the center left edge of other-el
8559     el.alignTo("other-el", "br-l?");
8560
8561     // align the center of el with the bottom left corner of other-el and
8562     // adjust the x position by -6 pixels (and the y position by 0)
8563     el.alignTo("other-el", "c-bl", [-6, 0]);
8564     </code></pre>
8565          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8566          * @param {String} position The position to align to.
8567          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8568          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8569          * @return {Roo.Element} this
8570          */
8571         alignTo : function(element, position, offsets, animate){
8572             var xy = this.getAlignToXY(element, position, offsets);
8573             this.setXY(xy, this.preanim(arguments, 3));
8574             return this;
8575         },
8576
8577         /**
8578          * Anchors an element to another element and realigns it when the window is resized.
8579          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8580          * @param {String} position The position to align to.
8581          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8582          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8583          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8584          * is a number, it is used as the buffer delay (defaults to 50ms).
8585          * @param {Function} callback The function to call after the animation finishes
8586          * @return {Roo.Element} this
8587          */
8588         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8589             var action = function(){
8590                 this.alignTo(el, alignment, offsets, animate);
8591                 Roo.callback(callback, this);
8592             };
8593             Roo.EventManager.onWindowResize(action, this);
8594             var tm = typeof monitorScroll;
8595             if(tm != 'undefined'){
8596                 Roo.EventManager.on(window, 'scroll', action, this,
8597                     {buffer: tm == 'number' ? monitorScroll : 50});
8598             }
8599             action.call(this); // align immediately
8600             return this;
8601         },
8602         /**
8603          * Clears any opacity settings from this element. Required in some cases for IE.
8604          * @return {Roo.Element} this
8605          */
8606         clearOpacity : function(){
8607             if (window.ActiveXObject) {
8608                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8609                     this.dom.style.filter = "";
8610                 }
8611             } else {
8612                 this.dom.style.opacity = "";
8613                 this.dom.style["-moz-opacity"] = "";
8614                 this.dom.style["-khtml-opacity"] = "";
8615             }
8616             return this;
8617         },
8618
8619         /**
8620          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8621          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8622          * @return {Roo.Element} this
8623          */
8624         hide : function(animate){
8625             this.setVisible(false, this.preanim(arguments, 0));
8626             return this;
8627         },
8628
8629         /**
8630         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8631         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8632          * @return {Roo.Element} this
8633          */
8634         show : function(animate){
8635             this.setVisible(true, this.preanim(arguments, 0));
8636             return this;
8637         },
8638
8639         /**
8640          * @private Test if size has a unit, otherwise appends the default
8641          */
8642         addUnits : function(size){
8643             return Roo.Element.addUnits(size, this.defaultUnit);
8644         },
8645
8646         /**
8647          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8648          * @return {Roo.Element} this
8649          */
8650         beginMeasure : function(){
8651             var el = this.dom;
8652             if(el.offsetWidth || el.offsetHeight){
8653                 return this; // offsets work already
8654             }
8655             var changed = [];
8656             var p = this.dom, b = document.body; // start with this element
8657             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8658                 var pe = Roo.get(p);
8659                 if(pe.getStyle('display') == 'none'){
8660                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8661                     p.style.visibility = "hidden";
8662                     p.style.display = "block";
8663                 }
8664                 p = p.parentNode;
8665             }
8666             this._measureChanged = changed;
8667             return this;
8668
8669         },
8670
8671         /**
8672          * Restores displays to before beginMeasure was called
8673          * @return {Roo.Element} this
8674          */
8675         endMeasure : function(){
8676             var changed = this._measureChanged;
8677             if(changed){
8678                 for(var i = 0, len = changed.length; i < len; i++) {
8679                     var r = changed[i];
8680                     r.el.style.visibility = r.visibility;
8681                     r.el.style.display = "none";
8682                 }
8683                 this._measureChanged = null;
8684             }
8685             return this;
8686         },
8687
8688         /**
8689         * Update the innerHTML of this element, optionally searching for and processing scripts
8690         * @param {String} html The new HTML
8691         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8692         * @param {Function} callback For async script loading you can be noticed when the update completes
8693         * @return {Roo.Element} this
8694          */
8695         update : function(html, loadScripts, callback){
8696             if(typeof html == "undefined"){
8697                 html = "";
8698             }
8699             if(loadScripts !== true){
8700                 this.dom.innerHTML = html;
8701                 if(typeof callback == "function"){
8702                     callback();
8703                 }
8704                 return this;
8705             }
8706             var id = Roo.id();
8707             var dom = this.dom;
8708
8709             html += '<span id="' + id + '"></span>';
8710
8711             E.onAvailable(id, function(){
8712                 var hd = document.getElementsByTagName("head")[0];
8713                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8714                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8715                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8716
8717                 var match;
8718                 while(match = re.exec(html)){
8719                     var attrs = match[1];
8720                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8721                     if(srcMatch && srcMatch[2]){
8722                        var s = document.createElement("script");
8723                        s.src = srcMatch[2];
8724                        var typeMatch = attrs.match(typeRe);
8725                        if(typeMatch && typeMatch[2]){
8726                            s.type = typeMatch[2];
8727                        }
8728                        hd.appendChild(s);
8729                     }else if(match[2] && match[2].length > 0){
8730                         if(window.execScript) {
8731                            window.execScript(match[2]);
8732                         } else {
8733                             /**
8734                              * eval:var:id
8735                              * eval:var:dom
8736                              * eval:var:html
8737                              * 
8738                              */
8739                            window.eval(match[2]);
8740                         }
8741                     }
8742                 }
8743                 var el = document.getElementById(id);
8744                 if(el){el.parentNode.removeChild(el);}
8745                 if(typeof callback == "function"){
8746                     callback();
8747                 }
8748             });
8749             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8750             return this;
8751         },
8752
8753         /**
8754          * Direct access to the UpdateManager update() method (takes the same parameters).
8755          * @param {String/Function} url The url for this request or a function to call to get the url
8756          * @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}
8757          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8758          * @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.
8759          * @return {Roo.Element} this
8760          */
8761         load : function(){
8762             var um = this.getUpdateManager();
8763             um.update.apply(um, arguments);
8764             return this;
8765         },
8766
8767         /**
8768         * Gets this element's UpdateManager
8769         * @return {Roo.UpdateManager} The UpdateManager
8770         */
8771         getUpdateManager : function(){
8772             if(!this.updateManager){
8773                 this.updateManager = new Roo.UpdateManager(this);
8774             }
8775             return this.updateManager;
8776         },
8777
8778         /**
8779          * Disables text selection for this element (normalized across browsers)
8780          * @return {Roo.Element} this
8781          */
8782         unselectable : function(){
8783             this.dom.unselectable = "on";
8784             this.swallowEvent("selectstart", true);
8785             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8786             this.addClass("x-unselectable");
8787             return this;
8788         },
8789
8790         /**
8791         * Calculates the x, y to center this element on the screen
8792         * @return {Array} The x, y values [x, y]
8793         */
8794         getCenterXY : function(){
8795             return this.getAlignToXY(document, 'c-c');
8796         },
8797
8798         /**
8799         * Centers the Element in either the viewport, or another Element.
8800         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8801         */
8802         center : function(centerIn){
8803             this.alignTo(centerIn || document, 'c-c');
8804             return this;
8805         },
8806
8807         /**
8808          * Tests various css rules/browsers to determine if this element uses a border box
8809          * @return {Boolean}
8810          */
8811         isBorderBox : function(){
8812             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8813         },
8814
8815         /**
8816          * Return a box {x, y, width, height} that can be used to set another elements
8817          * size/location to match this element.
8818          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8819          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8820          * @return {Object} box An object in the format {x, y, width, height}
8821          */
8822         getBox : function(contentBox, local){
8823             var xy;
8824             if(!local){
8825                 xy = this.getXY();
8826             }else{
8827                 var left = parseInt(this.getStyle("left"), 10) || 0;
8828                 var top = parseInt(this.getStyle("top"), 10) || 0;
8829                 xy = [left, top];
8830             }
8831             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8832             if(!contentBox){
8833                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8834             }else{
8835                 var l = this.getBorderWidth("l")+this.getPadding("l");
8836                 var r = this.getBorderWidth("r")+this.getPadding("r");
8837                 var t = this.getBorderWidth("t")+this.getPadding("t");
8838                 var b = this.getBorderWidth("b")+this.getPadding("b");
8839                 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)};
8840             }
8841             bx.right = bx.x + bx.width;
8842             bx.bottom = bx.y + bx.height;
8843             return bx;
8844         },
8845
8846         /**
8847          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8848          for more information about the sides.
8849          * @param {String} sides
8850          * @return {Number}
8851          */
8852         getFrameWidth : function(sides, onlyContentBox){
8853             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8854         },
8855
8856         /**
8857          * 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.
8858          * @param {Object} box The box to fill {x, y, width, height}
8859          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8860          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8861          * @return {Roo.Element} this
8862          */
8863         setBox : function(box, adjust, animate){
8864             var w = box.width, h = box.height;
8865             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8866                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8867                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8868             }
8869             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8870             return this;
8871         },
8872
8873         /**
8874          * Forces the browser to repaint this element
8875          * @return {Roo.Element} this
8876          */
8877          repaint : function(){
8878             var dom = this.dom;
8879             this.addClass("x-repaint");
8880             setTimeout(function(){
8881                 Roo.get(dom).removeClass("x-repaint");
8882             }, 1);
8883             return this;
8884         },
8885
8886         /**
8887          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8888          * then it returns the calculated width of the sides (see getPadding)
8889          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8890          * @return {Object/Number}
8891          */
8892         getMargins : function(side){
8893             if(!side){
8894                 return {
8895                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8896                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8897                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8898                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8899                 };
8900             }else{
8901                 return this.addStyles(side, El.margins);
8902              }
8903         },
8904
8905         // private
8906         addStyles : function(sides, styles){
8907             var val = 0, v, w;
8908             for(var i = 0, len = sides.length; i < len; i++){
8909                 v = this.getStyle(styles[sides.charAt(i)]);
8910                 if(v){
8911                      w = parseInt(v, 10);
8912                      if(w){ val += w; }
8913                 }
8914             }
8915             return val;
8916         },
8917
8918         /**
8919          * Creates a proxy element of this element
8920          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8921          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8922          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8923          * @return {Roo.Element} The new proxy element
8924          */
8925         createProxy : function(config, renderTo, matchBox){
8926             if(renderTo){
8927                 renderTo = Roo.getDom(renderTo);
8928             }else{
8929                 renderTo = document.body;
8930             }
8931             config = typeof config == "object" ?
8932                 config : {tag : "div", cls: config};
8933             var proxy = Roo.DomHelper.append(renderTo, config, true);
8934             if(matchBox){
8935                proxy.setBox(this.getBox());
8936             }
8937             return proxy;
8938         },
8939
8940         /**
8941          * Puts a mask over this element to disable user interaction. Requires core.css.
8942          * This method can only be applied to elements which accept child nodes.
8943          * @param {String} msg (optional) A message to display in the mask
8944          * @param {String} msgCls (optional) A css class to apply to the msg element
8945          * @return {Element} The mask  element
8946          */
8947         mask : function(msg, msgCls)
8948         {
8949             if(this.getStyle("position") == "static"){
8950                 this.setStyle("position", "relative");
8951             }
8952             if(!this._mask){
8953                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8954             }
8955             this.addClass("x-masked");
8956             this._mask.setDisplayed(true);
8957             
8958             // we wander
8959             var z = 0;
8960             var dom = this.dom
8961             while (dom && dom.style) {
8962                 if (!isNaN(parseInt(dom.style.zIndex))) {
8963                     z = Math.max(z, parseInt(dom.style.zIndex));
8964                 }
8965                 dom = dom.parentNode;
8966             }
8967             // if we are masking the body - then it hides everything..
8968             if (this.dom == document.body) {
8969                 z = 1000000;
8970                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
8971                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
8972             }
8973            
8974             if(typeof msg == 'string'){
8975                 if(!this._maskMsg){
8976                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
8977                 }
8978                 var mm = this._maskMsg;
8979                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
8980                 mm.dom.firstChild.innerHTML = msg;
8981                 mm.setDisplayed(true);
8982                 mm.center(this);
8983                 mm.setStyle('z-index', z + 102);
8984             }
8985             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
8986                 this._mask.setHeight(this.getHeight());
8987             }
8988             this._mask.setStyle('z-index', z + 100);
8989             
8990             return this._mask;
8991         },
8992
8993         /**
8994          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
8995          * it is cached for reuse.
8996          */
8997         unmask : function(removeEl){
8998             if(this._mask){
8999                 if(removeEl === true){
9000                     this._mask.remove();
9001                     delete this._mask;
9002                     if(this._maskMsg){
9003                         this._maskMsg.remove();
9004                         delete this._maskMsg;
9005                     }
9006                 }else{
9007                     this._mask.setDisplayed(false);
9008                     if(this._maskMsg){
9009                         this._maskMsg.setDisplayed(false);
9010                     }
9011                 }
9012             }
9013             this.removeClass("x-masked");
9014         },
9015
9016         /**
9017          * Returns true if this element is masked
9018          * @return {Boolean}
9019          */
9020         isMasked : function(){
9021             return this._mask && this._mask.isVisible();
9022         },
9023
9024         /**
9025          * Creates an iframe shim for this element to keep selects and other windowed objects from
9026          * showing through.
9027          * @return {Roo.Element} The new shim element
9028          */
9029         createShim : function(){
9030             var el = document.createElement('iframe');
9031             el.frameBorder = 'no';
9032             el.className = 'roo-shim';
9033             if(Roo.isIE && Roo.isSecure){
9034                 el.src = Roo.SSL_SECURE_URL;
9035             }
9036             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9037             shim.autoBoxAdjust = false;
9038             return shim;
9039         },
9040
9041         /**
9042          * Removes this element from the DOM and deletes it from the cache
9043          */
9044         remove : function(){
9045             if(this.dom.parentNode){
9046                 this.dom.parentNode.removeChild(this.dom);
9047             }
9048             delete El.cache[this.dom.id];
9049         },
9050
9051         /**
9052          * Sets up event handlers to add and remove a css class when the mouse is over this element
9053          * @param {String} className
9054          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9055          * mouseout events for children elements
9056          * @return {Roo.Element} this
9057          */
9058         addClassOnOver : function(className, preventFlicker){
9059             this.on("mouseover", function(){
9060                 Roo.fly(this, '_internal').addClass(className);
9061             }, this.dom);
9062             var removeFn = function(e){
9063                 if(preventFlicker !== true || !e.within(this, true)){
9064                     Roo.fly(this, '_internal').removeClass(className);
9065                 }
9066             };
9067             this.on("mouseout", removeFn, this.dom);
9068             return this;
9069         },
9070
9071         /**
9072          * Sets up event handlers to add and remove a css class when this element has the focus
9073          * @param {String} className
9074          * @return {Roo.Element} this
9075          */
9076         addClassOnFocus : function(className){
9077             this.on("focus", function(){
9078                 Roo.fly(this, '_internal').addClass(className);
9079             }, this.dom);
9080             this.on("blur", function(){
9081                 Roo.fly(this, '_internal').removeClass(className);
9082             }, this.dom);
9083             return this;
9084         },
9085         /**
9086          * 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)
9087          * @param {String} className
9088          * @return {Roo.Element} this
9089          */
9090         addClassOnClick : function(className){
9091             var dom = this.dom;
9092             this.on("mousedown", function(){
9093                 Roo.fly(dom, '_internal').addClass(className);
9094                 var d = Roo.get(document);
9095                 var fn = function(){
9096                     Roo.fly(dom, '_internal').removeClass(className);
9097                     d.removeListener("mouseup", fn);
9098                 };
9099                 d.on("mouseup", fn);
9100             });
9101             return this;
9102         },
9103
9104         /**
9105          * Stops the specified event from bubbling and optionally prevents the default action
9106          * @param {String} eventName
9107          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9108          * @return {Roo.Element} this
9109          */
9110         swallowEvent : function(eventName, preventDefault){
9111             var fn = function(e){
9112                 e.stopPropagation();
9113                 if(preventDefault){
9114                     e.preventDefault();
9115                 }
9116             };
9117             if(eventName instanceof Array){
9118                 for(var i = 0, len = eventName.length; i < len; i++){
9119                      this.on(eventName[i], fn);
9120                 }
9121                 return this;
9122             }
9123             this.on(eventName, fn);
9124             return this;
9125         },
9126
9127         /**
9128          * @private
9129          */
9130       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9131
9132         /**
9133          * Sizes this element to its parent element's dimensions performing
9134          * neccessary box adjustments.
9135          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9136          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9137          * @return {Roo.Element} this
9138          */
9139         fitToParent : function(monitorResize, targetParent) {
9140           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9141           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9142           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9143             return;
9144           }
9145           var p = Roo.get(targetParent || this.dom.parentNode);
9146           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9147           if (monitorResize === true) {
9148             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9149             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9150           }
9151           return this;
9152         },
9153
9154         /**
9155          * Gets the next sibling, skipping text nodes
9156          * @return {HTMLElement} The next sibling or null
9157          */
9158         getNextSibling : function(){
9159             var n = this.dom.nextSibling;
9160             while(n && n.nodeType != 1){
9161                 n = n.nextSibling;
9162             }
9163             return n;
9164         },
9165
9166         /**
9167          * Gets the previous sibling, skipping text nodes
9168          * @return {HTMLElement} The previous sibling or null
9169          */
9170         getPrevSibling : function(){
9171             var n = this.dom.previousSibling;
9172             while(n && n.nodeType != 1){
9173                 n = n.previousSibling;
9174             }
9175             return n;
9176         },
9177
9178
9179         /**
9180          * Appends the passed element(s) to this element
9181          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9182          * @return {Roo.Element} this
9183          */
9184         appendChild: function(el){
9185             el = Roo.get(el);
9186             el.appendTo(this);
9187             return this;
9188         },
9189
9190         /**
9191          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9192          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9193          * automatically generated with the specified attributes.
9194          * @param {HTMLElement} insertBefore (optional) a child element of this element
9195          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9196          * @return {Roo.Element} The new child element
9197          */
9198         createChild: function(config, insertBefore, returnDom){
9199             config = config || {tag:'div'};
9200             if(insertBefore){
9201                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9202             }
9203             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9204         },
9205
9206         /**
9207          * Appends this element to the passed element
9208          * @param {String/HTMLElement/Element} el The new parent element
9209          * @return {Roo.Element} this
9210          */
9211         appendTo: function(el){
9212             el = Roo.getDom(el);
9213             el.appendChild(this.dom);
9214             return this;
9215         },
9216
9217         /**
9218          * Inserts this element before the passed element in the DOM
9219          * @param {String/HTMLElement/Element} el The element to insert before
9220          * @return {Roo.Element} this
9221          */
9222         insertBefore: function(el){
9223             el = Roo.getDom(el);
9224             el.parentNode.insertBefore(this.dom, el);
9225             return this;
9226         },
9227
9228         /**
9229          * Inserts this element after the passed element in the DOM
9230          * @param {String/HTMLElement/Element} el The element to insert after
9231          * @return {Roo.Element} this
9232          */
9233         insertAfter: function(el){
9234             el = Roo.getDom(el);
9235             el.parentNode.insertBefore(this.dom, el.nextSibling);
9236             return this;
9237         },
9238
9239         /**
9240          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9241          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9242          * @return {Roo.Element} The new child
9243          */
9244         insertFirst: function(el, returnDom){
9245             el = el || {};
9246             if(typeof el == 'object' && !el.nodeType){ // dh config
9247                 return this.createChild(el, this.dom.firstChild, returnDom);
9248             }else{
9249                 el = Roo.getDom(el);
9250                 this.dom.insertBefore(el, this.dom.firstChild);
9251                 return !returnDom ? Roo.get(el) : el;
9252             }
9253         },
9254
9255         /**
9256          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9257          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9258          * @param {String} where (optional) 'before' or 'after' defaults to before
9259          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9260          * @return {Roo.Element} the inserted Element
9261          */
9262         insertSibling: function(el, where, returnDom){
9263             where = where ? where.toLowerCase() : 'before';
9264             el = el || {};
9265             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9266
9267             if(typeof el == 'object' && !el.nodeType){ // dh config
9268                 if(where == 'after' && !this.dom.nextSibling){
9269                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9270                 }else{
9271                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9272                 }
9273
9274             }else{
9275                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9276                             where == 'before' ? this.dom : this.dom.nextSibling);
9277                 if(!returnDom){
9278                     rt = Roo.get(rt);
9279                 }
9280             }
9281             return rt;
9282         },
9283
9284         /**
9285          * Creates and wraps this element with another element
9286          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9287          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9288          * @return {HTMLElement/Element} The newly created wrapper element
9289          */
9290         wrap: function(config, returnDom){
9291             if(!config){
9292                 config = {tag: "div"};
9293             }
9294             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9295             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9296             return newEl;
9297         },
9298
9299         /**
9300          * Replaces the passed element with this element
9301          * @param {String/HTMLElement/Element} el The element to replace
9302          * @return {Roo.Element} this
9303          */
9304         replace: function(el){
9305             el = Roo.get(el);
9306             this.insertBefore(el);
9307             el.remove();
9308             return this;
9309         },
9310
9311         /**
9312          * Inserts an html fragment into this element
9313          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9314          * @param {String} html The HTML fragment
9315          * @param {Boolean} returnEl True to return an Roo.Element
9316          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9317          */
9318         insertHtml : function(where, html, returnEl){
9319             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9320             return returnEl ? Roo.get(el) : el;
9321         },
9322
9323         /**
9324          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9325          * @param {Object} o The object with the attributes
9326          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9327          * @return {Roo.Element} this
9328          */
9329         set : function(o, useSet){
9330             var el = this.dom;
9331             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9332             for(var attr in o){
9333                 if(attr == "style" || typeof o[attr] == "function") continue;
9334                 if(attr=="cls"){
9335                     el.className = o["cls"];
9336                 }else{
9337                     if(useSet) el.setAttribute(attr, o[attr]);
9338                     else el[attr] = o[attr];
9339                 }
9340             }
9341             if(o.style){
9342                 Roo.DomHelper.applyStyles(el, o.style);
9343             }
9344             return this;
9345         },
9346
9347         /**
9348          * Convenience method for constructing a KeyMap
9349          * @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:
9350          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9351          * @param {Function} fn The function to call
9352          * @param {Object} scope (optional) The scope of the function
9353          * @return {Roo.KeyMap} The KeyMap created
9354          */
9355         addKeyListener : function(key, fn, scope){
9356             var config;
9357             if(typeof key != "object" || key instanceof Array){
9358                 config = {
9359                     key: key,
9360                     fn: fn,
9361                     scope: scope
9362                 };
9363             }else{
9364                 config = {
9365                     key : key.key,
9366                     shift : key.shift,
9367                     ctrl : key.ctrl,
9368                     alt : key.alt,
9369                     fn: fn,
9370                     scope: scope
9371                 };
9372             }
9373             return new Roo.KeyMap(this, config);
9374         },
9375
9376         /**
9377          * Creates a KeyMap for this element
9378          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9379          * @return {Roo.KeyMap} The KeyMap created
9380          */
9381         addKeyMap : function(config){
9382             return new Roo.KeyMap(this, config);
9383         },
9384
9385         /**
9386          * Returns true if this element is scrollable.
9387          * @return {Boolean}
9388          */
9389          isScrollable : function(){
9390             var dom = this.dom;
9391             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9392         },
9393
9394         /**
9395          * 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().
9396          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9397          * @param {Number} value The new scroll value
9398          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9399          * @return {Element} this
9400          */
9401
9402         scrollTo : function(side, value, animate){
9403             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9404             if(!animate || !A){
9405                 this.dom[prop] = value;
9406             }else{
9407                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9408                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9409             }
9410             return this;
9411         },
9412
9413         /**
9414          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9415          * within this element's scrollable range.
9416          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9417          * @param {Number} distance How far to scroll the element in pixels
9418          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9419          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9420          * was scrolled as far as it could go.
9421          */
9422          scroll : function(direction, distance, animate){
9423              if(!this.isScrollable()){
9424                  return;
9425              }
9426              var el = this.dom;
9427              var l = el.scrollLeft, t = el.scrollTop;
9428              var w = el.scrollWidth, h = el.scrollHeight;
9429              var cw = el.clientWidth, ch = el.clientHeight;
9430              direction = direction.toLowerCase();
9431              var scrolled = false;
9432              var a = this.preanim(arguments, 2);
9433              switch(direction){
9434                  case "l":
9435                  case "left":
9436                      if(w - l > cw){
9437                          var v = Math.min(l + distance, w-cw);
9438                          this.scrollTo("left", v, a);
9439                          scrolled = true;
9440                      }
9441                      break;
9442                 case "r":
9443                 case "right":
9444                      if(l > 0){
9445                          var v = Math.max(l - distance, 0);
9446                          this.scrollTo("left", v, a);
9447                          scrolled = true;
9448                      }
9449                      break;
9450                 case "t":
9451                 case "top":
9452                 case "up":
9453                      if(t > 0){
9454                          var v = Math.max(t - distance, 0);
9455                          this.scrollTo("top", v, a);
9456                          scrolled = true;
9457                      }
9458                      break;
9459                 case "b":
9460                 case "bottom":
9461                 case "down":
9462                      if(h - t > ch){
9463                          var v = Math.min(t + distance, h-ch);
9464                          this.scrollTo("top", v, a);
9465                          scrolled = true;
9466                      }
9467                      break;
9468              }
9469              return scrolled;
9470         },
9471
9472         /**
9473          * Translates the passed page coordinates into left/top css values for this element
9474          * @param {Number/Array} x The page x or an array containing [x, y]
9475          * @param {Number} y The page y
9476          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9477          */
9478         translatePoints : function(x, y){
9479             if(typeof x == 'object' || x instanceof Array){
9480                 y = x[1]; x = x[0];
9481             }
9482             var p = this.getStyle('position');
9483             var o = this.getXY();
9484
9485             var l = parseInt(this.getStyle('left'), 10);
9486             var t = parseInt(this.getStyle('top'), 10);
9487
9488             if(isNaN(l)){
9489                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9490             }
9491             if(isNaN(t)){
9492                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9493             }
9494
9495             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9496         },
9497
9498         /**
9499          * Returns the current scroll position of the element.
9500          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9501          */
9502         getScroll : function(){
9503             var d = this.dom, doc = document;
9504             if(d == doc || d == doc.body){
9505                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9506                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9507                 return {left: l, top: t};
9508             }else{
9509                 return {left: d.scrollLeft, top: d.scrollTop};
9510             }
9511         },
9512
9513         /**
9514          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9515          * are convert to standard 6 digit hex color.
9516          * @param {String} attr The css attribute
9517          * @param {String} defaultValue The default value to use when a valid color isn't found
9518          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9519          * YUI color anims.
9520          */
9521         getColor : function(attr, defaultValue, prefix){
9522             var v = this.getStyle(attr);
9523             if(!v || v == "transparent" || v == "inherit") {
9524                 return defaultValue;
9525             }
9526             var color = typeof prefix == "undefined" ? "#" : prefix;
9527             if(v.substr(0, 4) == "rgb("){
9528                 var rvs = v.slice(4, v.length -1).split(",");
9529                 for(var i = 0; i < 3; i++){
9530                     var h = parseInt(rvs[i]).toString(16);
9531                     if(h < 16){
9532                         h = "0" + h;
9533                     }
9534                     color += h;
9535                 }
9536             } else {
9537                 if(v.substr(0, 1) == "#"){
9538                     if(v.length == 4) {
9539                         for(var i = 1; i < 4; i++){
9540                             var c = v.charAt(i);
9541                             color +=  c + c;
9542                         }
9543                     }else if(v.length == 7){
9544                         color += v.substr(1);
9545                     }
9546                 }
9547             }
9548             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9549         },
9550
9551         /**
9552          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9553          * gradient background, rounded corners and a 4-way shadow.
9554          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9555          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9556          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9557          * @return {Roo.Element} this
9558          */
9559         boxWrap : function(cls){
9560             cls = cls || 'x-box';
9561             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9562             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9563             return el;
9564         },
9565
9566         /**
9567          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9568          * @param {String} namespace The namespace in which to look for the attribute
9569          * @param {String} name The attribute name
9570          * @return {String} The attribute value
9571          */
9572         getAttributeNS : Roo.isIE ? function(ns, name){
9573             var d = this.dom;
9574             var type = typeof d[ns+":"+name];
9575             if(type != 'undefined' && type != 'unknown'){
9576                 return d[ns+":"+name];
9577             }
9578             return d[name];
9579         } : function(ns, name){
9580             var d = this.dom;
9581             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9582         },
9583         
9584         
9585         /**
9586          * Sets or Returns the value the dom attribute value
9587          * @param {String} name The attribute name
9588          * @param {String} value (optional) The value to set the attribute to
9589          * @return {String} The attribute value
9590          */
9591         attr : function(name){
9592             if (arguments.length > 1) {
9593                 this.dom.setAttribute(name, arguments[1]);
9594                 return arguments[1];
9595             }
9596             if (!this.dom.hasAttribute(name)) {
9597                 return undefined;
9598             }
9599             return this.dom.getAttribute(name);
9600         }
9601         
9602         
9603         
9604     };
9605
9606     var ep = El.prototype;
9607
9608     /**
9609      * Appends an event handler (Shorthand for addListener)
9610      * @param {String}   eventName     The type of event to append
9611      * @param {Function} fn        The method the event invokes
9612      * @param {Object} scope       (optional) The scope (this object) of the fn
9613      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9614      * @method
9615      */
9616     ep.on = ep.addListener;
9617         // backwards compat
9618     ep.mon = ep.addListener;
9619
9620     /**
9621      * Removes an event handler from this element (shorthand for removeListener)
9622      * @param {String} eventName the type of event to remove
9623      * @param {Function} fn the method the event invokes
9624      * @return {Roo.Element} this
9625      * @method
9626      */
9627     ep.un = ep.removeListener;
9628
9629     /**
9630      * true to automatically adjust width and height settings for box-model issues (default to true)
9631      */
9632     ep.autoBoxAdjust = true;
9633
9634     // private
9635     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9636
9637     // private
9638     El.addUnits = function(v, defaultUnit){
9639         if(v === "" || v == "auto"){
9640             return v;
9641         }
9642         if(v === undefined){
9643             return '';
9644         }
9645         if(typeof v == "number" || !El.unitPattern.test(v)){
9646             return v + (defaultUnit || 'px');
9647         }
9648         return v;
9649     };
9650
9651     // special markup used throughout Roo when box wrapping elements
9652     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>';
9653     /**
9654      * Visibility mode constant - Use visibility to hide element
9655      * @static
9656      * @type Number
9657      */
9658     El.VISIBILITY = 1;
9659     /**
9660      * Visibility mode constant - Use display to hide element
9661      * @static
9662      * @type Number
9663      */
9664     El.DISPLAY = 2;
9665
9666     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9667     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9668     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9669
9670
9671
9672     /**
9673      * @private
9674      */
9675     El.cache = {};
9676
9677     var docEl;
9678
9679     /**
9680      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9681      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9682      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9683      * @return {Element} The Element object
9684      * @static
9685      */
9686     El.get = function(el){
9687         var ex, elm, id;
9688         if(!el){ return null; }
9689         if(typeof el == "string"){ // element id
9690             if(!(elm = document.getElementById(el))){
9691                 return null;
9692             }
9693             if(ex = El.cache[el]){
9694                 ex.dom = elm;
9695             }else{
9696                 ex = El.cache[el] = new El(elm);
9697             }
9698             return ex;
9699         }else if(el.tagName){ // dom element
9700             if(!(id = el.id)){
9701                 id = Roo.id(el);
9702             }
9703             if(ex = El.cache[id]){
9704                 ex.dom = el;
9705             }else{
9706                 ex = El.cache[id] = new El(el);
9707             }
9708             return ex;
9709         }else if(el instanceof El){
9710             if(el != docEl){
9711                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9712                                                               // catch case where it hasn't been appended
9713                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9714             }
9715             return el;
9716         }else if(el.isComposite){
9717             return el;
9718         }else if(el instanceof Array){
9719             return El.select(el);
9720         }else if(el == document){
9721             // create a bogus element object representing the document object
9722             if(!docEl){
9723                 var f = function(){};
9724                 f.prototype = El.prototype;
9725                 docEl = new f();
9726                 docEl.dom = document;
9727             }
9728             return docEl;
9729         }
9730         return null;
9731     };
9732
9733     // private
9734     El.uncache = function(el){
9735         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9736             if(a[i]){
9737                 delete El.cache[a[i].id || a[i]];
9738             }
9739         }
9740     };
9741
9742     // private
9743     // Garbage collection - uncache elements/purge listeners on orphaned elements
9744     // so we don't hold a reference and cause the browser to retain them
9745     El.garbageCollect = function(){
9746         if(!Roo.enableGarbageCollector){
9747             clearInterval(El.collectorThread);
9748             return;
9749         }
9750         for(var eid in El.cache){
9751             var el = El.cache[eid], d = el.dom;
9752             // -------------------------------------------------------
9753             // Determining what is garbage:
9754             // -------------------------------------------------------
9755             // !d
9756             // dom node is null, definitely garbage
9757             // -------------------------------------------------------
9758             // !d.parentNode
9759             // no parentNode == direct orphan, definitely garbage
9760             // -------------------------------------------------------
9761             // !d.offsetParent && !document.getElementById(eid)
9762             // display none elements have no offsetParent so we will
9763             // also try to look it up by it's id. However, check
9764             // offsetParent first so we don't do unneeded lookups.
9765             // This enables collection of elements that are not orphans
9766             // directly, but somewhere up the line they have an orphan
9767             // parent.
9768             // -------------------------------------------------------
9769             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9770                 delete El.cache[eid];
9771                 if(d && Roo.enableListenerCollection){
9772                     E.purgeElement(d);
9773                 }
9774             }
9775         }
9776     }
9777     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9778
9779
9780     // dom is optional
9781     El.Flyweight = function(dom){
9782         this.dom = dom;
9783     };
9784     El.Flyweight.prototype = El.prototype;
9785
9786     El._flyweights = {};
9787     /**
9788      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9789      * the dom node can be overwritten by other code.
9790      * @param {String/HTMLElement} el The dom node or id
9791      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9792      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9793      * @static
9794      * @return {Element} The shared Element object
9795      */
9796     El.fly = function(el, named){
9797         named = named || '_global';
9798         el = Roo.getDom(el);
9799         if(!el){
9800             return null;
9801         }
9802         if(!El._flyweights[named]){
9803             El._flyweights[named] = new El.Flyweight();
9804         }
9805         El._flyweights[named].dom = el;
9806         return El._flyweights[named];
9807     };
9808
9809     /**
9810      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9811      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9812      * Shorthand of {@link Roo.Element#get}
9813      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9814      * @return {Element} The Element object
9815      * @member Roo
9816      * @method get
9817      */
9818     Roo.get = El.get;
9819     /**
9820      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9821      * the dom node can be overwritten by other code.
9822      * Shorthand of {@link Roo.Element#fly}
9823      * @param {String/HTMLElement} el The dom node or id
9824      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9825      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9826      * @static
9827      * @return {Element} The shared Element object
9828      * @member Roo
9829      * @method fly
9830      */
9831     Roo.fly = El.fly;
9832
9833     // speedy lookup for elements never to box adjust
9834     var noBoxAdjust = Roo.isStrict ? {
9835         select:1
9836     } : {
9837         input:1, select:1, textarea:1
9838     };
9839     if(Roo.isIE || Roo.isGecko){
9840         noBoxAdjust['button'] = 1;
9841     }
9842
9843
9844     Roo.EventManager.on(window, 'unload', function(){
9845         delete El.cache;
9846         delete El._flyweights;
9847     });
9848 })();
9849
9850
9851
9852
9853 if(Roo.DomQuery){
9854     Roo.Element.selectorFunction = Roo.DomQuery.select;
9855 }
9856
9857 Roo.Element.select = function(selector, unique, root){
9858     var els;
9859     if(typeof selector == "string"){
9860         els = Roo.Element.selectorFunction(selector, root);
9861     }else if(selector.length !== undefined){
9862         els = selector;
9863     }else{
9864         throw "Invalid selector";
9865     }
9866     if(unique === true){
9867         return new Roo.CompositeElement(els);
9868     }else{
9869         return new Roo.CompositeElementLite(els);
9870     }
9871 };
9872 /**
9873  * Selects elements based on the passed CSS selector to enable working on them as 1.
9874  * @param {String/Array} selector The CSS selector or an array of elements
9875  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9876  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9877  * @return {CompositeElementLite/CompositeElement}
9878  * @member Roo
9879  * @method select
9880  */
9881 Roo.select = Roo.Element.select;
9882
9883
9884
9885
9886
9887
9888
9889
9890
9891
9892
9893
9894
9895
9896 /*
9897  * Based on:
9898  * Ext JS Library 1.1.1
9899  * Copyright(c) 2006-2007, Ext JS, LLC.
9900  *
9901  * Originally Released Under LGPL - original licence link has changed is not relivant.
9902  *
9903  * Fork - LGPL
9904  * <script type="text/javascript">
9905  */
9906
9907
9908
9909 //Notifies Element that fx methods are available
9910 Roo.enableFx = true;
9911
9912 /**
9913  * @class Roo.Fx
9914  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9915  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9916  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9917  * Element effects to work.</p><br/>
9918  *
9919  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9920  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9921  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9922  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9923  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9924  * expected results and should be done with care.</p><br/>
9925  *
9926  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9927  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9928 <pre>
9929 Value  Description
9930 -----  -----------------------------
9931 tl     The top left corner
9932 t      The center of the top edge
9933 tr     The top right corner
9934 l      The center of the left edge
9935 r      The center of the right edge
9936 bl     The bottom left corner
9937 b      The center of the bottom edge
9938 br     The bottom right corner
9939 </pre>
9940  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9941  * below are common options that can be passed to any Fx method.</b>
9942  * @cfg {Function} callback A function called when the effect is finished
9943  * @cfg {Object} scope The scope of the effect function
9944  * @cfg {String} easing A valid Easing value for the effect
9945  * @cfg {String} afterCls A css class to apply after the effect
9946  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9947  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9948  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9949  * effects that end with the element being visually hidden, ignored otherwise)
9950  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9951  * a function which returns such a specification that will be applied to the Element after the effect finishes
9952  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9953  * @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
9954  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9955  */
9956 Roo.Fx = {
9957         /**
9958          * Slides the element into view.  An anchor point can be optionally passed to set the point of
9959          * origin for the slide effect.  This function automatically handles wrapping the element with
9960          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
9961          * Usage:
9962          *<pre><code>
9963 // default: slide the element in from the top
9964 el.slideIn();
9965
9966 // custom: slide the element in from the right with a 2-second duration
9967 el.slideIn('r', { duration: 2 });
9968
9969 // common config options shown with default values
9970 el.slideIn('t', {
9971     easing: 'easeOut',
9972     duration: .5
9973 });
9974 </code></pre>
9975          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
9976          * @param {Object} options (optional) Object literal with any of the Fx config options
9977          * @return {Roo.Element} The Element
9978          */
9979     slideIn : function(anchor, o){
9980         var el = this.getFxEl();
9981         o = o || {};
9982
9983         el.queueFx(o, function(){
9984
9985             anchor = anchor || "t";
9986
9987             // fix display to visibility
9988             this.fixDisplay();
9989
9990             // restore values after effect
9991             var r = this.getFxRestore();
9992             var b = this.getBox();
9993             // fixed size for slide
9994             this.setSize(b);
9995
9996             // wrap if needed
9997             var wrap = this.fxWrap(r.pos, o, "hidden");
9998
9999             var st = this.dom.style;
10000             st.visibility = "visible";
10001             st.position = "absolute";
10002
10003             // clear out temp styles after slide and unwrap
10004             var after = function(){
10005                 el.fxUnwrap(wrap, r.pos, o);
10006                 st.width = r.width;
10007                 st.height = r.height;
10008                 el.afterFx(o);
10009             };
10010             // time to calc the positions
10011             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10012
10013             switch(anchor.toLowerCase()){
10014                 case "t":
10015                     wrap.setSize(b.width, 0);
10016                     st.left = st.bottom = "0";
10017                     a = {height: bh};
10018                 break;
10019                 case "l":
10020                     wrap.setSize(0, b.height);
10021                     st.right = st.top = "0";
10022                     a = {width: bw};
10023                 break;
10024                 case "r":
10025                     wrap.setSize(0, b.height);
10026                     wrap.setX(b.right);
10027                     st.left = st.top = "0";
10028                     a = {width: bw, points: pt};
10029                 break;
10030                 case "b":
10031                     wrap.setSize(b.width, 0);
10032                     wrap.setY(b.bottom);
10033                     st.left = st.top = "0";
10034                     a = {height: bh, points: pt};
10035                 break;
10036                 case "tl":
10037                     wrap.setSize(0, 0);
10038                     st.right = st.bottom = "0";
10039                     a = {width: bw, height: bh};
10040                 break;
10041                 case "bl":
10042                     wrap.setSize(0, 0);
10043                     wrap.setY(b.y+b.height);
10044                     st.right = st.top = "0";
10045                     a = {width: bw, height: bh, points: pt};
10046                 break;
10047                 case "br":
10048                     wrap.setSize(0, 0);
10049                     wrap.setXY([b.right, b.bottom]);
10050                     st.left = st.top = "0";
10051                     a = {width: bw, height: bh, points: pt};
10052                 break;
10053                 case "tr":
10054                     wrap.setSize(0, 0);
10055                     wrap.setX(b.x+b.width);
10056                     st.left = st.bottom = "0";
10057                     a = {width: bw, height: bh, points: pt};
10058                 break;
10059             }
10060             this.dom.style.visibility = "visible";
10061             wrap.show();
10062
10063             arguments.callee.anim = wrap.fxanim(a,
10064                 o,
10065                 'motion',
10066                 .5,
10067                 'easeOut', after);
10068         });
10069         return this;
10070     },
10071     
10072         /**
10073          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10074          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10075          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10076          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10077          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10078          * Usage:
10079          *<pre><code>
10080 // default: slide the element out to the top
10081 el.slideOut();
10082
10083 // custom: slide the element out to the right with a 2-second duration
10084 el.slideOut('r', { duration: 2 });
10085
10086 // common config options shown with default values
10087 el.slideOut('t', {
10088     easing: 'easeOut',
10089     duration: .5,
10090     remove: false,
10091     useDisplay: false
10092 });
10093 </code></pre>
10094          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10095          * @param {Object} options (optional) Object literal with any of the Fx config options
10096          * @return {Roo.Element} The Element
10097          */
10098     slideOut : function(anchor, o){
10099         var el = this.getFxEl();
10100         o = o || {};
10101
10102         el.queueFx(o, function(){
10103
10104             anchor = anchor || "t";
10105
10106             // restore values after effect
10107             var r = this.getFxRestore();
10108             
10109             var b = this.getBox();
10110             // fixed size for slide
10111             this.setSize(b);
10112
10113             // wrap if needed
10114             var wrap = this.fxWrap(r.pos, o, "visible");
10115
10116             var st = this.dom.style;
10117             st.visibility = "visible";
10118             st.position = "absolute";
10119
10120             wrap.setSize(b);
10121
10122             var after = function(){
10123                 if(o.useDisplay){
10124                     el.setDisplayed(false);
10125                 }else{
10126                     el.hide();
10127                 }
10128
10129                 el.fxUnwrap(wrap, r.pos, o);
10130
10131                 st.width = r.width;
10132                 st.height = r.height;
10133
10134                 el.afterFx(o);
10135             };
10136
10137             var a, zero = {to: 0};
10138             switch(anchor.toLowerCase()){
10139                 case "t":
10140                     st.left = st.bottom = "0";
10141                     a = {height: zero};
10142                 break;
10143                 case "l":
10144                     st.right = st.top = "0";
10145                     a = {width: zero};
10146                 break;
10147                 case "r":
10148                     st.left = st.top = "0";
10149                     a = {width: zero, points: {to:[b.right, b.y]}};
10150                 break;
10151                 case "b":
10152                     st.left = st.top = "0";
10153                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10154                 break;
10155                 case "tl":
10156                     st.right = st.bottom = "0";
10157                     a = {width: zero, height: zero};
10158                 break;
10159                 case "bl":
10160                     st.right = st.top = "0";
10161                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10162                 break;
10163                 case "br":
10164                     st.left = st.top = "0";
10165                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10166                 break;
10167                 case "tr":
10168                     st.left = st.bottom = "0";
10169                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10170                 break;
10171             }
10172
10173             arguments.callee.anim = wrap.fxanim(a,
10174                 o,
10175                 'motion',
10176                 .5,
10177                 "easeOut", after);
10178         });
10179         return this;
10180     },
10181
10182         /**
10183          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10184          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10185          * The element must be removed from the DOM using the 'remove' config option if desired.
10186          * Usage:
10187          *<pre><code>
10188 // default
10189 el.puff();
10190
10191 // common config options shown with default values
10192 el.puff({
10193     easing: 'easeOut',
10194     duration: .5,
10195     remove: false,
10196     useDisplay: false
10197 });
10198 </code></pre>
10199          * @param {Object} options (optional) Object literal with any of the Fx config options
10200          * @return {Roo.Element} The Element
10201          */
10202     puff : function(o){
10203         var el = this.getFxEl();
10204         o = o || {};
10205
10206         el.queueFx(o, function(){
10207             this.clearOpacity();
10208             this.show();
10209
10210             // restore values after effect
10211             var r = this.getFxRestore();
10212             var st = this.dom.style;
10213
10214             var after = function(){
10215                 if(o.useDisplay){
10216                     el.setDisplayed(false);
10217                 }else{
10218                     el.hide();
10219                 }
10220
10221                 el.clearOpacity();
10222
10223                 el.setPositioning(r.pos);
10224                 st.width = r.width;
10225                 st.height = r.height;
10226                 st.fontSize = '';
10227                 el.afterFx(o);
10228             };
10229
10230             var width = this.getWidth();
10231             var height = this.getHeight();
10232
10233             arguments.callee.anim = this.fxanim({
10234                     width : {to: this.adjustWidth(width * 2)},
10235                     height : {to: this.adjustHeight(height * 2)},
10236                     points : {by: [-(width * .5), -(height * .5)]},
10237                     opacity : {to: 0},
10238                     fontSize: {to:200, unit: "%"}
10239                 },
10240                 o,
10241                 'motion',
10242                 .5,
10243                 "easeOut", after);
10244         });
10245         return this;
10246     },
10247
10248         /**
10249          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10250          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10251          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10252          * Usage:
10253          *<pre><code>
10254 // default
10255 el.switchOff();
10256
10257 // all config options shown with default values
10258 el.switchOff({
10259     easing: 'easeIn',
10260     duration: .3,
10261     remove: false,
10262     useDisplay: false
10263 });
10264 </code></pre>
10265          * @param {Object} options (optional) Object literal with any of the Fx config options
10266          * @return {Roo.Element} The Element
10267          */
10268     switchOff : function(o){
10269         var el = this.getFxEl();
10270         o = o || {};
10271
10272         el.queueFx(o, function(){
10273             this.clearOpacity();
10274             this.clip();
10275
10276             // restore values after effect
10277             var r = this.getFxRestore();
10278             var st = this.dom.style;
10279
10280             var after = function(){
10281                 if(o.useDisplay){
10282                     el.setDisplayed(false);
10283                 }else{
10284                     el.hide();
10285                 }
10286
10287                 el.clearOpacity();
10288                 el.setPositioning(r.pos);
10289                 st.width = r.width;
10290                 st.height = r.height;
10291
10292                 el.afterFx(o);
10293             };
10294
10295             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10296                 this.clearOpacity();
10297                 (function(){
10298                     this.fxanim({
10299                         height:{to:1},
10300                         points:{by:[0, this.getHeight() * .5]}
10301                     }, o, 'motion', 0.3, 'easeIn', after);
10302                 }).defer(100, this);
10303             });
10304         });
10305         return this;
10306     },
10307
10308     /**
10309      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10310      * changed using the "attr" config option) and then fading back to the original color. If no original
10311      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10312      * Usage:
10313 <pre><code>
10314 // default: highlight background to yellow
10315 el.highlight();
10316
10317 // custom: highlight foreground text to blue for 2 seconds
10318 el.highlight("0000ff", { attr: 'color', duration: 2 });
10319
10320 // common config options shown with default values
10321 el.highlight("ffff9c", {
10322     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10323     endColor: (current color) or "ffffff",
10324     easing: 'easeIn',
10325     duration: 1
10326 });
10327 </code></pre>
10328      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10329      * @param {Object} options (optional) Object literal with any of the Fx config options
10330      * @return {Roo.Element} The Element
10331      */ 
10332     highlight : function(color, o){
10333         var el = this.getFxEl();
10334         o = o || {};
10335
10336         el.queueFx(o, function(){
10337             color = color || "ffff9c";
10338             attr = o.attr || "backgroundColor";
10339
10340             this.clearOpacity();
10341             this.show();
10342
10343             var origColor = this.getColor(attr);
10344             var restoreColor = this.dom.style[attr];
10345             endColor = (o.endColor || origColor) || "ffffff";
10346
10347             var after = function(){
10348                 el.dom.style[attr] = restoreColor;
10349                 el.afterFx(o);
10350             };
10351
10352             var a = {};
10353             a[attr] = {from: color, to: endColor};
10354             arguments.callee.anim = this.fxanim(a,
10355                 o,
10356                 'color',
10357                 1,
10358                 'easeIn', after);
10359         });
10360         return this;
10361     },
10362
10363    /**
10364     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10365     * Usage:
10366 <pre><code>
10367 // default: a single light blue ripple
10368 el.frame();
10369
10370 // custom: 3 red ripples lasting 3 seconds total
10371 el.frame("ff0000", 3, { duration: 3 });
10372
10373 // common config options shown with default values
10374 el.frame("C3DAF9", 1, {
10375     duration: 1 //duration of entire animation (not each individual ripple)
10376     // Note: Easing is not configurable and will be ignored if included
10377 });
10378 </code></pre>
10379     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10380     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10381     * @param {Object} options (optional) Object literal with any of the Fx config options
10382     * @return {Roo.Element} The Element
10383     */
10384     frame : function(color, count, o){
10385         var el = this.getFxEl();
10386         o = o || {};
10387
10388         el.queueFx(o, function(){
10389             color = color || "#C3DAF9";
10390             if(color.length == 6){
10391                 color = "#" + color;
10392             }
10393             count = count || 1;
10394             duration = o.duration || 1;
10395             this.show();
10396
10397             var b = this.getBox();
10398             var animFn = function(){
10399                 var proxy = this.createProxy({
10400
10401                      style:{
10402                         visbility:"hidden",
10403                         position:"absolute",
10404                         "z-index":"35000", // yee haw
10405                         border:"0px solid " + color
10406                      }
10407                   });
10408                 var scale = Roo.isBorderBox ? 2 : 1;
10409                 proxy.animate({
10410                     top:{from:b.y, to:b.y - 20},
10411                     left:{from:b.x, to:b.x - 20},
10412                     borderWidth:{from:0, to:10},
10413                     opacity:{from:1, to:0},
10414                     height:{from:b.height, to:(b.height + (20*scale))},
10415                     width:{from:b.width, to:(b.width + (20*scale))}
10416                 }, duration, function(){
10417                     proxy.remove();
10418                 });
10419                 if(--count > 0){
10420                      animFn.defer((duration/2)*1000, this);
10421                 }else{
10422                     el.afterFx(o);
10423                 }
10424             };
10425             animFn.call(this);
10426         });
10427         return this;
10428     },
10429
10430    /**
10431     * Creates a pause before any subsequent queued effects begin.  If there are
10432     * no effects queued after the pause it will have no effect.
10433     * Usage:
10434 <pre><code>
10435 el.pause(1);
10436 </code></pre>
10437     * @param {Number} seconds The length of time to pause (in seconds)
10438     * @return {Roo.Element} The Element
10439     */
10440     pause : function(seconds){
10441         var el = this.getFxEl();
10442         var o = {};
10443
10444         el.queueFx(o, function(){
10445             setTimeout(function(){
10446                 el.afterFx(o);
10447             }, seconds * 1000);
10448         });
10449         return this;
10450     },
10451
10452    /**
10453     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10454     * using the "endOpacity" config option.
10455     * Usage:
10456 <pre><code>
10457 // default: fade in from opacity 0 to 100%
10458 el.fadeIn();
10459
10460 // custom: fade in from opacity 0 to 75% over 2 seconds
10461 el.fadeIn({ endOpacity: .75, duration: 2});
10462
10463 // common config options shown with default values
10464 el.fadeIn({
10465     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10466     easing: 'easeOut',
10467     duration: .5
10468 });
10469 </code></pre>
10470     * @param {Object} options (optional) Object literal with any of the Fx config options
10471     * @return {Roo.Element} The Element
10472     */
10473     fadeIn : function(o){
10474         var el = this.getFxEl();
10475         o = o || {};
10476         el.queueFx(o, function(){
10477             this.setOpacity(0);
10478             this.fixDisplay();
10479             this.dom.style.visibility = 'visible';
10480             var to = o.endOpacity || 1;
10481             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10482                 o, null, .5, "easeOut", function(){
10483                 if(to == 1){
10484                     this.clearOpacity();
10485                 }
10486                 el.afterFx(o);
10487             });
10488         });
10489         return this;
10490     },
10491
10492    /**
10493     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10494     * using the "endOpacity" config option.
10495     * Usage:
10496 <pre><code>
10497 // default: fade out from the element's current opacity to 0
10498 el.fadeOut();
10499
10500 // custom: fade out from the element's current opacity to 25% over 2 seconds
10501 el.fadeOut({ endOpacity: .25, duration: 2});
10502
10503 // common config options shown with default values
10504 el.fadeOut({
10505     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10506     easing: 'easeOut',
10507     duration: .5
10508     remove: false,
10509     useDisplay: false
10510 });
10511 </code></pre>
10512     * @param {Object} options (optional) Object literal with any of the Fx config options
10513     * @return {Roo.Element} The Element
10514     */
10515     fadeOut : function(o){
10516         var el = this.getFxEl();
10517         o = o || {};
10518         el.queueFx(o, function(){
10519             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10520                 o, null, .5, "easeOut", function(){
10521                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10522                      this.dom.style.display = "none";
10523                 }else{
10524                      this.dom.style.visibility = "hidden";
10525                 }
10526                 this.clearOpacity();
10527                 el.afterFx(o);
10528             });
10529         });
10530         return this;
10531     },
10532
10533    /**
10534     * Animates the transition of an element's dimensions from a starting height/width
10535     * to an ending height/width.
10536     * Usage:
10537 <pre><code>
10538 // change height and width to 100x100 pixels
10539 el.scale(100, 100);
10540
10541 // common config options shown with default values.  The height and width will default to
10542 // the element's existing values if passed as null.
10543 el.scale(
10544     [element's width],
10545     [element's height], {
10546     easing: 'easeOut',
10547     duration: .35
10548 });
10549 </code></pre>
10550     * @param {Number} width  The new width (pass undefined to keep the original width)
10551     * @param {Number} height  The new height (pass undefined to keep the original height)
10552     * @param {Object} options (optional) Object literal with any of the Fx config options
10553     * @return {Roo.Element} The Element
10554     */
10555     scale : function(w, h, o){
10556         this.shift(Roo.apply({}, o, {
10557             width: w,
10558             height: h
10559         }));
10560         return this;
10561     },
10562
10563    /**
10564     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10565     * Any of these properties not specified in the config object will not be changed.  This effect 
10566     * requires that at least one new dimension, position or opacity setting must be passed in on
10567     * the config object in order for the function to have any effect.
10568     * Usage:
10569 <pre><code>
10570 // slide the element horizontally to x position 200 while changing the height and opacity
10571 el.shift({ x: 200, height: 50, opacity: .8 });
10572
10573 // common config options shown with default values.
10574 el.shift({
10575     width: [element's width],
10576     height: [element's height],
10577     x: [element's x position],
10578     y: [element's y position],
10579     opacity: [element's opacity],
10580     easing: 'easeOut',
10581     duration: .35
10582 });
10583 </code></pre>
10584     * @param {Object} options  Object literal with any of the Fx config options
10585     * @return {Roo.Element} The Element
10586     */
10587     shift : function(o){
10588         var el = this.getFxEl();
10589         o = o || {};
10590         el.queueFx(o, function(){
10591             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10592             if(w !== undefined){
10593                 a.width = {to: this.adjustWidth(w)};
10594             }
10595             if(h !== undefined){
10596                 a.height = {to: this.adjustHeight(h)};
10597             }
10598             if(x !== undefined || y !== undefined){
10599                 a.points = {to: [
10600                     x !== undefined ? x : this.getX(),
10601                     y !== undefined ? y : this.getY()
10602                 ]};
10603             }
10604             if(op !== undefined){
10605                 a.opacity = {to: op};
10606             }
10607             if(o.xy !== undefined){
10608                 a.points = {to: o.xy};
10609             }
10610             arguments.callee.anim = this.fxanim(a,
10611                 o, 'motion', .35, "easeOut", function(){
10612                 el.afterFx(o);
10613             });
10614         });
10615         return this;
10616     },
10617
10618         /**
10619          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10620          * ending point of the effect.
10621          * Usage:
10622          *<pre><code>
10623 // default: slide the element downward while fading out
10624 el.ghost();
10625
10626 // custom: slide the element out to the right with a 2-second duration
10627 el.ghost('r', { duration: 2 });
10628
10629 // common config options shown with default values
10630 el.ghost('b', {
10631     easing: 'easeOut',
10632     duration: .5
10633     remove: false,
10634     useDisplay: false
10635 });
10636 </code></pre>
10637          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10638          * @param {Object} options (optional) Object literal with any of the Fx config options
10639          * @return {Roo.Element} The Element
10640          */
10641     ghost : function(anchor, o){
10642         var el = this.getFxEl();
10643         o = o || {};
10644
10645         el.queueFx(o, function(){
10646             anchor = anchor || "b";
10647
10648             // restore values after effect
10649             var r = this.getFxRestore();
10650             var w = this.getWidth(),
10651                 h = this.getHeight();
10652
10653             var st = this.dom.style;
10654
10655             var after = function(){
10656                 if(o.useDisplay){
10657                     el.setDisplayed(false);
10658                 }else{
10659                     el.hide();
10660                 }
10661
10662                 el.clearOpacity();
10663                 el.setPositioning(r.pos);
10664                 st.width = r.width;
10665                 st.height = r.height;
10666
10667                 el.afterFx(o);
10668             };
10669
10670             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10671             switch(anchor.toLowerCase()){
10672                 case "t":
10673                     pt.by = [0, -h];
10674                 break;
10675                 case "l":
10676                     pt.by = [-w, 0];
10677                 break;
10678                 case "r":
10679                     pt.by = [w, 0];
10680                 break;
10681                 case "b":
10682                     pt.by = [0, h];
10683                 break;
10684                 case "tl":
10685                     pt.by = [-w, -h];
10686                 break;
10687                 case "bl":
10688                     pt.by = [-w, h];
10689                 break;
10690                 case "br":
10691                     pt.by = [w, h];
10692                 break;
10693                 case "tr":
10694                     pt.by = [w, -h];
10695                 break;
10696             }
10697
10698             arguments.callee.anim = this.fxanim(a,
10699                 o,
10700                 'motion',
10701                 .5,
10702                 "easeOut", after);
10703         });
10704         return this;
10705     },
10706
10707         /**
10708          * Ensures that all effects queued after syncFx is called on the element are
10709          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10710          * @return {Roo.Element} The Element
10711          */
10712     syncFx : function(){
10713         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10714             block : false,
10715             concurrent : true,
10716             stopFx : false
10717         });
10718         return this;
10719     },
10720
10721         /**
10722          * Ensures that all effects queued after sequenceFx is called on the element are
10723          * run in sequence.  This is the opposite of {@link #syncFx}.
10724          * @return {Roo.Element} The Element
10725          */
10726     sequenceFx : function(){
10727         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10728             block : false,
10729             concurrent : false,
10730             stopFx : false
10731         });
10732         return this;
10733     },
10734
10735         /* @private */
10736     nextFx : function(){
10737         var ef = this.fxQueue[0];
10738         if(ef){
10739             ef.call(this);
10740         }
10741     },
10742
10743         /**
10744          * Returns true if the element has any effects actively running or queued, else returns false.
10745          * @return {Boolean} True if element has active effects, else false
10746          */
10747     hasActiveFx : function(){
10748         return this.fxQueue && this.fxQueue[0];
10749     },
10750
10751         /**
10752          * Stops any running effects and clears the element's internal effects queue if it contains
10753          * any additional effects that haven't started yet.
10754          * @return {Roo.Element} The Element
10755          */
10756     stopFx : function(){
10757         if(this.hasActiveFx()){
10758             var cur = this.fxQueue[0];
10759             if(cur && cur.anim && cur.anim.isAnimated()){
10760                 this.fxQueue = [cur]; // clear out others
10761                 cur.anim.stop(true);
10762             }
10763         }
10764         return this;
10765     },
10766
10767         /* @private */
10768     beforeFx : function(o){
10769         if(this.hasActiveFx() && !o.concurrent){
10770            if(o.stopFx){
10771                this.stopFx();
10772                return true;
10773            }
10774            return false;
10775         }
10776         return true;
10777     },
10778
10779         /**
10780          * Returns true if the element is currently blocking so that no other effect can be queued
10781          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10782          * used to ensure that an effect initiated by a user action runs to completion prior to the
10783          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10784          * @return {Boolean} True if blocking, else false
10785          */
10786     hasFxBlock : function(){
10787         var q = this.fxQueue;
10788         return q && q[0] && q[0].block;
10789     },
10790
10791         /* @private */
10792     queueFx : function(o, fn){
10793         if(!this.fxQueue){
10794             this.fxQueue = [];
10795         }
10796         if(!this.hasFxBlock()){
10797             Roo.applyIf(o, this.fxDefaults);
10798             if(!o.concurrent){
10799                 var run = this.beforeFx(o);
10800                 fn.block = o.block;
10801                 this.fxQueue.push(fn);
10802                 if(run){
10803                     this.nextFx();
10804                 }
10805             }else{
10806                 fn.call(this);
10807             }
10808         }
10809         return this;
10810     },
10811
10812         /* @private */
10813     fxWrap : function(pos, o, vis){
10814         var wrap;
10815         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10816             var wrapXY;
10817             if(o.fixPosition){
10818                 wrapXY = this.getXY();
10819             }
10820             var div = document.createElement("div");
10821             div.style.visibility = vis;
10822             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10823             wrap.setPositioning(pos);
10824             if(wrap.getStyle("position") == "static"){
10825                 wrap.position("relative");
10826             }
10827             this.clearPositioning('auto');
10828             wrap.clip();
10829             wrap.dom.appendChild(this.dom);
10830             if(wrapXY){
10831                 wrap.setXY(wrapXY);
10832             }
10833         }
10834         return wrap;
10835     },
10836
10837         /* @private */
10838     fxUnwrap : function(wrap, pos, o){
10839         this.clearPositioning();
10840         this.setPositioning(pos);
10841         if(!o.wrap){
10842             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10843             wrap.remove();
10844         }
10845     },
10846
10847         /* @private */
10848     getFxRestore : function(){
10849         var st = this.dom.style;
10850         return {pos: this.getPositioning(), width: st.width, height : st.height};
10851     },
10852
10853         /* @private */
10854     afterFx : function(o){
10855         if(o.afterStyle){
10856             this.applyStyles(o.afterStyle);
10857         }
10858         if(o.afterCls){
10859             this.addClass(o.afterCls);
10860         }
10861         if(o.remove === true){
10862             this.remove();
10863         }
10864         Roo.callback(o.callback, o.scope, [this]);
10865         if(!o.concurrent){
10866             this.fxQueue.shift();
10867             this.nextFx();
10868         }
10869     },
10870
10871         /* @private */
10872     getFxEl : function(){ // support for composite element fx
10873         return Roo.get(this.dom);
10874     },
10875
10876         /* @private */
10877     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10878         animType = animType || 'run';
10879         opt = opt || {};
10880         var anim = Roo.lib.Anim[animType](
10881             this.dom, args,
10882             (opt.duration || defaultDur) || .35,
10883             (opt.easing || defaultEase) || 'easeOut',
10884             function(){
10885                 Roo.callback(cb, this);
10886             },
10887             this
10888         );
10889         opt.anim = anim;
10890         return anim;
10891     }
10892 };
10893
10894 // backwords compat
10895 Roo.Fx.resize = Roo.Fx.scale;
10896
10897 //When included, Roo.Fx is automatically applied to Element so that all basic
10898 //effects are available directly via the Element API
10899 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10900  * Based on:
10901  * Ext JS Library 1.1.1
10902  * Copyright(c) 2006-2007, Ext JS, LLC.
10903  *
10904  * Originally Released Under LGPL - original licence link has changed is not relivant.
10905  *
10906  * Fork - LGPL
10907  * <script type="text/javascript">
10908  */
10909
10910
10911 /**
10912  * @class Roo.CompositeElement
10913  * Standard composite class. Creates a Roo.Element for every element in the collection.
10914  * <br><br>
10915  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10916  * actions will be performed on all the elements in this collection.</b>
10917  * <br><br>
10918  * All methods return <i>this</i> and can be chained.
10919  <pre><code>
10920  var els = Roo.select("#some-el div.some-class", true);
10921  // or select directly from an existing element
10922  var el = Roo.get('some-el');
10923  el.select('div.some-class', true);
10924
10925  els.setWidth(100); // all elements become 100 width
10926  els.hide(true); // all elements fade out and hide
10927  // or
10928  els.setWidth(100).hide(true);
10929  </code></pre>
10930  */
10931 Roo.CompositeElement = function(els){
10932     this.elements = [];
10933     this.addElements(els);
10934 };
10935 Roo.CompositeElement.prototype = {
10936     isComposite: true,
10937     addElements : function(els){
10938         if(!els) return this;
10939         if(typeof els == "string"){
10940             els = Roo.Element.selectorFunction(els);
10941         }
10942         var yels = this.elements;
10943         var index = yels.length-1;
10944         for(var i = 0, len = els.length; i < len; i++) {
10945                 yels[++index] = Roo.get(els[i]);
10946         }
10947         return this;
10948     },
10949
10950     /**
10951     * Clears this composite and adds the elements returned by the passed selector.
10952     * @param {String/Array} els A string CSS selector, an array of elements or an element
10953     * @return {CompositeElement} this
10954     */
10955     fill : function(els){
10956         this.elements = [];
10957         this.add(els);
10958         return this;
10959     },
10960
10961     /**
10962     * Filters this composite to only elements that match the passed selector.
10963     * @param {String} selector A string CSS selector
10964     * @return {CompositeElement} this
10965     */
10966     filter : function(selector){
10967         var els = [];
10968         this.each(function(el){
10969             if(el.is(selector)){
10970                 els[els.length] = el.dom;
10971             }
10972         });
10973         this.fill(els);
10974         return this;
10975     },
10976
10977     invoke : function(fn, args){
10978         var els = this.elements;
10979         for(var i = 0, len = els.length; i < len; i++) {
10980                 Roo.Element.prototype[fn].apply(els[i], args);
10981         }
10982         return this;
10983     },
10984     /**
10985     * Adds elements to this composite.
10986     * @param {String/Array} els A string CSS selector, an array of elements or an element
10987     * @return {CompositeElement} this
10988     */
10989     add : function(els){
10990         if(typeof els == "string"){
10991             this.addElements(Roo.Element.selectorFunction(els));
10992         }else if(els.length !== undefined){
10993             this.addElements(els);
10994         }else{
10995             this.addElements([els]);
10996         }
10997         return this;
10998     },
10999     /**
11000     * Calls the passed function passing (el, this, index) for each element in this composite.
11001     * @param {Function} fn The function to call
11002     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11003     * @return {CompositeElement} this
11004     */
11005     each : function(fn, scope){
11006         var els = this.elements;
11007         for(var i = 0, len = els.length; i < len; i++){
11008             if(fn.call(scope || els[i], els[i], this, i) === false) {
11009                 break;
11010             }
11011         }
11012         return this;
11013     },
11014
11015     /**
11016      * Returns the Element object at the specified index
11017      * @param {Number} index
11018      * @return {Roo.Element}
11019      */
11020     item : function(index){
11021         return this.elements[index] || null;
11022     },
11023
11024     /**
11025      * Returns the first Element
11026      * @return {Roo.Element}
11027      */
11028     first : function(){
11029         return this.item(0);
11030     },
11031
11032     /**
11033      * Returns the last Element
11034      * @return {Roo.Element}
11035      */
11036     last : function(){
11037         return this.item(this.elements.length-1);
11038     },
11039
11040     /**
11041      * Returns the number of elements in this composite
11042      * @return Number
11043      */
11044     getCount : function(){
11045         return this.elements.length;
11046     },
11047
11048     /**
11049      * Returns true if this composite contains the passed element
11050      * @return Boolean
11051      */
11052     contains : function(el){
11053         return this.indexOf(el) !== -1;
11054     },
11055
11056     /**
11057      * Returns true if this composite contains the passed element
11058      * @return Boolean
11059      */
11060     indexOf : function(el){
11061         return this.elements.indexOf(Roo.get(el));
11062     },
11063
11064
11065     /**
11066     * Removes the specified element(s).
11067     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11068     * or an array of any of those.
11069     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11070     * @return {CompositeElement} this
11071     */
11072     removeElement : function(el, removeDom){
11073         if(el instanceof Array){
11074             for(var i = 0, len = el.length; i < len; i++){
11075                 this.removeElement(el[i]);
11076             }
11077             return this;
11078         }
11079         var index = typeof el == 'number' ? el : this.indexOf(el);
11080         if(index !== -1){
11081             if(removeDom){
11082                 var d = this.elements[index];
11083                 if(d.dom){
11084                     d.remove();
11085                 }else{
11086                     d.parentNode.removeChild(d);
11087                 }
11088             }
11089             this.elements.splice(index, 1);
11090         }
11091         return this;
11092     },
11093
11094     /**
11095     * Replaces the specified element with the passed element.
11096     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11097     * to replace.
11098     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11099     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11100     * @return {CompositeElement} this
11101     */
11102     replaceElement : function(el, replacement, domReplace){
11103         var index = typeof el == 'number' ? el : this.indexOf(el);
11104         if(index !== -1){
11105             if(domReplace){
11106                 this.elements[index].replaceWith(replacement);
11107             }else{
11108                 this.elements.splice(index, 1, Roo.get(replacement))
11109             }
11110         }
11111         return this;
11112     },
11113
11114     /**
11115      * Removes all elements.
11116      */
11117     clear : function(){
11118         this.elements = [];
11119     }
11120 };
11121 (function(){
11122     Roo.CompositeElement.createCall = function(proto, fnName){
11123         if(!proto[fnName]){
11124             proto[fnName] = function(){
11125                 return this.invoke(fnName, arguments);
11126             };
11127         }
11128     };
11129     for(var fnName in Roo.Element.prototype){
11130         if(typeof Roo.Element.prototype[fnName] == "function"){
11131             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11132         }
11133     };
11134 })();
11135 /*
11136  * Based on:
11137  * Ext JS Library 1.1.1
11138  * Copyright(c) 2006-2007, Ext JS, LLC.
11139  *
11140  * Originally Released Under LGPL - original licence link has changed is not relivant.
11141  *
11142  * Fork - LGPL
11143  * <script type="text/javascript">
11144  */
11145
11146 /**
11147  * @class Roo.CompositeElementLite
11148  * @extends Roo.CompositeElement
11149  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11150  <pre><code>
11151  var els = Roo.select("#some-el div.some-class");
11152  // or select directly from an existing element
11153  var el = Roo.get('some-el');
11154  el.select('div.some-class');
11155
11156  els.setWidth(100); // all elements become 100 width
11157  els.hide(true); // all elements fade out and hide
11158  // or
11159  els.setWidth(100).hide(true);
11160  </code></pre><br><br>
11161  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11162  * actions will be performed on all the elements in this collection.</b>
11163  */
11164 Roo.CompositeElementLite = function(els){
11165     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11166     this.el = new Roo.Element.Flyweight();
11167 };
11168 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11169     addElements : function(els){
11170         if(els){
11171             if(els instanceof Array){
11172                 this.elements = this.elements.concat(els);
11173             }else{
11174                 var yels = this.elements;
11175                 var index = yels.length-1;
11176                 for(var i = 0, len = els.length; i < len; i++) {
11177                     yels[++index] = els[i];
11178                 }
11179             }
11180         }
11181         return this;
11182     },
11183     invoke : function(fn, args){
11184         var els = this.elements;
11185         var el = this.el;
11186         for(var i = 0, len = els.length; i < len; i++) {
11187             el.dom = els[i];
11188                 Roo.Element.prototype[fn].apply(el, args);
11189         }
11190         return this;
11191     },
11192     /**
11193      * Returns a flyweight Element of the dom element object at the specified index
11194      * @param {Number} index
11195      * @return {Roo.Element}
11196      */
11197     item : function(index){
11198         if(!this.elements[index]){
11199             return null;
11200         }
11201         this.el.dom = this.elements[index];
11202         return this.el;
11203     },
11204
11205     // fixes scope with flyweight
11206     addListener : function(eventName, handler, scope, opt){
11207         var els = this.elements;
11208         for(var i = 0, len = els.length; i < len; i++) {
11209             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11210         }
11211         return this;
11212     },
11213
11214     /**
11215     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11216     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11217     * a reference to the dom node, use el.dom.</b>
11218     * @param {Function} fn The function to call
11219     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11220     * @return {CompositeElement} this
11221     */
11222     each : function(fn, scope){
11223         var els = this.elements;
11224         var el = this.el;
11225         for(var i = 0, len = els.length; i < len; i++){
11226             el.dom = els[i];
11227                 if(fn.call(scope || el, el, this, i) === false){
11228                 break;
11229             }
11230         }
11231         return this;
11232     },
11233
11234     indexOf : function(el){
11235         return this.elements.indexOf(Roo.getDom(el));
11236     },
11237
11238     replaceElement : function(el, replacement, domReplace){
11239         var index = typeof el == 'number' ? el : this.indexOf(el);
11240         if(index !== -1){
11241             replacement = Roo.getDom(replacement);
11242             if(domReplace){
11243                 var d = this.elements[index];
11244                 d.parentNode.insertBefore(replacement, d);
11245                 d.parentNode.removeChild(d);
11246             }
11247             this.elements.splice(index, 1, replacement);
11248         }
11249         return this;
11250     }
11251 });
11252 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11253
11254 /*
11255  * Based on:
11256  * Ext JS Library 1.1.1
11257  * Copyright(c) 2006-2007, Ext JS, LLC.
11258  *
11259  * Originally Released Under LGPL - original licence link has changed is not relivant.
11260  *
11261  * Fork - LGPL
11262  * <script type="text/javascript">
11263  */
11264
11265  
11266
11267 /**
11268  * @class Roo.data.Connection
11269  * @extends Roo.util.Observable
11270  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11271  * either to a configured URL, or to a URL specified at request time.<br><br>
11272  * <p>
11273  * Requests made by this class are asynchronous, and will return immediately. No data from
11274  * the server will be available to the statement immediately following the {@link #request} call.
11275  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11276  * <p>
11277  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11278  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11279  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11280  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11281  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11282  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11283  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11284  * standard DOM methods.
11285  * @constructor
11286  * @param {Object} config a configuration object.
11287  */
11288 Roo.data.Connection = function(config){
11289     Roo.apply(this, config);
11290     this.addEvents({
11291         /**
11292          * @event beforerequest
11293          * Fires before a network request is made to retrieve a data object.
11294          * @param {Connection} conn This Connection object.
11295          * @param {Object} options The options config object passed to the {@link #request} method.
11296          */
11297         "beforerequest" : true,
11298         /**
11299          * @event requestcomplete
11300          * Fires if the request was successfully completed.
11301          * @param {Connection} conn This Connection object.
11302          * @param {Object} response The XHR object containing the response data.
11303          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11304          * @param {Object} options The options config object passed to the {@link #request} method.
11305          */
11306         "requestcomplete" : true,
11307         /**
11308          * @event requestexception
11309          * Fires if an error HTTP status was returned from the server.
11310          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11311          * @param {Connection} conn This Connection object.
11312          * @param {Object} response The XHR object containing the response data.
11313          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11314          * @param {Object} options The options config object passed to the {@link #request} method.
11315          */
11316         "requestexception" : true
11317     });
11318     Roo.data.Connection.superclass.constructor.call(this);
11319 };
11320
11321 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11322     /**
11323      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11324      */
11325     /**
11326      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11327      * extra parameters to each request made by this object. (defaults to undefined)
11328      */
11329     /**
11330      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11331      *  to each request made by this object. (defaults to undefined)
11332      */
11333     /**
11334      * @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)
11335      */
11336     /**
11337      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11338      */
11339     timeout : 30000,
11340     /**
11341      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11342      * @type Boolean
11343      */
11344     autoAbort:false,
11345
11346     /**
11347      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11348      * @type Boolean
11349      */
11350     disableCaching: true,
11351
11352     /**
11353      * Sends an HTTP request to a remote server.
11354      * @param {Object} options An object which may contain the following properties:<ul>
11355      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11356      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11357      * request, a url encoded string or a function to call to get either.</li>
11358      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11359      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11360      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11361      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11362      * <li>options {Object} The parameter to the request call.</li>
11363      * <li>success {Boolean} True if the request succeeded.</li>
11364      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11365      * </ul></li>
11366      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11367      * The callback is passed the following parameters:<ul>
11368      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11369      * <li>options {Object} The parameter to the request call.</li>
11370      * </ul></li>
11371      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11372      * The callback is passed the following parameters:<ul>
11373      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11374      * <li>options {Object} The parameter to the request call.</li>
11375      * </ul></li>
11376      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11377      * for the callback function. Defaults to the browser window.</li>
11378      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11379      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11380      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11381      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11382      * params for the post data. Any params will be appended to the URL.</li>
11383      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11384      * </ul>
11385      * @return {Number} transactionId
11386      */
11387     request : function(o){
11388         if(this.fireEvent("beforerequest", this, o) !== false){
11389             var p = o.params;
11390
11391             if(typeof p == "function"){
11392                 p = p.call(o.scope||window, o);
11393             }
11394             if(typeof p == "object"){
11395                 p = Roo.urlEncode(o.params);
11396             }
11397             if(this.extraParams){
11398                 var extras = Roo.urlEncode(this.extraParams);
11399                 p = p ? (p + '&' + extras) : extras;
11400             }
11401
11402             var url = o.url || this.url;
11403             if(typeof url == 'function'){
11404                 url = url.call(o.scope||window, o);
11405             }
11406
11407             if(o.form){
11408                 var form = Roo.getDom(o.form);
11409                 url = url || form.action;
11410
11411                 var enctype = form.getAttribute("enctype");
11412                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11413                     return this.doFormUpload(o, p, url);
11414                 }
11415                 var f = Roo.lib.Ajax.serializeForm(form);
11416                 p = p ? (p + '&' + f) : f;
11417             }
11418
11419             var hs = o.headers;
11420             if(this.defaultHeaders){
11421                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11422                 if(!o.headers){
11423                     o.headers = hs;
11424                 }
11425             }
11426
11427             var cb = {
11428                 success: this.handleResponse,
11429                 failure: this.handleFailure,
11430                 scope: this,
11431                 argument: {options: o},
11432                 timeout : o.timeout || this.timeout
11433             };
11434
11435             var method = o.method||this.method||(p ? "POST" : "GET");
11436
11437             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11438                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11439             }
11440
11441             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11442                 if(o.autoAbort){
11443                     this.abort();
11444                 }
11445             }else if(this.autoAbort !== false){
11446                 this.abort();
11447             }
11448
11449             if((method == 'GET' && p) || o.xmlData){
11450                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11451                 p = '';
11452             }
11453             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11454             return this.transId;
11455         }else{
11456             Roo.callback(o.callback, o.scope, [o, null, null]);
11457             return null;
11458         }
11459     },
11460
11461     /**
11462      * Determine whether this object has a request outstanding.
11463      * @param {Number} transactionId (Optional) defaults to the last transaction
11464      * @return {Boolean} True if there is an outstanding request.
11465      */
11466     isLoading : function(transId){
11467         if(transId){
11468             return Roo.lib.Ajax.isCallInProgress(transId);
11469         }else{
11470             return this.transId ? true : false;
11471         }
11472     },
11473
11474     /**
11475      * Aborts any outstanding request.
11476      * @param {Number} transactionId (Optional) defaults to the last transaction
11477      */
11478     abort : function(transId){
11479         if(transId || this.isLoading()){
11480             Roo.lib.Ajax.abort(transId || this.transId);
11481         }
11482     },
11483
11484     // private
11485     handleResponse : function(response){
11486         this.transId = false;
11487         var options = response.argument.options;
11488         response.argument = options ? options.argument : null;
11489         this.fireEvent("requestcomplete", this, response, options);
11490         Roo.callback(options.success, options.scope, [response, options]);
11491         Roo.callback(options.callback, options.scope, [options, true, response]);
11492     },
11493
11494     // private
11495     handleFailure : function(response, e){
11496         this.transId = false;
11497         var options = response.argument.options;
11498         response.argument = options ? options.argument : null;
11499         this.fireEvent("requestexception", this, response, options, e);
11500         Roo.callback(options.failure, options.scope, [response, options]);
11501         Roo.callback(options.callback, options.scope, [options, false, response]);
11502     },
11503
11504     // private
11505     doFormUpload : function(o, ps, url){
11506         var id = Roo.id();
11507         var frame = document.createElement('iframe');
11508         frame.id = id;
11509         frame.name = id;
11510         frame.className = 'x-hidden';
11511         if(Roo.isIE){
11512             frame.src = Roo.SSL_SECURE_URL;
11513         }
11514         document.body.appendChild(frame);
11515
11516         if(Roo.isIE){
11517            document.frames[id].name = id;
11518         }
11519
11520         var form = Roo.getDom(o.form);
11521         form.target = id;
11522         form.method = 'POST';
11523         form.enctype = form.encoding = 'multipart/form-data';
11524         if(url){
11525             form.action = url;
11526         }
11527
11528         var hiddens, hd;
11529         if(ps){ // add dynamic params
11530             hiddens = [];
11531             ps = Roo.urlDecode(ps, false);
11532             for(var k in ps){
11533                 if(ps.hasOwnProperty(k)){
11534                     hd = document.createElement('input');
11535                     hd.type = 'hidden';
11536                     hd.name = k;
11537                     hd.value = ps[k];
11538                     form.appendChild(hd);
11539                     hiddens.push(hd);
11540                 }
11541             }
11542         }
11543
11544         function cb(){
11545             var r = {  // bogus response object
11546                 responseText : '',
11547                 responseXML : null
11548             };
11549
11550             r.argument = o ? o.argument : null;
11551
11552             try { //
11553                 var doc;
11554                 if(Roo.isIE){
11555                     doc = frame.contentWindow.document;
11556                 }else {
11557                     doc = (frame.contentDocument || window.frames[id].document);
11558                 }
11559                 if(doc && doc.body){
11560                     r.responseText = doc.body.innerHTML;
11561                 }
11562                 if(doc && doc.XMLDocument){
11563                     r.responseXML = doc.XMLDocument;
11564                 }else {
11565                     r.responseXML = doc;
11566                 }
11567             }
11568             catch(e) {
11569                 // ignore
11570             }
11571
11572             Roo.EventManager.removeListener(frame, 'load', cb, this);
11573
11574             this.fireEvent("requestcomplete", this, r, o);
11575             Roo.callback(o.success, o.scope, [r, o]);
11576             Roo.callback(o.callback, o.scope, [o, true, r]);
11577
11578             setTimeout(function(){document.body.removeChild(frame);}, 100);
11579         }
11580
11581         Roo.EventManager.on(frame, 'load', cb, this);
11582         form.submit();
11583
11584         if(hiddens){ // remove dynamic params
11585             for(var i = 0, len = hiddens.length; i < len; i++){
11586                 form.removeChild(hiddens[i]);
11587             }
11588         }
11589     }
11590 });
11591 /*
11592  * Based on:
11593  * Ext JS Library 1.1.1
11594  * Copyright(c) 2006-2007, Ext JS, LLC.
11595  *
11596  * Originally Released Under LGPL - original licence link has changed is not relivant.
11597  *
11598  * Fork - LGPL
11599  * <script type="text/javascript">
11600  */
11601  
11602 /**
11603  * Global Ajax request class.
11604  * 
11605  * @class Roo.Ajax
11606  * @extends Roo.data.Connection
11607  * @static
11608  * 
11609  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11610  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11611  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11612  * @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)
11613  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11614  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11615  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11616  */
11617 Roo.Ajax = new Roo.data.Connection({
11618     // fix up the docs
11619     /**
11620      * @scope Roo.Ajax
11621      * @type {Boolear} 
11622      */
11623     autoAbort : false,
11624
11625     /**
11626      * Serialize the passed form into a url encoded string
11627      * @scope Roo.Ajax
11628      * @param {String/HTMLElement} form
11629      * @return {String}
11630      */
11631     serializeForm : function(form){
11632         return Roo.lib.Ajax.serializeForm(form);
11633     }
11634 });/*
11635  * Based on:
11636  * Ext JS Library 1.1.1
11637  * Copyright(c) 2006-2007, Ext JS, LLC.
11638  *
11639  * Originally Released Under LGPL - original licence link has changed is not relivant.
11640  *
11641  * Fork - LGPL
11642  * <script type="text/javascript">
11643  */
11644
11645  
11646 /**
11647  * @class Roo.UpdateManager
11648  * @extends Roo.util.Observable
11649  * Provides AJAX-style update for Element object.<br><br>
11650  * Usage:<br>
11651  * <pre><code>
11652  * // Get it from a Roo.Element object
11653  * var el = Roo.get("foo");
11654  * var mgr = el.getUpdateManager();
11655  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11656  * ...
11657  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11658  * <br>
11659  * // or directly (returns the same UpdateManager instance)
11660  * var mgr = new Roo.UpdateManager("myElementId");
11661  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11662  * mgr.on("update", myFcnNeedsToKnow);
11663  * <br>
11664    // short handed call directly from the element object
11665    Roo.get("foo").load({
11666         url: "bar.php",
11667         scripts:true,
11668         params: "for=bar",
11669         text: "Loading Foo..."
11670    });
11671  * </code></pre>
11672  * @constructor
11673  * Create new UpdateManager directly.
11674  * @param {String/HTMLElement/Roo.Element} el The element to update
11675  * @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).
11676  */
11677 Roo.UpdateManager = function(el, forceNew){
11678     el = Roo.get(el);
11679     if(!forceNew && el.updateManager){
11680         return el.updateManager;
11681     }
11682     /**
11683      * The Element object
11684      * @type Roo.Element
11685      */
11686     this.el = el;
11687     /**
11688      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11689      * @type String
11690      */
11691     this.defaultUrl = null;
11692
11693     this.addEvents({
11694         /**
11695          * @event beforeupdate
11696          * Fired before an update is made, return false from your handler and the update is cancelled.
11697          * @param {Roo.Element} el
11698          * @param {String/Object/Function} url
11699          * @param {String/Object} params
11700          */
11701         "beforeupdate": true,
11702         /**
11703          * @event update
11704          * Fired after successful update is made.
11705          * @param {Roo.Element} el
11706          * @param {Object} oResponseObject The response Object
11707          */
11708         "update": true,
11709         /**
11710          * @event failure
11711          * Fired on update failure.
11712          * @param {Roo.Element} el
11713          * @param {Object} oResponseObject The response Object
11714          */
11715         "failure": true
11716     });
11717     var d = Roo.UpdateManager.defaults;
11718     /**
11719      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11720      * @type String
11721      */
11722     this.sslBlankUrl = d.sslBlankUrl;
11723     /**
11724      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11725      * @type Boolean
11726      */
11727     this.disableCaching = d.disableCaching;
11728     /**
11729      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11730      * @type String
11731      */
11732     this.indicatorText = d.indicatorText;
11733     /**
11734      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11735      * @type String
11736      */
11737     this.showLoadIndicator = d.showLoadIndicator;
11738     /**
11739      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11740      * @type Number
11741      */
11742     this.timeout = d.timeout;
11743
11744     /**
11745      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11746      * @type Boolean
11747      */
11748     this.loadScripts = d.loadScripts;
11749
11750     /**
11751      * Transaction object of current executing transaction
11752      */
11753     this.transaction = null;
11754
11755     /**
11756      * @private
11757      */
11758     this.autoRefreshProcId = null;
11759     /**
11760      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11761      * @type Function
11762      */
11763     this.refreshDelegate = this.refresh.createDelegate(this);
11764     /**
11765      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11766      * @type Function
11767      */
11768     this.updateDelegate = this.update.createDelegate(this);
11769     /**
11770      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11771      * @type Function
11772      */
11773     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11774     /**
11775      * @private
11776      */
11777     this.successDelegate = this.processSuccess.createDelegate(this);
11778     /**
11779      * @private
11780      */
11781     this.failureDelegate = this.processFailure.createDelegate(this);
11782
11783     if(!this.renderer){
11784      /**
11785       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11786       */
11787     this.renderer = new Roo.UpdateManager.BasicRenderer();
11788     }
11789     
11790     Roo.UpdateManager.superclass.constructor.call(this);
11791 };
11792
11793 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11794     /**
11795      * Get the Element this UpdateManager is bound to
11796      * @return {Roo.Element} The element
11797      */
11798     getEl : function(){
11799         return this.el;
11800     },
11801     /**
11802      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11803      * @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:
11804 <pre><code>
11805 um.update({<br/>
11806     url: "your-url.php",<br/>
11807     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11808     callback: yourFunction,<br/>
11809     scope: yourObject, //(optional scope)  <br/>
11810     discardUrl: false, <br/>
11811     nocache: false,<br/>
11812     text: "Loading...",<br/>
11813     timeout: 30,<br/>
11814     scripts: false<br/>
11815 });
11816 </code></pre>
11817      * The only required property is url. The optional properties nocache, text and scripts
11818      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11819      * @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}
11820      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11821      * @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.
11822      */
11823     update : function(url, params, callback, discardUrl){
11824         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11825             var method = this.method,
11826                 cfg;
11827             if(typeof url == "object"){ // must be config object
11828                 cfg = url;
11829                 url = cfg.url;
11830                 params = params || cfg.params;
11831                 callback = callback || cfg.callback;
11832                 discardUrl = discardUrl || cfg.discardUrl;
11833                 if(callback && cfg.scope){
11834                     callback = callback.createDelegate(cfg.scope);
11835                 }
11836                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11837                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11838                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11839                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11840                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11841             }
11842             this.showLoading();
11843             if(!discardUrl){
11844                 this.defaultUrl = url;
11845             }
11846             if(typeof url == "function"){
11847                 url = url.call(this);
11848             }
11849
11850             method = method || (params ? "POST" : "GET");
11851             if(method == "GET"){
11852                 url = this.prepareUrl(url);
11853             }
11854
11855             var o = Roo.apply(cfg ||{}, {
11856                 url : url,
11857                 params: params,
11858                 success: this.successDelegate,
11859                 failure: this.failureDelegate,
11860                 callback: undefined,
11861                 timeout: (this.timeout*1000),
11862                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11863             });
11864             Roo.log("updated manager called with timeout of " + o.timeout);
11865             this.transaction = Roo.Ajax.request(o);
11866         }
11867     },
11868
11869     /**
11870      * 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.
11871      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11872      * @param {String/HTMLElement} form The form Id or form element
11873      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11874      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11875      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11876      */
11877     formUpdate : function(form, url, reset, callback){
11878         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11879             if(typeof url == "function"){
11880                 url = url.call(this);
11881             }
11882             form = Roo.getDom(form);
11883             this.transaction = Roo.Ajax.request({
11884                 form: form,
11885                 url:url,
11886                 success: this.successDelegate,
11887                 failure: this.failureDelegate,
11888                 timeout: (this.timeout*1000),
11889                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11890             });
11891             this.showLoading.defer(1, this);
11892         }
11893     },
11894
11895     /**
11896      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11897      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11898      */
11899     refresh : function(callback){
11900         if(this.defaultUrl == null){
11901             return;
11902         }
11903         this.update(this.defaultUrl, null, callback, true);
11904     },
11905
11906     /**
11907      * Set this element to auto refresh.
11908      * @param {Number} interval How often to update (in seconds).
11909      * @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)
11910      * @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}
11911      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11912      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11913      */
11914     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11915         if(refreshNow){
11916             this.update(url || this.defaultUrl, params, callback, true);
11917         }
11918         if(this.autoRefreshProcId){
11919             clearInterval(this.autoRefreshProcId);
11920         }
11921         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11922     },
11923
11924     /**
11925      * Stop auto refresh on this element.
11926      */
11927      stopAutoRefresh : function(){
11928         if(this.autoRefreshProcId){
11929             clearInterval(this.autoRefreshProcId);
11930             delete this.autoRefreshProcId;
11931         }
11932     },
11933
11934     isAutoRefreshing : function(){
11935        return this.autoRefreshProcId ? true : false;
11936     },
11937     /**
11938      * Called to update the element to "Loading" state. Override to perform custom action.
11939      */
11940     showLoading : function(){
11941         if(this.showLoadIndicator){
11942             this.el.update(this.indicatorText);
11943         }
11944     },
11945
11946     /**
11947      * Adds unique parameter to query string if disableCaching = true
11948      * @private
11949      */
11950     prepareUrl : function(url){
11951         if(this.disableCaching){
11952             var append = "_dc=" + (new Date().getTime());
11953             if(url.indexOf("?") !== -1){
11954                 url += "&" + append;
11955             }else{
11956                 url += "?" + append;
11957             }
11958         }
11959         return url;
11960     },
11961
11962     /**
11963      * @private
11964      */
11965     processSuccess : function(response){
11966         this.transaction = null;
11967         if(response.argument.form && response.argument.reset){
11968             try{ // put in try/catch since some older FF releases had problems with this
11969                 response.argument.form.reset();
11970             }catch(e){}
11971         }
11972         if(this.loadScripts){
11973             this.renderer.render(this.el, response, this,
11974                 this.updateComplete.createDelegate(this, [response]));
11975         }else{
11976             this.renderer.render(this.el, response, this);
11977             this.updateComplete(response);
11978         }
11979     },
11980
11981     updateComplete : function(response){
11982         this.fireEvent("update", this.el, response);
11983         if(typeof response.argument.callback == "function"){
11984             response.argument.callback(this.el, true, response);
11985         }
11986     },
11987
11988     /**
11989      * @private
11990      */
11991     processFailure : function(response){
11992         this.transaction = null;
11993         this.fireEvent("failure", this.el, response);
11994         if(typeof response.argument.callback == "function"){
11995             response.argument.callback(this.el, false, response);
11996         }
11997     },
11998
11999     /**
12000      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12001      * @param {Object} renderer The object implementing the render() method
12002      */
12003     setRenderer : function(renderer){
12004         this.renderer = renderer;
12005     },
12006
12007     getRenderer : function(){
12008        return this.renderer;
12009     },
12010
12011     /**
12012      * Set the defaultUrl used for updates
12013      * @param {String/Function} defaultUrl The url or a function to call to get the url
12014      */
12015     setDefaultUrl : function(defaultUrl){
12016         this.defaultUrl = defaultUrl;
12017     },
12018
12019     /**
12020      * Aborts the executing transaction
12021      */
12022     abort : function(){
12023         if(this.transaction){
12024             Roo.Ajax.abort(this.transaction);
12025         }
12026     },
12027
12028     /**
12029      * Returns true if an update is in progress
12030      * @return {Boolean}
12031      */
12032     isUpdating : function(){
12033         if(this.transaction){
12034             return Roo.Ajax.isLoading(this.transaction);
12035         }
12036         return false;
12037     }
12038 });
12039
12040 /**
12041  * @class Roo.UpdateManager.defaults
12042  * @static (not really - but it helps the doc tool)
12043  * The defaults collection enables customizing the default properties of UpdateManager
12044  */
12045    Roo.UpdateManager.defaults = {
12046        /**
12047          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12048          * @type Number
12049          */
12050          timeout : 30,
12051
12052          /**
12053          * True to process scripts by default (Defaults to false).
12054          * @type Boolean
12055          */
12056         loadScripts : false,
12057
12058         /**
12059         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12060         * @type String
12061         */
12062         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12063         /**
12064          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12065          * @type Boolean
12066          */
12067         disableCaching : false,
12068         /**
12069          * Whether to show indicatorText when loading (Defaults to true).
12070          * @type Boolean
12071          */
12072         showLoadIndicator : true,
12073         /**
12074          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12075          * @type String
12076          */
12077         indicatorText : '<div class="loading-indicator">Loading...</div>'
12078    };
12079
12080 /**
12081  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12082  *Usage:
12083  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12084  * @param {String/HTMLElement/Roo.Element} el The element to update
12085  * @param {String} url The url
12086  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12087  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12088  * @static
12089  * @deprecated
12090  * @member Roo.UpdateManager
12091  */
12092 Roo.UpdateManager.updateElement = function(el, url, params, options){
12093     var um = Roo.get(el, true).getUpdateManager();
12094     Roo.apply(um, options);
12095     um.update(url, params, options ? options.callback : null);
12096 };
12097 // alias for backwards compat
12098 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12099 /**
12100  * @class Roo.UpdateManager.BasicRenderer
12101  * Default Content renderer. Updates the elements innerHTML with the responseText.
12102  */
12103 Roo.UpdateManager.BasicRenderer = function(){};
12104
12105 Roo.UpdateManager.BasicRenderer.prototype = {
12106     /**
12107      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12108      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12109      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12110      * @param {Roo.Element} el The element being rendered
12111      * @param {Object} response The YUI Connect response object
12112      * @param {UpdateManager} updateManager The calling update manager
12113      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12114      */
12115      render : function(el, response, updateManager, callback){
12116         el.update(response.responseText, updateManager.loadScripts, callback);
12117     }
12118 };
12119 /*
12120  * Based on:
12121  * Roo JS
12122  * (c)) Alan Knowles
12123  * Licence : LGPL
12124  */
12125
12126
12127 /**
12128  * @class Roo.DomTemplate
12129  * @extends Roo.Template
12130  * An effort at a dom based template engine..
12131  *
12132  * Similar to XTemplate, except it uses dom parsing to create the template..
12133  *
12134  * Supported features:
12135  *
12136  *  Tags:
12137
12138 <pre><code>
12139       {a_variable} - output encoded.
12140       {a_variable.format:("Y-m-d")} - call a method on the variable
12141       {a_variable:raw} - unencoded output
12142       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12143       {a_variable:this.method_on_template(...)} - call a method on the template object.
12144  
12145 </code></pre>
12146  *  The tpl tag:
12147 <pre><code>
12148         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12149         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12150         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12151         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12152   
12153 </code></pre>
12154  *      
12155  */
12156 Roo.DomTemplate = function()
12157 {
12158      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12159      if (this.html) {
12160         this.compile();
12161      }
12162 };
12163
12164
12165 Roo.extend(Roo.DomTemplate, Roo.Template, {
12166     /**
12167      * id counter for sub templates.
12168      */
12169     id : 0,
12170     /**
12171      * flag to indicate if dom parser is inside a pre,
12172      * it will strip whitespace if not.
12173      */
12174     inPre : false,
12175     
12176     /**
12177      * The various sub templates
12178      */
12179     tpls : false,
12180     
12181     
12182     
12183     /**
12184      *
12185      * basic tag replacing syntax
12186      * WORD:WORD()
12187      *
12188      * // you can fake an object call by doing this
12189      *  x.t:(test,tesT) 
12190      * 
12191      */
12192     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12193     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12194     
12195     iterChild : function (node, method) {
12196         
12197         var oldPre = this.inPre;
12198         if (node.tagName == 'PRE') {
12199             this.inPre = true;
12200         }
12201         for( var i = 0; i < node.childNodes.length; i++) {
12202             method.call(this, node.childNodes[i]);
12203         }
12204         this.inPre = oldPre;
12205     },
12206     
12207     
12208     
12209     /**
12210      * compile the template
12211      *
12212      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12213      *
12214      */
12215     compile: function()
12216     {
12217         var s = this.html;
12218         
12219         // covert the html into DOM...
12220         var doc = false;
12221         var div =false;
12222         try {
12223             doc = document.implementation.createHTMLDocument("");
12224             doc.documentElement.innerHTML =   this.html  ;
12225             div = doc.documentElement;
12226         } catch (e) {
12227             // old IE... - nasty -- it causes all sorts of issues.. with
12228             // images getting pulled from server..
12229             div = document.createElement('div');
12230             div.innerHTML = this.html;
12231         }
12232         //doc.documentElement.innerHTML = htmlBody
12233          
12234         
12235         
12236         this.tpls = [];
12237         var _t = this;
12238         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12239         
12240         var tpls = this.tpls;
12241         
12242         // create a top level template from the snippet..
12243         
12244         //Roo.log(div.innerHTML);
12245         
12246         var tpl = {
12247             uid : 'master',
12248             id : this.id++,
12249             attr : false,
12250             value : false,
12251             body : div.innerHTML,
12252             
12253             forCall : false,
12254             execCall : false,
12255             dom : div,
12256             isTop : true
12257             
12258         };
12259         tpls.unshift(tpl);
12260         
12261         
12262         // compile them...
12263         this.tpls = [];
12264         Roo.each(tpls, function(tp){
12265             this.compileTpl(tp);
12266             this.tpls[tp.id] = tp;
12267         }, this);
12268         
12269         this.master = tpls[0];
12270         return this;
12271         
12272         
12273     },
12274     
12275     compileNode : function(node, istop) {
12276         // test for
12277         //Roo.log(node);
12278         
12279         
12280         // skip anything not a tag..
12281         if (node.nodeType != 1) {
12282             if (node.nodeType == 3 && !this.inPre) {
12283                 // reduce white space..
12284                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12285                 
12286             }
12287             return;
12288         }
12289         
12290         var tpl = {
12291             uid : false,
12292             id : false,
12293             attr : false,
12294             value : false,
12295             body : '',
12296             
12297             forCall : false,
12298             execCall : false,
12299             dom : false,
12300             isTop : istop
12301             
12302             
12303         };
12304         
12305         
12306         switch(true) {
12307             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12308             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12309             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12310             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12311             // no default..
12312         }
12313         
12314         
12315         if (!tpl.attr) {
12316             // just itterate children..
12317             this.iterChild(node,this.compileNode);
12318             return;
12319         }
12320         tpl.uid = this.id++;
12321         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12322         node.removeAttribute('roo-'+ tpl.attr);
12323         if (tpl.attr != 'name') {
12324             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12325             node.parentNode.replaceChild(placeholder,  node);
12326         } else {
12327             
12328             var placeholder =  document.createElement('span');
12329             placeholder.className = 'roo-tpl-' + tpl.value;
12330             node.parentNode.replaceChild(placeholder,  node);
12331         }
12332         
12333         // parent now sees '{domtplXXXX}
12334         this.iterChild(node,this.compileNode);
12335         
12336         // we should now have node body...
12337         var div = document.createElement('div');
12338         div.appendChild(node);
12339         tpl.dom = node;
12340         // this has the unfortunate side effect of converting tagged attributes
12341         // eg. href="{...}" into %7C...%7D
12342         // this has been fixed by searching for those combo's although it's a bit hacky..
12343         
12344         
12345         tpl.body = div.innerHTML;
12346         
12347         
12348          
12349         tpl.id = tpl.uid;
12350         switch(tpl.attr) {
12351             case 'for' :
12352                 switch (tpl.value) {
12353                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12354                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12355                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12356                 }
12357                 break;
12358             
12359             case 'exec':
12360                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12361                 break;
12362             
12363             case 'if':     
12364                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12365                 break;
12366             
12367             case 'name':
12368                 tpl.id  = tpl.value; // replace non characters???
12369                 break;
12370             
12371         }
12372         
12373         
12374         this.tpls.push(tpl);
12375         
12376         
12377         
12378     },
12379     
12380     
12381     
12382     
12383     /**
12384      * Compile a segment of the template into a 'sub-template'
12385      *
12386      * 
12387      * 
12388      *
12389      */
12390     compileTpl : function(tpl)
12391     {
12392         var fm = Roo.util.Format;
12393         var useF = this.disableFormats !== true;
12394         
12395         var sep = Roo.isGecko ? "+\n" : ",\n";
12396         
12397         var undef = function(str) {
12398             Roo.debug && Roo.log("Property not found :"  + str);
12399             return '';
12400         };
12401           
12402         //Roo.log(tpl.body);
12403         
12404         
12405         
12406         var fn = function(m, lbrace, name, format, args)
12407         {
12408             //Roo.log("ARGS");
12409             //Roo.log(arguments);
12410             args = args ? args.replace(/\\'/g,"'") : args;
12411             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12412             if (typeof(format) == 'undefined') {
12413                 format =  'htmlEncode'; 
12414             }
12415             if (format == 'raw' ) {
12416                 format = false;
12417             }
12418             
12419             if(name.substr(0, 6) == 'domtpl'){
12420                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12421             }
12422             
12423             // build an array of options to determine if value is undefined..
12424             
12425             // basically get 'xxxx.yyyy' then do
12426             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12427             //    (function () { Roo.log("Property not found"); return ''; })() :
12428             //    ......
12429             
12430             var udef_ar = [];
12431             var lookfor = '';
12432             Roo.each(name.split('.'), function(st) {
12433                 lookfor += (lookfor.length ? '.': '') + st;
12434                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12435             });
12436             
12437             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12438             
12439             
12440             if(format && useF){
12441                 
12442                 args = args ? ',' + args : "";
12443                  
12444                 if(format.substr(0, 5) != "this."){
12445                     format = "fm." + format + '(';
12446                 }else{
12447                     format = 'this.call("'+ format.substr(5) + '", ';
12448                     args = ", values";
12449                 }
12450                 
12451                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12452             }
12453              
12454             if (args && args.length) {
12455                 // called with xxyx.yuu:(test,test)
12456                 // change to ()
12457                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12458             }
12459             // raw.. - :raw modifier..
12460             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12461             
12462         };
12463         var body;
12464         // branched to use + in gecko and [].join() in others
12465         if(Roo.isGecko){
12466             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12467                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12468                     "';};};";
12469         }else{
12470             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12471             body.push(tpl.body.replace(/(\r\n|\n)/g,
12472                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12473             body.push("'].join('');};};");
12474             body = body.join('');
12475         }
12476         
12477         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12478        
12479         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12480         eval(body);
12481         
12482         return this;
12483     },
12484      
12485     /**
12486      * same as applyTemplate, except it's done to one of the subTemplates
12487      * when using named templates, you can do:
12488      *
12489      * var str = pl.applySubTemplate('your-name', values);
12490      *
12491      * 
12492      * @param {Number} id of the template
12493      * @param {Object} values to apply to template
12494      * @param {Object} parent (normaly the instance of this object)
12495      */
12496     applySubTemplate : function(id, values, parent)
12497     {
12498         
12499         
12500         var t = this.tpls[id];
12501         
12502         
12503         try { 
12504             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12505                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12506                 return '';
12507             }
12508         } catch(e) {
12509             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12510             Roo.log(values);
12511           
12512             return '';
12513         }
12514         try { 
12515             
12516             if(t.execCall && t.execCall.call(this, values, parent)){
12517                 return '';
12518             }
12519         } catch(e) {
12520             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12521             Roo.log(values);
12522             return '';
12523         }
12524         
12525         try {
12526             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12527             parent = t.target ? values : parent;
12528             if(t.forCall && vs instanceof Array){
12529                 var buf = [];
12530                 for(var i = 0, len = vs.length; i < len; i++){
12531                     try {
12532                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12533                     } catch (e) {
12534                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12535                         Roo.log(e.body);
12536                         //Roo.log(t.compiled);
12537                         Roo.log(vs[i]);
12538                     }   
12539                 }
12540                 return buf.join('');
12541             }
12542         } catch (e) {
12543             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12544             Roo.log(values);
12545             return '';
12546         }
12547         try {
12548             return t.compiled.call(this, vs, parent);
12549         } catch (e) {
12550             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12551             Roo.log(e.body);
12552             //Roo.log(t.compiled);
12553             Roo.log(values);
12554             return '';
12555         }
12556     },
12557
12558    
12559
12560     applyTemplate : function(values){
12561         return this.master.compiled.call(this, values, {});
12562         //var s = this.subs;
12563     },
12564
12565     apply : function(){
12566         return this.applyTemplate.apply(this, arguments);
12567     }
12568
12569  });
12570
12571 Roo.DomTemplate.from = function(el){
12572     el = Roo.getDom(el);
12573     return new Roo.Domtemplate(el.value || el.innerHTML);
12574 };/*
12575  * Based on:
12576  * Ext JS Library 1.1.1
12577  * Copyright(c) 2006-2007, Ext JS, LLC.
12578  *
12579  * Originally Released Under LGPL - original licence link has changed is not relivant.
12580  *
12581  * Fork - LGPL
12582  * <script type="text/javascript">
12583  */
12584
12585 /**
12586  * @class Roo.util.DelayedTask
12587  * Provides a convenient method of performing setTimeout where a new
12588  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12589  * You can use this class to buffer
12590  * the keypress events for a certain number of milliseconds, and perform only if they stop
12591  * for that amount of time.
12592  * @constructor The parameters to this constructor serve as defaults and are not required.
12593  * @param {Function} fn (optional) The default function to timeout
12594  * @param {Object} scope (optional) The default scope of that timeout
12595  * @param {Array} args (optional) The default Array of arguments
12596  */
12597 Roo.util.DelayedTask = function(fn, scope, args){
12598     var id = null, d, t;
12599
12600     var call = function(){
12601         var now = new Date().getTime();
12602         if(now - t >= d){
12603             clearInterval(id);
12604             id = null;
12605             fn.apply(scope, args || []);
12606         }
12607     };
12608     /**
12609      * Cancels any pending timeout and queues a new one
12610      * @param {Number} delay The milliseconds to delay
12611      * @param {Function} newFn (optional) Overrides function passed to constructor
12612      * @param {Object} newScope (optional) Overrides scope passed to constructor
12613      * @param {Array} newArgs (optional) Overrides args passed to constructor
12614      */
12615     this.delay = function(delay, newFn, newScope, newArgs){
12616         if(id && delay != d){
12617             this.cancel();
12618         }
12619         d = delay;
12620         t = new Date().getTime();
12621         fn = newFn || fn;
12622         scope = newScope || scope;
12623         args = newArgs || args;
12624         if(!id){
12625             id = setInterval(call, d);
12626         }
12627     };
12628
12629     /**
12630      * Cancel the last queued timeout
12631      */
12632     this.cancel = function(){
12633         if(id){
12634             clearInterval(id);
12635             id = null;
12636         }
12637     };
12638 };/*
12639  * Based on:
12640  * Ext JS Library 1.1.1
12641  * Copyright(c) 2006-2007, Ext JS, LLC.
12642  *
12643  * Originally Released Under LGPL - original licence link has changed is not relivant.
12644  *
12645  * Fork - LGPL
12646  * <script type="text/javascript">
12647  */
12648  
12649  
12650 Roo.util.TaskRunner = function(interval){
12651     interval = interval || 10;
12652     var tasks = [], removeQueue = [];
12653     var id = 0;
12654     var running = false;
12655
12656     var stopThread = function(){
12657         running = false;
12658         clearInterval(id);
12659         id = 0;
12660     };
12661
12662     var startThread = function(){
12663         if(!running){
12664             running = true;
12665             id = setInterval(runTasks, interval);
12666         }
12667     };
12668
12669     var removeTask = function(task){
12670         removeQueue.push(task);
12671         if(task.onStop){
12672             task.onStop();
12673         }
12674     };
12675
12676     var runTasks = function(){
12677         if(removeQueue.length > 0){
12678             for(var i = 0, len = removeQueue.length; i < len; i++){
12679                 tasks.remove(removeQueue[i]);
12680             }
12681             removeQueue = [];
12682             if(tasks.length < 1){
12683                 stopThread();
12684                 return;
12685             }
12686         }
12687         var now = new Date().getTime();
12688         for(var i = 0, len = tasks.length; i < len; ++i){
12689             var t = tasks[i];
12690             var itime = now - t.taskRunTime;
12691             if(t.interval <= itime){
12692                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12693                 t.taskRunTime = now;
12694                 if(rt === false || t.taskRunCount === t.repeat){
12695                     removeTask(t);
12696                     return;
12697                 }
12698             }
12699             if(t.duration && t.duration <= (now - t.taskStartTime)){
12700                 removeTask(t);
12701             }
12702         }
12703     };
12704
12705     /**
12706      * Queues a new task.
12707      * @param {Object} task
12708      */
12709     this.start = function(task){
12710         tasks.push(task);
12711         task.taskStartTime = new Date().getTime();
12712         task.taskRunTime = 0;
12713         task.taskRunCount = 0;
12714         startThread();
12715         return task;
12716     };
12717
12718     this.stop = function(task){
12719         removeTask(task);
12720         return task;
12721     };
12722
12723     this.stopAll = function(){
12724         stopThread();
12725         for(var i = 0, len = tasks.length; i < len; i++){
12726             if(tasks[i].onStop){
12727                 tasks[i].onStop();
12728             }
12729         }
12730         tasks = [];
12731         removeQueue = [];
12732     };
12733 };
12734
12735 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12736  * Based on:
12737  * Ext JS Library 1.1.1
12738  * Copyright(c) 2006-2007, Ext JS, LLC.
12739  *
12740  * Originally Released Under LGPL - original licence link has changed is not relivant.
12741  *
12742  * Fork - LGPL
12743  * <script type="text/javascript">
12744  */
12745
12746  
12747 /**
12748  * @class Roo.util.MixedCollection
12749  * @extends Roo.util.Observable
12750  * A Collection class that maintains both numeric indexes and keys and exposes events.
12751  * @constructor
12752  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12753  * collection (defaults to false)
12754  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12755  * and return the key value for that item.  This is used when available to look up the key on items that
12756  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12757  * equivalent to providing an implementation for the {@link #getKey} method.
12758  */
12759 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12760     this.items = [];
12761     this.map = {};
12762     this.keys = [];
12763     this.length = 0;
12764     this.addEvents({
12765         /**
12766          * @event clear
12767          * Fires when the collection is cleared.
12768          */
12769         "clear" : true,
12770         /**
12771          * @event add
12772          * Fires when an item is added to the collection.
12773          * @param {Number} index The index at which the item was added.
12774          * @param {Object} o The item added.
12775          * @param {String} key The key associated with the added item.
12776          */
12777         "add" : true,
12778         /**
12779          * @event replace
12780          * Fires when an item is replaced in the collection.
12781          * @param {String} key he key associated with the new added.
12782          * @param {Object} old The item being replaced.
12783          * @param {Object} new The new item.
12784          */
12785         "replace" : true,
12786         /**
12787          * @event remove
12788          * Fires when an item is removed from the collection.
12789          * @param {Object} o The item being removed.
12790          * @param {String} key (optional) The key associated with the removed item.
12791          */
12792         "remove" : true,
12793         "sort" : true
12794     });
12795     this.allowFunctions = allowFunctions === true;
12796     if(keyFn){
12797         this.getKey = keyFn;
12798     }
12799     Roo.util.MixedCollection.superclass.constructor.call(this);
12800 };
12801
12802 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12803     allowFunctions : false,
12804     
12805 /**
12806  * Adds an item to the collection.
12807  * @param {String} key The key to associate with the item
12808  * @param {Object} o The item to add.
12809  * @return {Object} The item added.
12810  */
12811     add : function(key, o){
12812         if(arguments.length == 1){
12813             o = arguments[0];
12814             key = this.getKey(o);
12815         }
12816         if(typeof key == "undefined" || key === null){
12817             this.length++;
12818             this.items.push(o);
12819             this.keys.push(null);
12820         }else{
12821             var old = this.map[key];
12822             if(old){
12823                 return this.replace(key, o);
12824             }
12825             this.length++;
12826             this.items.push(o);
12827             this.map[key] = o;
12828             this.keys.push(key);
12829         }
12830         this.fireEvent("add", this.length-1, o, key);
12831         return o;
12832     },
12833        
12834 /**
12835   * MixedCollection has a generic way to fetch keys if you implement getKey.
12836 <pre><code>
12837 // normal way
12838 var mc = new Roo.util.MixedCollection();
12839 mc.add(someEl.dom.id, someEl);
12840 mc.add(otherEl.dom.id, otherEl);
12841 //and so on
12842
12843 // using getKey
12844 var mc = new Roo.util.MixedCollection();
12845 mc.getKey = function(el){
12846    return el.dom.id;
12847 };
12848 mc.add(someEl);
12849 mc.add(otherEl);
12850
12851 // or via the constructor
12852 var mc = new Roo.util.MixedCollection(false, function(el){
12853    return el.dom.id;
12854 });
12855 mc.add(someEl);
12856 mc.add(otherEl);
12857 </code></pre>
12858  * @param o {Object} The item for which to find the key.
12859  * @return {Object} The key for the passed item.
12860  */
12861     getKey : function(o){
12862          return o.id; 
12863     },
12864    
12865 /**
12866  * Replaces an item in the collection.
12867  * @param {String} key The key associated with the item to replace, or the item to replace.
12868  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12869  * @return {Object}  The new item.
12870  */
12871     replace : function(key, o){
12872         if(arguments.length == 1){
12873             o = arguments[0];
12874             key = this.getKey(o);
12875         }
12876         var old = this.item(key);
12877         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12878              return this.add(key, o);
12879         }
12880         var index = this.indexOfKey(key);
12881         this.items[index] = o;
12882         this.map[key] = o;
12883         this.fireEvent("replace", key, old, o);
12884         return o;
12885     },
12886    
12887 /**
12888  * Adds all elements of an Array or an Object to the collection.
12889  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12890  * an Array of values, each of which are added to the collection.
12891  */
12892     addAll : function(objs){
12893         if(arguments.length > 1 || objs instanceof Array){
12894             var args = arguments.length > 1 ? arguments : objs;
12895             for(var i = 0, len = args.length; i < len; i++){
12896                 this.add(args[i]);
12897             }
12898         }else{
12899             for(var key in objs){
12900                 if(this.allowFunctions || typeof objs[key] != "function"){
12901                     this.add(key, objs[key]);
12902                 }
12903             }
12904         }
12905     },
12906    
12907 /**
12908  * Executes the specified function once for every item in the collection, passing each
12909  * item as the first and only parameter. returning false from the function will stop the iteration.
12910  * @param {Function} fn The function to execute for each item.
12911  * @param {Object} scope (optional) The scope in which to execute the function.
12912  */
12913     each : function(fn, scope){
12914         var items = [].concat(this.items); // each safe for removal
12915         for(var i = 0, len = items.length; i < len; i++){
12916             if(fn.call(scope || items[i], items[i], i, len) === false){
12917                 break;
12918             }
12919         }
12920     },
12921    
12922 /**
12923  * Executes the specified function once for every key in the collection, passing each
12924  * key, and its associated item as the first two parameters.
12925  * @param {Function} fn The function to execute for each item.
12926  * @param {Object} scope (optional) The scope in which to execute the function.
12927  */
12928     eachKey : function(fn, scope){
12929         for(var i = 0, len = this.keys.length; i < len; i++){
12930             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12931         }
12932     },
12933    
12934 /**
12935  * Returns the first item in the collection which elicits a true return value from the
12936  * passed selection function.
12937  * @param {Function} fn The selection function to execute for each item.
12938  * @param {Object} scope (optional) The scope in which to execute the function.
12939  * @return {Object} The first item in the collection which returned true from the selection function.
12940  */
12941     find : function(fn, scope){
12942         for(var i = 0, len = this.items.length; i < len; i++){
12943             if(fn.call(scope || window, this.items[i], this.keys[i])){
12944                 return this.items[i];
12945             }
12946         }
12947         return null;
12948     },
12949    
12950 /**
12951  * Inserts an item at the specified index in the collection.
12952  * @param {Number} index The index to insert the item at.
12953  * @param {String} key The key to associate with the new item, or the item itself.
12954  * @param {Object} o  (optional) If the second parameter was a key, the new item.
12955  * @return {Object} The item inserted.
12956  */
12957     insert : function(index, key, o){
12958         if(arguments.length == 2){
12959             o = arguments[1];
12960             key = this.getKey(o);
12961         }
12962         if(index >= this.length){
12963             return this.add(key, o);
12964         }
12965         this.length++;
12966         this.items.splice(index, 0, o);
12967         if(typeof key != "undefined" && key != null){
12968             this.map[key] = o;
12969         }
12970         this.keys.splice(index, 0, key);
12971         this.fireEvent("add", index, o, key);
12972         return o;
12973     },
12974    
12975 /**
12976  * Removed an item from the collection.
12977  * @param {Object} o The item to remove.
12978  * @return {Object} The item removed.
12979  */
12980     remove : function(o){
12981         return this.removeAt(this.indexOf(o));
12982     },
12983    
12984 /**
12985  * Remove an item from a specified index in the collection.
12986  * @param {Number} index The index within the collection of the item to remove.
12987  */
12988     removeAt : function(index){
12989         if(index < this.length && index >= 0){
12990             this.length--;
12991             var o = this.items[index];
12992             this.items.splice(index, 1);
12993             var key = this.keys[index];
12994             if(typeof key != "undefined"){
12995                 delete this.map[key];
12996             }
12997             this.keys.splice(index, 1);
12998             this.fireEvent("remove", o, key);
12999         }
13000     },
13001    
13002 /**
13003  * Removed an item associated with the passed key fom the collection.
13004  * @param {String} key The key of the item to remove.
13005  */
13006     removeKey : function(key){
13007         return this.removeAt(this.indexOfKey(key));
13008     },
13009    
13010 /**
13011  * Returns the number of items in the collection.
13012  * @return {Number} the number of items in the collection.
13013  */
13014     getCount : function(){
13015         return this.length; 
13016     },
13017    
13018 /**
13019  * Returns index within the collection of the passed Object.
13020  * @param {Object} o The item to find the index of.
13021  * @return {Number} index of the item.
13022  */
13023     indexOf : function(o){
13024         if(!this.items.indexOf){
13025             for(var i = 0, len = this.items.length; i < len; i++){
13026                 if(this.items[i] == o) return i;
13027             }
13028             return -1;
13029         }else{
13030             return this.items.indexOf(o);
13031         }
13032     },
13033    
13034 /**
13035  * Returns index within the collection of the passed key.
13036  * @param {String} key The key to find the index of.
13037  * @return {Number} index of the key.
13038  */
13039     indexOfKey : function(key){
13040         if(!this.keys.indexOf){
13041             for(var i = 0, len = this.keys.length; i < len; i++){
13042                 if(this.keys[i] == key) return i;
13043             }
13044             return -1;
13045         }else{
13046             return this.keys.indexOf(key);
13047         }
13048     },
13049    
13050 /**
13051  * Returns the item associated with the passed key OR index. Key has priority over index.
13052  * @param {String/Number} key The key or index of the item.
13053  * @return {Object} The item associated with the passed key.
13054  */
13055     item : function(key){
13056         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13057         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13058     },
13059     
13060 /**
13061  * Returns the item at the specified index.
13062  * @param {Number} index The index of the item.
13063  * @return {Object}
13064  */
13065     itemAt : function(index){
13066         return this.items[index];
13067     },
13068     
13069 /**
13070  * Returns the item associated with the passed key.
13071  * @param {String/Number} key The key of the item.
13072  * @return {Object} The item associated with the passed key.
13073  */
13074     key : function(key){
13075         return this.map[key];
13076     },
13077    
13078 /**
13079  * Returns true if the collection contains the passed Object as an item.
13080  * @param {Object} o  The Object to look for in the collection.
13081  * @return {Boolean} True if the collection contains the Object as an item.
13082  */
13083     contains : function(o){
13084         return this.indexOf(o) != -1;
13085     },
13086    
13087 /**
13088  * Returns true if the collection contains the passed Object as a key.
13089  * @param {String} key The key to look for in the collection.
13090  * @return {Boolean} True if the collection contains the Object as a key.
13091  */
13092     containsKey : function(key){
13093         return typeof this.map[key] != "undefined";
13094     },
13095    
13096 /**
13097  * Removes all items from the collection.
13098  */
13099     clear : function(){
13100         this.length = 0;
13101         this.items = [];
13102         this.keys = [];
13103         this.map = {};
13104         this.fireEvent("clear");
13105     },
13106    
13107 /**
13108  * Returns the first item in the collection.
13109  * @return {Object} the first item in the collection..
13110  */
13111     first : function(){
13112         return this.items[0]; 
13113     },
13114    
13115 /**
13116  * Returns the last item in the collection.
13117  * @return {Object} the last item in the collection..
13118  */
13119     last : function(){
13120         return this.items[this.length-1];   
13121     },
13122     
13123     _sort : function(property, dir, fn){
13124         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13125         fn = fn || function(a, b){
13126             return a-b;
13127         };
13128         var c = [], k = this.keys, items = this.items;
13129         for(var i = 0, len = items.length; i < len; i++){
13130             c[c.length] = {key: k[i], value: items[i], index: i};
13131         }
13132         c.sort(function(a, b){
13133             var v = fn(a[property], b[property]) * dsc;
13134             if(v == 0){
13135                 v = (a.index < b.index ? -1 : 1);
13136             }
13137             return v;
13138         });
13139         for(var i = 0, len = c.length; i < len; i++){
13140             items[i] = c[i].value;
13141             k[i] = c[i].key;
13142         }
13143         this.fireEvent("sort", this);
13144     },
13145     
13146     /**
13147      * Sorts this collection with the passed comparison function
13148      * @param {String} direction (optional) "ASC" or "DESC"
13149      * @param {Function} fn (optional) comparison function
13150      */
13151     sort : function(dir, fn){
13152         this._sort("value", dir, fn);
13153     },
13154     
13155     /**
13156      * Sorts this collection by keys
13157      * @param {String} direction (optional) "ASC" or "DESC"
13158      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13159      */
13160     keySort : function(dir, fn){
13161         this._sort("key", dir, fn || function(a, b){
13162             return String(a).toUpperCase()-String(b).toUpperCase();
13163         });
13164     },
13165     
13166     /**
13167      * Returns a range of items in this collection
13168      * @param {Number} startIndex (optional) defaults to 0
13169      * @param {Number} endIndex (optional) default to the last item
13170      * @return {Array} An array of items
13171      */
13172     getRange : function(start, end){
13173         var items = this.items;
13174         if(items.length < 1){
13175             return [];
13176         }
13177         start = start || 0;
13178         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13179         var r = [];
13180         if(start <= end){
13181             for(var i = start; i <= end; i++) {
13182                     r[r.length] = items[i];
13183             }
13184         }else{
13185             for(var i = start; i >= end; i--) {
13186                     r[r.length] = items[i];
13187             }
13188         }
13189         return r;
13190     },
13191         
13192     /**
13193      * Filter the <i>objects</i> in this collection by a specific property. 
13194      * Returns a new collection that has been filtered.
13195      * @param {String} property A property on your objects
13196      * @param {String/RegExp} value Either string that the property values 
13197      * should start with or a RegExp to test against the property
13198      * @return {MixedCollection} The new filtered collection
13199      */
13200     filter : function(property, value){
13201         if(!value.exec){ // not a regex
13202             value = String(value);
13203             if(value.length == 0){
13204                 return this.clone();
13205             }
13206             value = new RegExp("^" + Roo.escapeRe(value), "i");
13207         }
13208         return this.filterBy(function(o){
13209             return o && value.test(o[property]);
13210         });
13211         },
13212     
13213     /**
13214      * Filter by a function. * Returns a new collection that has been filtered.
13215      * The passed function will be called with each 
13216      * object in the collection. If the function returns true, the value is included 
13217      * otherwise it is filtered.
13218      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13219      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13220      * @return {MixedCollection} The new filtered collection
13221      */
13222     filterBy : function(fn, scope){
13223         var r = new Roo.util.MixedCollection();
13224         r.getKey = this.getKey;
13225         var k = this.keys, it = this.items;
13226         for(var i = 0, len = it.length; i < len; i++){
13227             if(fn.call(scope||this, it[i], k[i])){
13228                                 r.add(k[i], it[i]);
13229                         }
13230         }
13231         return r;
13232     },
13233     
13234     /**
13235      * Creates a duplicate of this collection
13236      * @return {MixedCollection}
13237      */
13238     clone : function(){
13239         var r = new Roo.util.MixedCollection();
13240         var k = this.keys, it = this.items;
13241         for(var i = 0, len = it.length; i < len; i++){
13242             r.add(k[i], it[i]);
13243         }
13244         r.getKey = this.getKey;
13245         return r;
13246     }
13247 });
13248 /**
13249  * Returns the item associated with the passed key or index.
13250  * @method
13251  * @param {String/Number} key The key or index of the item.
13252  * @return {Object} The item associated with the passed key.
13253  */
13254 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13255  * Based on:
13256  * Ext JS Library 1.1.1
13257  * Copyright(c) 2006-2007, Ext JS, LLC.
13258  *
13259  * Originally Released Under LGPL - original licence link has changed is not relivant.
13260  *
13261  * Fork - LGPL
13262  * <script type="text/javascript">
13263  */
13264 /**
13265  * @class Roo.util.JSON
13266  * Modified version of Douglas Crockford"s json.js that doesn"t
13267  * mess with the Object prototype 
13268  * http://www.json.org/js.html
13269  * @singleton
13270  */
13271 Roo.util.JSON = new (function(){
13272     var useHasOwn = {}.hasOwnProperty ? true : false;
13273     
13274     // crashes Safari in some instances
13275     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13276     
13277     var pad = function(n) {
13278         return n < 10 ? "0" + n : n;
13279     };
13280     
13281     var m = {
13282         "\b": '\\b',
13283         "\t": '\\t',
13284         "\n": '\\n',
13285         "\f": '\\f',
13286         "\r": '\\r',
13287         '"' : '\\"',
13288         "\\": '\\\\'
13289     };
13290
13291     var encodeString = function(s){
13292         if (/["\\\x00-\x1f]/.test(s)) {
13293             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13294                 var c = m[b];
13295                 if(c){
13296                     return c;
13297                 }
13298                 c = b.charCodeAt();
13299                 return "\\u00" +
13300                     Math.floor(c / 16).toString(16) +
13301                     (c % 16).toString(16);
13302             }) + '"';
13303         }
13304         return '"' + s + '"';
13305     };
13306     
13307     var encodeArray = function(o){
13308         var a = ["["], b, i, l = o.length, v;
13309             for (i = 0; i < l; i += 1) {
13310                 v = o[i];
13311                 switch (typeof v) {
13312                     case "undefined":
13313                     case "function":
13314                     case "unknown":
13315                         break;
13316                     default:
13317                         if (b) {
13318                             a.push(',');
13319                         }
13320                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13321                         b = true;
13322                 }
13323             }
13324             a.push("]");
13325             return a.join("");
13326     };
13327     
13328     var encodeDate = function(o){
13329         return '"' + o.getFullYear() + "-" +
13330                 pad(o.getMonth() + 1) + "-" +
13331                 pad(o.getDate()) + "T" +
13332                 pad(o.getHours()) + ":" +
13333                 pad(o.getMinutes()) + ":" +
13334                 pad(o.getSeconds()) + '"';
13335     };
13336     
13337     /**
13338      * Encodes an Object, Array or other value
13339      * @param {Mixed} o The variable to encode
13340      * @return {String} The JSON string
13341      */
13342     this.encode = function(o)
13343     {
13344         // should this be extended to fully wrap stringify..
13345         
13346         if(typeof o == "undefined" || o === null){
13347             return "null";
13348         }else if(o instanceof Array){
13349             return encodeArray(o);
13350         }else if(o instanceof Date){
13351             return encodeDate(o);
13352         }else if(typeof o == "string"){
13353             return encodeString(o);
13354         }else if(typeof o == "number"){
13355             return isFinite(o) ? String(o) : "null";
13356         }else if(typeof o == "boolean"){
13357             return String(o);
13358         }else {
13359             var a = ["{"], b, i, v;
13360             for (i in o) {
13361                 if(!useHasOwn || o.hasOwnProperty(i)) {
13362                     v = o[i];
13363                     switch (typeof v) {
13364                     case "undefined":
13365                     case "function":
13366                     case "unknown":
13367                         break;
13368                     default:
13369                         if(b){
13370                             a.push(',');
13371                         }
13372                         a.push(this.encode(i), ":",
13373                                 v === null ? "null" : this.encode(v));
13374                         b = true;
13375                     }
13376                 }
13377             }
13378             a.push("}");
13379             return a.join("");
13380         }
13381     };
13382     
13383     /**
13384      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13385      * @param {String} json The JSON string
13386      * @return {Object} The resulting object
13387      */
13388     this.decode = function(json){
13389         
13390         return  /** eval:var:json */ eval("(" + json + ')');
13391     };
13392 })();
13393 /** 
13394  * Shorthand for {@link Roo.util.JSON#encode}
13395  * @member Roo encode 
13396  * @method */
13397 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13398 /** 
13399  * Shorthand for {@link Roo.util.JSON#decode}
13400  * @member Roo decode 
13401  * @method */
13402 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13403 /*
13404  * Based on:
13405  * Ext JS Library 1.1.1
13406  * Copyright(c) 2006-2007, Ext JS, LLC.
13407  *
13408  * Originally Released Under LGPL - original licence link has changed is not relivant.
13409  *
13410  * Fork - LGPL
13411  * <script type="text/javascript">
13412  */
13413  
13414 /**
13415  * @class Roo.util.Format
13416  * Reusable data formatting functions
13417  * @singleton
13418  */
13419 Roo.util.Format = function(){
13420     var trimRe = /^\s+|\s+$/g;
13421     return {
13422         /**
13423          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13424          * @param {String} value The string to truncate
13425          * @param {Number} length The maximum length to allow before truncating
13426          * @return {String} The converted text
13427          */
13428         ellipsis : function(value, len){
13429             if(value && value.length > len){
13430                 return value.substr(0, len-3)+"...";
13431             }
13432             return value;
13433         },
13434
13435         /**
13436          * Checks a reference and converts it to empty string if it is undefined
13437          * @param {Mixed} value Reference to check
13438          * @return {Mixed} Empty string if converted, otherwise the original value
13439          */
13440         undef : function(value){
13441             return typeof value != "undefined" ? value : "";
13442         },
13443
13444         /**
13445          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13446          * @param {String} value The string to encode
13447          * @return {String} The encoded text
13448          */
13449         htmlEncode : function(value){
13450             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13451         },
13452
13453         /**
13454          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13455          * @param {String} value The string to decode
13456          * @return {String} The decoded text
13457          */
13458         htmlDecode : function(value){
13459             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13460         },
13461
13462         /**
13463          * Trims any whitespace from either side of a string
13464          * @param {String} value The text to trim
13465          * @return {String} The trimmed text
13466          */
13467         trim : function(value){
13468             return String(value).replace(trimRe, "");
13469         },
13470
13471         /**
13472          * Returns a substring from within an original string
13473          * @param {String} value The original text
13474          * @param {Number} start The start index of the substring
13475          * @param {Number} length The length of the substring
13476          * @return {String} The substring
13477          */
13478         substr : function(value, start, length){
13479             return String(value).substr(start, length);
13480         },
13481
13482         /**
13483          * Converts a string to all lower case letters
13484          * @param {String} value The text to convert
13485          * @return {String} The converted text
13486          */
13487         lowercase : function(value){
13488             return String(value).toLowerCase();
13489         },
13490
13491         /**
13492          * Converts a string to all upper case letters
13493          * @param {String} value The text to convert
13494          * @return {String} The converted text
13495          */
13496         uppercase : function(value){
13497             return String(value).toUpperCase();
13498         },
13499
13500         /**
13501          * Converts the first character only of a string to upper case
13502          * @param {String} value The text to convert
13503          * @return {String} The converted text
13504          */
13505         capitalize : function(value){
13506             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13507         },
13508
13509         // private
13510         call : function(value, fn){
13511             if(arguments.length > 2){
13512                 var args = Array.prototype.slice.call(arguments, 2);
13513                 args.unshift(value);
13514                  
13515                 return /** eval:var:value */  eval(fn).apply(window, args);
13516             }else{
13517                 /** eval:var:value */
13518                 return /** eval:var:value */ eval(fn).call(window, value);
13519             }
13520         },
13521
13522        
13523         /**
13524          * safer version of Math.toFixed..??/
13525          * @param {Number/String} value The numeric value to format
13526          * @param {Number/String} value Decimal places 
13527          * @return {String} The formatted currency string
13528          */
13529         toFixed : function(v, n)
13530         {
13531             // why not use to fixed - precision is buggered???
13532             if (!n) {
13533                 return Math.round(v-0);
13534             }
13535             var fact = Math.pow(10,n+1);
13536             v = (Math.round((v-0)*fact))/fact;
13537             var z = (''+fact).substring(2);
13538             if (v == Math.floor(v)) {
13539                 return Math.floor(v) + '.' + z;
13540             }
13541             
13542             // now just padd decimals..
13543             var ps = String(v).split('.');
13544             var fd = (ps[1] + z);
13545             var r = fd.substring(0,n); 
13546             var rm = fd.substring(n); 
13547             if (rm < 5) {
13548                 return ps[0] + '.' + r;
13549             }
13550             r*=1; // turn it into a number;
13551             r++;
13552             if (String(r).length != n) {
13553                 ps[0]*=1;
13554                 ps[0]++;
13555                 r = String(r).substring(1); // chop the end off.
13556             }
13557             
13558             return ps[0] + '.' + r;
13559              
13560         },
13561         
13562         /**
13563          * Format a number as US currency
13564          * @param {Number/String} value The numeric value to format
13565          * @return {String} The formatted currency string
13566          */
13567         usMoney : function(v){
13568             return '$' + Roo.util.Format.number(v);
13569         },
13570         
13571         /**
13572          * Format a number
13573          * eventually this should probably emulate php's number_format
13574          * @param {Number/String} value The numeric value to format
13575          * @param {Number} decimals number of decimal places
13576          * @return {String} The formatted currency string
13577          */
13578         number : function(v,decimals)
13579         {
13580             // multiply and round.
13581             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13582             var mul = Math.pow(10, decimals);
13583             var zero = String(mul).substring(1);
13584             v = (Math.round((v-0)*mul))/mul;
13585             
13586             // if it's '0' number.. then
13587             
13588             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13589             v = String(v);
13590             var ps = v.split('.');
13591             var whole = ps[0];
13592             
13593             
13594             var r = /(\d+)(\d{3})/;
13595             // add comma's
13596             while (r.test(whole)) {
13597                 whole = whole.replace(r, '$1' + ',' + '$2');
13598             }
13599             
13600             
13601             var sub = ps[1] ?
13602                     // has decimals..
13603                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13604                     // does not have decimals
13605                     (decimals ? ('.' + zero) : '');
13606             
13607             
13608             return whole + sub ;
13609         },
13610         
13611         /**
13612          * Parse a value into a formatted date using the specified format pattern.
13613          * @param {Mixed} value The value to format
13614          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13615          * @return {String} The formatted date string
13616          */
13617         date : function(v, format){
13618             if(!v){
13619                 return "";
13620             }
13621             if(!(v instanceof Date)){
13622                 v = new Date(Date.parse(v));
13623             }
13624             return v.dateFormat(format || Roo.util.Format.defaults.date);
13625         },
13626
13627         /**
13628          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13629          * @param {String} format Any valid date format string
13630          * @return {Function} The date formatting function
13631          */
13632         dateRenderer : function(format){
13633             return function(v){
13634                 return Roo.util.Format.date(v, format);  
13635             };
13636         },
13637
13638         // private
13639         stripTagsRE : /<\/?[^>]+>/gi,
13640         
13641         /**
13642          * Strips all HTML tags
13643          * @param {Mixed} value The text from which to strip tags
13644          * @return {String} The stripped text
13645          */
13646         stripTags : function(v){
13647             return !v ? v : String(v).replace(this.stripTagsRE, "");
13648         }
13649     };
13650 }();
13651 Roo.util.Format.defaults = {
13652     date : 'd/M/Y'
13653 };/*
13654  * Based on:
13655  * Ext JS Library 1.1.1
13656  * Copyright(c) 2006-2007, Ext JS, LLC.
13657  *
13658  * Originally Released Under LGPL - original licence link has changed is not relivant.
13659  *
13660  * Fork - LGPL
13661  * <script type="text/javascript">
13662  */
13663
13664
13665  
13666
13667 /**
13668  * @class Roo.MasterTemplate
13669  * @extends Roo.Template
13670  * Provides a template that can have child templates. The syntax is:
13671 <pre><code>
13672 var t = new Roo.MasterTemplate(
13673         '&lt;select name="{name}"&gt;',
13674                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13675         '&lt;/select&gt;'
13676 );
13677 t.add('options', {value: 'foo', text: 'bar'});
13678 // or you can add multiple child elements in one shot
13679 t.addAll('options', [
13680     {value: 'foo', text: 'bar'},
13681     {value: 'foo2', text: 'bar2'},
13682     {value: 'foo3', text: 'bar3'}
13683 ]);
13684 // then append, applying the master template values
13685 t.append('my-form', {name: 'my-select'});
13686 </code></pre>
13687 * A name attribute for the child template is not required if you have only one child
13688 * template or you want to refer to them by index.
13689  */
13690 Roo.MasterTemplate = function(){
13691     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13692     this.originalHtml = this.html;
13693     var st = {};
13694     var m, re = this.subTemplateRe;
13695     re.lastIndex = 0;
13696     var subIndex = 0;
13697     while(m = re.exec(this.html)){
13698         var name = m[1], content = m[2];
13699         st[subIndex] = {
13700             name: name,
13701             index: subIndex,
13702             buffer: [],
13703             tpl : new Roo.Template(content)
13704         };
13705         if(name){
13706             st[name] = st[subIndex];
13707         }
13708         st[subIndex].tpl.compile();
13709         st[subIndex].tpl.call = this.call.createDelegate(this);
13710         subIndex++;
13711     }
13712     this.subCount = subIndex;
13713     this.subs = st;
13714 };
13715 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13716     /**
13717     * The regular expression used to match sub templates
13718     * @type RegExp
13719     * @property
13720     */
13721     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13722
13723     /**
13724      * Applies the passed values to a child template.
13725      * @param {String/Number} name (optional) The name or index of the child template
13726      * @param {Array/Object} values The values to be applied to the template
13727      * @return {MasterTemplate} this
13728      */
13729      add : function(name, values){
13730         if(arguments.length == 1){
13731             values = arguments[0];
13732             name = 0;
13733         }
13734         var s = this.subs[name];
13735         s.buffer[s.buffer.length] = s.tpl.apply(values);
13736         return this;
13737     },
13738
13739     /**
13740      * Applies all the passed values to a child template.
13741      * @param {String/Number} name (optional) The name or index of the child template
13742      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13743      * @param {Boolean} reset (optional) True to reset the template first
13744      * @return {MasterTemplate} this
13745      */
13746     fill : function(name, values, reset){
13747         var a = arguments;
13748         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13749             values = a[0];
13750             name = 0;
13751             reset = a[1];
13752         }
13753         if(reset){
13754             this.reset();
13755         }
13756         for(var i = 0, len = values.length; i < len; i++){
13757             this.add(name, values[i]);
13758         }
13759         return this;
13760     },
13761
13762     /**
13763      * Resets the template for reuse
13764      * @return {MasterTemplate} this
13765      */
13766      reset : function(){
13767         var s = this.subs;
13768         for(var i = 0; i < this.subCount; i++){
13769             s[i].buffer = [];
13770         }
13771         return this;
13772     },
13773
13774     applyTemplate : function(values){
13775         var s = this.subs;
13776         var replaceIndex = -1;
13777         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13778             return s[++replaceIndex].buffer.join("");
13779         });
13780         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13781     },
13782
13783     apply : function(){
13784         return this.applyTemplate.apply(this, arguments);
13785     },
13786
13787     compile : function(){return this;}
13788 });
13789
13790 /**
13791  * Alias for fill().
13792  * @method
13793  */
13794 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13795  /**
13796  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13797  * var tpl = Roo.MasterTemplate.from('element-id');
13798  * @param {String/HTMLElement} el
13799  * @param {Object} config
13800  * @static
13801  */
13802 Roo.MasterTemplate.from = function(el, config){
13803     el = Roo.getDom(el);
13804     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13805 };/*
13806  * Based on:
13807  * Ext JS Library 1.1.1
13808  * Copyright(c) 2006-2007, Ext JS, LLC.
13809  *
13810  * Originally Released Under LGPL - original licence link has changed is not relivant.
13811  *
13812  * Fork - LGPL
13813  * <script type="text/javascript">
13814  */
13815
13816  
13817 /**
13818  * @class Roo.util.CSS
13819  * Utility class for manipulating CSS rules
13820  * @singleton
13821  */
13822 Roo.util.CSS = function(){
13823         var rules = null;
13824         var doc = document;
13825
13826     var camelRe = /(-[a-z])/gi;
13827     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13828
13829    return {
13830    /**
13831     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13832     * tag and appended to the HEAD of the document.
13833     * @param {String|Object} cssText The text containing the css rules
13834     * @param {String} id An id to add to the stylesheet for later removal
13835     * @return {StyleSheet}
13836     */
13837     createStyleSheet : function(cssText, id){
13838         var ss;
13839         var head = doc.getElementsByTagName("head")[0];
13840         var nrules = doc.createElement("style");
13841         nrules.setAttribute("type", "text/css");
13842         if(id){
13843             nrules.setAttribute("id", id);
13844         }
13845         if (typeof(cssText) != 'string') {
13846             // support object maps..
13847             // not sure if this a good idea.. 
13848             // perhaps it should be merged with the general css handling
13849             // and handle js style props.
13850             var cssTextNew = [];
13851             for(var n in cssText) {
13852                 var citems = [];
13853                 for(var k in cssText[n]) {
13854                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13855                 }
13856                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13857                 
13858             }
13859             cssText = cssTextNew.join("\n");
13860             
13861         }
13862        
13863        
13864        if(Roo.isIE){
13865            head.appendChild(nrules);
13866            ss = nrules.styleSheet;
13867            ss.cssText = cssText;
13868        }else{
13869            try{
13870                 nrules.appendChild(doc.createTextNode(cssText));
13871            }catch(e){
13872                nrules.cssText = cssText; 
13873            }
13874            head.appendChild(nrules);
13875            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13876        }
13877        this.cacheStyleSheet(ss);
13878        return ss;
13879    },
13880
13881    /**
13882     * Removes a style or link tag by id
13883     * @param {String} id The id of the tag
13884     */
13885    removeStyleSheet : function(id){
13886        var existing = doc.getElementById(id);
13887        if(existing){
13888            existing.parentNode.removeChild(existing);
13889        }
13890    },
13891
13892    /**
13893     * Dynamically swaps an existing stylesheet reference for a new one
13894     * @param {String} id The id of an existing link tag to remove
13895     * @param {String} url The href of the new stylesheet to include
13896     */
13897    swapStyleSheet : function(id, url){
13898        this.removeStyleSheet(id);
13899        var ss = doc.createElement("link");
13900        ss.setAttribute("rel", "stylesheet");
13901        ss.setAttribute("type", "text/css");
13902        ss.setAttribute("id", id);
13903        ss.setAttribute("href", url);
13904        doc.getElementsByTagName("head")[0].appendChild(ss);
13905    },
13906    
13907    /**
13908     * Refresh the rule cache if you have dynamically added stylesheets
13909     * @return {Object} An object (hash) of rules indexed by selector
13910     */
13911    refreshCache : function(){
13912        return this.getRules(true);
13913    },
13914
13915    // private
13916    cacheStyleSheet : function(stylesheet){
13917        if(!rules){
13918            rules = {};
13919        }
13920        try{// try catch for cross domain access issue
13921            var ssRules = stylesheet.cssRules || stylesheet.rules;
13922            for(var j = ssRules.length-1; j >= 0; --j){
13923                rules[ssRules[j].selectorText] = ssRules[j];
13924            }
13925        }catch(e){}
13926    },
13927    
13928    /**
13929     * Gets all css rules for the document
13930     * @param {Boolean} refreshCache true to refresh the internal cache
13931     * @return {Object} An object (hash) of rules indexed by selector
13932     */
13933    getRules : function(refreshCache){
13934                 if(rules == null || refreshCache){
13935                         rules = {};
13936                         var ds = doc.styleSheets;
13937                         for(var i =0, len = ds.length; i < len; i++){
13938                             try{
13939                         this.cacheStyleSheet(ds[i]);
13940                     }catch(e){} 
13941                 }
13942                 }
13943                 return rules;
13944         },
13945         
13946         /**
13947     * Gets an an individual CSS rule by selector(s)
13948     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13949     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13950     * @return {CSSRule} The CSS rule or null if one is not found
13951     */
13952    getRule : function(selector, refreshCache){
13953                 var rs = this.getRules(refreshCache);
13954                 if(!(selector instanceof Array)){
13955                     return rs[selector];
13956                 }
13957                 for(var i = 0; i < selector.length; i++){
13958                         if(rs[selector[i]]){
13959                                 return rs[selector[i]];
13960                         }
13961                 }
13962                 return null;
13963         },
13964         
13965         
13966         /**
13967     * Updates a rule property
13968     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
13969     * @param {String} property The css property
13970     * @param {String} value The new value for the property
13971     * @return {Boolean} true If a rule was found and updated
13972     */
13973    updateRule : function(selector, property, value){
13974                 if(!(selector instanceof Array)){
13975                         var rule = this.getRule(selector);
13976                         if(rule){
13977                                 rule.style[property.replace(camelRe, camelFn)] = value;
13978                                 return true;
13979                         }
13980                 }else{
13981                         for(var i = 0; i < selector.length; i++){
13982                                 if(this.updateRule(selector[i], property, value)){
13983                                         return true;
13984                                 }
13985                         }
13986                 }
13987                 return false;
13988         }
13989    };   
13990 }();/*
13991  * Based on:
13992  * Ext JS Library 1.1.1
13993  * Copyright(c) 2006-2007, Ext JS, LLC.
13994  *
13995  * Originally Released Under LGPL - original licence link has changed is not relivant.
13996  *
13997  * Fork - LGPL
13998  * <script type="text/javascript">
13999  */
14000
14001  
14002
14003 /**
14004  * @class Roo.util.ClickRepeater
14005  * @extends Roo.util.Observable
14006  * 
14007  * A wrapper class which can be applied to any element. Fires a "click" event while the
14008  * mouse is pressed. The interval between firings may be specified in the config but
14009  * defaults to 10 milliseconds.
14010  * 
14011  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14012  * 
14013  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14014  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14015  * Similar to an autorepeat key delay.
14016  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14017  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14018  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14019  *           "interval" and "delay" are ignored. "immediate" is honored.
14020  * @cfg {Boolean} preventDefault True to prevent the default click event
14021  * @cfg {Boolean} stopDefault True to stop the default click event
14022  * 
14023  * @history
14024  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14025  *     2007-02-02 jvs Renamed to ClickRepeater
14026  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14027  *
14028  *  @constructor
14029  * @param {String/HTMLElement/Element} el The element to listen on
14030  * @param {Object} config
14031  **/
14032 Roo.util.ClickRepeater = function(el, config)
14033 {
14034     this.el = Roo.get(el);
14035     this.el.unselectable();
14036
14037     Roo.apply(this, config);
14038
14039     this.addEvents({
14040     /**
14041      * @event mousedown
14042      * Fires when the mouse button is depressed.
14043      * @param {Roo.util.ClickRepeater} this
14044      */
14045         "mousedown" : true,
14046     /**
14047      * @event click
14048      * Fires on a specified interval during the time the element is pressed.
14049      * @param {Roo.util.ClickRepeater} this
14050      */
14051         "click" : true,
14052     /**
14053      * @event mouseup
14054      * Fires when the mouse key is released.
14055      * @param {Roo.util.ClickRepeater} this
14056      */
14057         "mouseup" : true
14058     });
14059
14060     this.el.on("mousedown", this.handleMouseDown, this);
14061     if(this.preventDefault || this.stopDefault){
14062         this.el.on("click", function(e){
14063             if(this.preventDefault){
14064                 e.preventDefault();
14065             }
14066             if(this.stopDefault){
14067                 e.stopEvent();
14068             }
14069         }, this);
14070     }
14071
14072     // allow inline handler
14073     if(this.handler){
14074         this.on("click", this.handler,  this.scope || this);
14075     }
14076
14077     Roo.util.ClickRepeater.superclass.constructor.call(this);
14078 };
14079
14080 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14081     interval : 20,
14082     delay: 250,
14083     preventDefault : true,
14084     stopDefault : false,
14085     timer : 0,
14086
14087     // private
14088     handleMouseDown : function(){
14089         clearTimeout(this.timer);
14090         this.el.blur();
14091         if(this.pressClass){
14092             this.el.addClass(this.pressClass);
14093         }
14094         this.mousedownTime = new Date();
14095
14096         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14097         this.el.on("mouseout", this.handleMouseOut, this);
14098
14099         this.fireEvent("mousedown", this);
14100         this.fireEvent("click", this);
14101         
14102         this.timer = this.click.defer(this.delay || this.interval, this);
14103     },
14104
14105     // private
14106     click : function(){
14107         this.fireEvent("click", this);
14108         this.timer = this.click.defer(this.getInterval(), this);
14109     },
14110
14111     // private
14112     getInterval: function(){
14113         if(!this.accelerate){
14114             return this.interval;
14115         }
14116         var pressTime = this.mousedownTime.getElapsed();
14117         if(pressTime < 500){
14118             return 400;
14119         }else if(pressTime < 1700){
14120             return 320;
14121         }else if(pressTime < 2600){
14122             return 250;
14123         }else if(pressTime < 3500){
14124             return 180;
14125         }else if(pressTime < 4400){
14126             return 140;
14127         }else if(pressTime < 5300){
14128             return 80;
14129         }else if(pressTime < 6200){
14130             return 50;
14131         }else{
14132             return 10;
14133         }
14134     },
14135
14136     // private
14137     handleMouseOut : function(){
14138         clearTimeout(this.timer);
14139         if(this.pressClass){
14140             this.el.removeClass(this.pressClass);
14141         }
14142         this.el.on("mouseover", this.handleMouseReturn, this);
14143     },
14144
14145     // private
14146     handleMouseReturn : function(){
14147         this.el.un("mouseover", this.handleMouseReturn);
14148         if(this.pressClass){
14149             this.el.addClass(this.pressClass);
14150         }
14151         this.click();
14152     },
14153
14154     // private
14155     handleMouseUp : function(){
14156         clearTimeout(this.timer);
14157         this.el.un("mouseover", this.handleMouseReturn);
14158         this.el.un("mouseout", this.handleMouseOut);
14159         Roo.get(document).un("mouseup", this.handleMouseUp);
14160         this.el.removeClass(this.pressClass);
14161         this.fireEvent("mouseup", this);
14162     }
14163 });/*
14164  * Based on:
14165  * Ext JS Library 1.1.1
14166  * Copyright(c) 2006-2007, Ext JS, LLC.
14167  *
14168  * Originally Released Under LGPL - original licence link has changed is not relivant.
14169  *
14170  * Fork - LGPL
14171  * <script type="text/javascript">
14172  */
14173
14174  
14175 /**
14176  * @class Roo.KeyNav
14177  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14178  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14179  * way to implement custom navigation schemes for any UI component.</p>
14180  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14181  * pageUp, pageDown, del, home, end.  Usage:</p>
14182  <pre><code>
14183 var nav = new Roo.KeyNav("my-element", {
14184     "left" : function(e){
14185         this.moveLeft(e.ctrlKey);
14186     },
14187     "right" : function(e){
14188         this.moveRight(e.ctrlKey);
14189     },
14190     "enter" : function(e){
14191         this.save();
14192     },
14193     scope : this
14194 });
14195 </code></pre>
14196  * @constructor
14197  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14198  * @param {Object} config The config
14199  */
14200 Roo.KeyNav = function(el, config){
14201     this.el = Roo.get(el);
14202     Roo.apply(this, config);
14203     if(!this.disabled){
14204         this.disabled = true;
14205         this.enable();
14206     }
14207 };
14208
14209 Roo.KeyNav.prototype = {
14210     /**
14211      * @cfg {Boolean} disabled
14212      * True to disable this KeyNav instance (defaults to false)
14213      */
14214     disabled : false,
14215     /**
14216      * @cfg {String} defaultEventAction
14217      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14218      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14219      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14220      */
14221     defaultEventAction: "stopEvent",
14222     /**
14223      * @cfg {Boolean} forceKeyDown
14224      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14225      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14226      * handle keydown instead of keypress.
14227      */
14228     forceKeyDown : false,
14229
14230     // private
14231     prepareEvent : function(e){
14232         var k = e.getKey();
14233         var h = this.keyToHandler[k];
14234         //if(h && this[h]){
14235         //    e.stopPropagation();
14236         //}
14237         if(Roo.isSafari && h && k >= 37 && k <= 40){
14238             e.stopEvent();
14239         }
14240     },
14241
14242     // private
14243     relay : function(e){
14244         var k = e.getKey();
14245         var h = this.keyToHandler[k];
14246         if(h && this[h]){
14247             if(this.doRelay(e, this[h], h) !== true){
14248                 e[this.defaultEventAction]();
14249             }
14250         }
14251     },
14252
14253     // private
14254     doRelay : function(e, h, hname){
14255         return h.call(this.scope || this, e);
14256     },
14257
14258     // possible handlers
14259     enter : false,
14260     left : false,
14261     right : false,
14262     up : false,
14263     down : false,
14264     tab : false,
14265     esc : false,
14266     pageUp : false,
14267     pageDown : false,
14268     del : false,
14269     home : false,
14270     end : false,
14271
14272     // quick lookup hash
14273     keyToHandler : {
14274         37 : "left",
14275         39 : "right",
14276         38 : "up",
14277         40 : "down",
14278         33 : "pageUp",
14279         34 : "pageDown",
14280         46 : "del",
14281         36 : "home",
14282         35 : "end",
14283         13 : "enter",
14284         27 : "esc",
14285         9  : "tab"
14286     },
14287
14288         /**
14289          * Enable this KeyNav
14290          */
14291         enable: function(){
14292                 if(this.disabled){
14293             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14294             // the EventObject will normalize Safari automatically
14295             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14296                 this.el.on("keydown", this.relay,  this);
14297             }else{
14298                 this.el.on("keydown", this.prepareEvent,  this);
14299                 this.el.on("keypress", this.relay,  this);
14300             }
14301                     this.disabled = false;
14302                 }
14303         },
14304
14305         /**
14306          * Disable this KeyNav
14307          */
14308         disable: function(){
14309                 if(!this.disabled){
14310                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14311                 this.el.un("keydown", this.relay);
14312             }else{
14313                 this.el.un("keydown", this.prepareEvent);
14314                 this.el.un("keypress", this.relay);
14315             }
14316                     this.disabled = true;
14317                 }
14318         }
14319 };/*
14320  * Based on:
14321  * Ext JS Library 1.1.1
14322  * Copyright(c) 2006-2007, Ext JS, LLC.
14323  *
14324  * Originally Released Under LGPL - original licence link has changed is not relivant.
14325  *
14326  * Fork - LGPL
14327  * <script type="text/javascript">
14328  */
14329
14330  
14331 /**
14332  * @class Roo.KeyMap
14333  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14334  * The constructor accepts the same config object as defined by {@link #addBinding}.
14335  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14336  * combination it will call the function with this signature (if the match is a multi-key
14337  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14338  * A KeyMap can also handle a string representation of keys.<br />
14339  * Usage:
14340  <pre><code>
14341 // map one key by key code
14342 var map = new Roo.KeyMap("my-element", {
14343     key: 13, // or Roo.EventObject.ENTER
14344     fn: myHandler,
14345     scope: myObject
14346 });
14347
14348 // map multiple keys to one action by string
14349 var map = new Roo.KeyMap("my-element", {
14350     key: "a\r\n\t",
14351     fn: myHandler,
14352     scope: myObject
14353 });
14354
14355 // map multiple keys to multiple actions by strings and array of codes
14356 var map = new Roo.KeyMap("my-element", [
14357     {
14358         key: [10,13],
14359         fn: function(){ alert("Return was pressed"); }
14360     }, {
14361         key: "abc",
14362         fn: function(){ alert('a, b or c was pressed'); }
14363     }, {
14364         key: "\t",
14365         ctrl:true,
14366         shift:true,
14367         fn: function(){ alert('Control + shift + tab was pressed.'); }
14368     }
14369 ]);
14370 </code></pre>
14371  * <b>Note: A KeyMap starts enabled</b>
14372  * @constructor
14373  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14374  * @param {Object} config The config (see {@link #addBinding})
14375  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14376  */
14377 Roo.KeyMap = function(el, config, eventName){
14378     this.el  = Roo.get(el);
14379     this.eventName = eventName || "keydown";
14380     this.bindings = [];
14381     if(config){
14382         this.addBinding(config);
14383     }
14384     this.enable();
14385 };
14386
14387 Roo.KeyMap.prototype = {
14388     /**
14389      * True to stop the event from bubbling and prevent the default browser action if the
14390      * key was handled by the KeyMap (defaults to false)
14391      * @type Boolean
14392      */
14393     stopEvent : false,
14394
14395     /**
14396      * Add a new binding to this KeyMap. The following config object properties are supported:
14397      * <pre>
14398 Property    Type             Description
14399 ----------  ---------------  ----------------------------------------------------------------------
14400 key         String/Array     A single keycode or an array of keycodes to handle
14401 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14402 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14403 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14404 fn          Function         The function to call when KeyMap finds the expected key combination
14405 scope       Object           The scope of the callback function
14406 </pre>
14407      *
14408      * Usage:
14409      * <pre><code>
14410 // Create a KeyMap
14411 var map = new Roo.KeyMap(document, {
14412     key: Roo.EventObject.ENTER,
14413     fn: handleKey,
14414     scope: this
14415 });
14416
14417 //Add a new binding to the existing KeyMap later
14418 map.addBinding({
14419     key: 'abc',
14420     shift: true,
14421     fn: handleKey,
14422     scope: this
14423 });
14424 </code></pre>
14425      * @param {Object/Array} config A single KeyMap config or an array of configs
14426      */
14427         addBinding : function(config){
14428         if(config instanceof Array){
14429             for(var i = 0, len = config.length; i < len; i++){
14430                 this.addBinding(config[i]);
14431             }
14432             return;
14433         }
14434         var keyCode = config.key,
14435             shift = config.shift, 
14436             ctrl = config.ctrl, 
14437             alt = config.alt,
14438             fn = config.fn,
14439             scope = config.scope;
14440         if(typeof keyCode == "string"){
14441             var ks = [];
14442             var keyString = keyCode.toUpperCase();
14443             for(var j = 0, len = keyString.length; j < len; j++){
14444                 ks.push(keyString.charCodeAt(j));
14445             }
14446             keyCode = ks;
14447         }
14448         var keyArray = keyCode instanceof Array;
14449         var handler = function(e){
14450             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14451                 var k = e.getKey();
14452                 if(keyArray){
14453                     for(var i = 0, len = keyCode.length; i < len; i++){
14454                         if(keyCode[i] == k){
14455                           if(this.stopEvent){
14456                               e.stopEvent();
14457                           }
14458                           fn.call(scope || window, k, e);
14459                           return;
14460                         }
14461                     }
14462                 }else{
14463                     if(k == keyCode){
14464                         if(this.stopEvent){
14465                            e.stopEvent();
14466                         }
14467                         fn.call(scope || window, k, e);
14468                     }
14469                 }
14470             }
14471         };
14472         this.bindings.push(handler);  
14473         },
14474
14475     /**
14476      * Shorthand for adding a single key listener
14477      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14478      * following options:
14479      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14480      * @param {Function} fn The function to call
14481      * @param {Object} scope (optional) The scope of the function
14482      */
14483     on : function(key, fn, scope){
14484         var keyCode, shift, ctrl, alt;
14485         if(typeof key == "object" && !(key instanceof Array)){
14486             keyCode = key.key;
14487             shift = key.shift;
14488             ctrl = key.ctrl;
14489             alt = key.alt;
14490         }else{
14491             keyCode = key;
14492         }
14493         this.addBinding({
14494             key: keyCode,
14495             shift: shift,
14496             ctrl: ctrl,
14497             alt: alt,
14498             fn: fn,
14499             scope: scope
14500         })
14501     },
14502
14503     // private
14504     handleKeyDown : function(e){
14505             if(this.enabled){ //just in case
14506             var b = this.bindings;
14507             for(var i = 0, len = b.length; i < len; i++){
14508                 b[i].call(this, e);
14509             }
14510             }
14511         },
14512         
14513         /**
14514          * Returns true if this KeyMap is enabled
14515          * @return {Boolean} 
14516          */
14517         isEnabled : function(){
14518             return this.enabled;  
14519         },
14520         
14521         /**
14522          * Enables this KeyMap
14523          */
14524         enable: function(){
14525                 if(!this.enabled){
14526                     this.el.on(this.eventName, this.handleKeyDown, this);
14527                     this.enabled = true;
14528                 }
14529         },
14530
14531         /**
14532          * Disable this KeyMap
14533          */
14534         disable: function(){
14535                 if(this.enabled){
14536                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14537                     this.enabled = false;
14538                 }
14539         }
14540 };/*
14541  * Based on:
14542  * Ext JS Library 1.1.1
14543  * Copyright(c) 2006-2007, Ext JS, LLC.
14544  *
14545  * Originally Released Under LGPL - original licence link has changed is not relivant.
14546  *
14547  * Fork - LGPL
14548  * <script type="text/javascript">
14549  */
14550
14551  
14552 /**
14553  * @class Roo.util.TextMetrics
14554  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14555  * wide, in pixels, a given block of text will be.
14556  * @singleton
14557  */
14558 Roo.util.TextMetrics = function(){
14559     var shared;
14560     return {
14561         /**
14562          * Measures the size of the specified text
14563          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14564          * that can affect the size of the rendered text
14565          * @param {String} text The text to measure
14566          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14567          * in order to accurately measure the text height
14568          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14569          */
14570         measure : function(el, text, fixedWidth){
14571             if(!shared){
14572                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14573             }
14574             shared.bind(el);
14575             shared.setFixedWidth(fixedWidth || 'auto');
14576             return shared.getSize(text);
14577         },
14578
14579         /**
14580          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14581          * the overhead of multiple calls to initialize the style properties on each measurement.
14582          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14583          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14584          * in order to accurately measure the text height
14585          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14586          */
14587         createInstance : function(el, fixedWidth){
14588             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14589         }
14590     };
14591 }();
14592
14593  
14594
14595 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14596     var ml = new Roo.Element(document.createElement('div'));
14597     document.body.appendChild(ml.dom);
14598     ml.position('absolute');
14599     ml.setLeftTop(-1000, -1000);
14600     ml.hide();
14601
14602     if(fixedWidth){
14603         ml.setWidth(fixedWidth);
14604     }
14605      
14606     var instance = {
14607         /**
14608          * Returns the size of the specified text based on the internal element's style and width properties
14609          * @memberOf Roo.util.TextMetrics.Instance#
14610          * @param {String} text The text to measure
14611          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14612          */
14613         getSize : function(text){
14614             ml.update(text);
14615             var s = ml.getSize();
14616             ml.update('');
14617             return s;
14618         },
14619
14620         /**
14621          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14622          * that can affect the size of the rendered text
14623          * @memberOf Roo.util.TextMetrics.Instance#
14624          * @param {String/HTMLElement} el The element, dom node or id
14625          */
14626         bind : function(el){
14627             ml.setStyle(
14628                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14629             );
14630         },
14631
14632         /**
14633          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14634          * to set a fixed width in order to accurately measure the text height.
14635          * @memberOf Roo.util.TextMetrics.Instance#
14636          * @param {Number} width The width to set on the element
14637          */
14638         setFixedWidth : function(width){
14639             ml.setWidth(width);
14640         },
14641
14642         /**
14643          * Returns the measured width of the specified text
14644          * @memberOf Roo.util.TextMetrics.Instance#
14645          * @param {String} text The text to measure
14646          * @return {Number} width The width in pixels
14647          */
14648         getWidth : function(text){
14649             ml.dom.style.width = 'auto';
14650             return this.getSize(text).width;
14651         },
14652
14653         /**
14654          * Returns the measured height of the specified text.  For multiline text, be sure to call
14655          * {@link #setFixedWidth} if necessary.
14656          * @memberOf Roo.util.TextMetrics.Instance#
14657          * @param {String} text The text to measure
14658          * @return {Number} height The height in pixels
14659          */
14660         getHeight : function(text){
14661             return this.getSize(text).height;
14662         }
14663     };
14664
14665     instance.bind(bindTo);
14666
14667     return instance;
14668 };
14669
14670 // backwards compat
14671 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14672  * Based on:
14673  * Ext JS Library 1.1.1
14674  * Copyright(c) 2006-2007, Ext JS, LLC.
14675  *
14676  * Originally Released Under LGPL - original licence link has changed is not relivant.
14677  *
14678  * Fork - LGPL
14679  * <script type="text/javascript">
14680  */
14681
14682 /**
14683  * @class Roo.state.Provider
14684  * Abstract base class for state provider implementations. This class provides methods
14685  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14686  * Provider interface.
14687  */
14688 Roo.state.Provider = function(){
14689     /**
14690      * @event statechange
14691      * Fires when a state change occurs.
14692      * @param {Provider} this This state provider
14693      * @param {String} key The state key which was changed
14694      * @param {String} value The encoded value for the state
14695      */
14696     this.addEvents({
14697         "statechange": true
14698     });
14699     this.state = {};
14700     Roo.state.Provider.superclass.constructor.call(this);
14701 };
14702 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14703     /**
14704      * Returns the current value for a key
14705      * @param {String} name The key name
14706      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14707      * @return {Mixed} The state data
14708      */
14709     get : function(name, defaultValue){
14710         return typeof this.state[name] == "undefined" ?
14711             defaultValue : this.state[name];
14712     },
14713     
14714     /**
14715      * Clears a value from the state
14716      * @param {String} name The key name
14717      */
14718     clear : function(name){
14719         delete this.state[name];
14720         this.fireEvent("statechange", this, name, null);
14721     },
14722     
14723     /**
14724      * Sets the value for a key
14725      * @param {String} name The key name
14726      * @param {Mixed} value The value to set
14727      */
14728     set : function(name, value){
14729         this.state[name] = value;
14730         this.fireEvent("statechange", this, name, value);
14731     },
14732     
14733     /**
14734      * Decodes a string previously encoded with {@link #encodeValue}.
14735      * @param {String} value The value to decode
14736      * @return {Mixed} The decoded value
14737      */
14738     decodeValue : function(cookie){
14739         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14740         var matches = re.exec(unescape(cookie));
14741         if(!matches || !matches[1]) return; // non state cookie
14742         var type = matches[1];
14743         var v = matches[2];
14744         switch(type){
14745             case "n":
14746                 return parseFloat(v);
14747             case "d":
14748                 return new Date(Date.parse(v));
14749             case "b":
14750                 return (v == "1");
14751             case "a":
14752                 var all = [];
14753                 var values = v.split("^");
14754                 for(var i = 0, len = values.length; i < len; i++){
14755                     all.push(this.decodeValue(values[i]));
14756                 }
14757                 return all;
14758            case "o":
14759                 var all = {};
14760                 var values = v.split("^");
14761                 for(var i = 0, len = values.length; i < len; i++){
14762                     var kv = values[i].split("=");
14763                     all[kv[0]] = this.decodeValue(kv[1]);
14764                 }
14765                 return all;
14766            default:
14767                 return v;
14768         }
14769     },
14770     
14771     /**
14772      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14773      * @param {Mixed} value The value to encode
14774      * @return {String} The encoded value
14775      */
14776     encodeValue : function(v){
14777         var enc;
14778         if(typeof v == "number"){
14779             enc = "n:" + v;
14780         }else if(typeof v == "boolean"){
14781             enc = "b:" + (v ? "1" : "0");
14782         }else if(v instanceof Date){
14783             enc = "d:" + v.toGMTString();
14784         }else if(v instanceof Array){
14785             var flat = "";
14786             for(var i = 0, len = v.length; i < len; i++){
14787                 flat += this.encodeValue(v[i]);
14788                 if(i != len-1) flat += "^";
14789             }
14790             enc = "a:" + flat;
14791         }else if(typeof v == "object"){
14792             var flat = "";
14793             for(var key in v){
14794                 if(typeof v[key] != "function"){
14795                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14796                 }
14797             }
14798             enc = "o:" + flat.substring(0, flat.length-1);
14799         }else{
14800             enc = "s:" + v;
14801         }
14802         return escape(enc);        
14803     }
14804 });
14805
14806 /*
14807  * Based on:
14808  * Ext JS Library 1.1.1
14809  * Copyright(c) 2006-2007, Ext JS, LLC.
14810  *
14811  * Originally Released Under LGPL - original licence link has changed is not relivant.
14812  *
14813  * Fork - LGPL
14814  * <script type="text/javascript">
14815  */
14816 /**
14817  * @class Roo.state.Manager
14818  * This is the global state manager. By default all components that are "state aware" check this class
14819  * for state information if you don't pass them a custom state provider. In order for this class
14820  * to be useful, it must be initialized with a provider when your application initializes.
14821  <pre><code>
14822 // in your initialization function
14823 init : function(){
14824    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14825    ...
14826    // supposed you have a {@link Roo.BorderLayout}
14827    var layout = new Roo.BorderLayout(...);
14828    layout.restoreState();
14829    // or a {Roo.BasicDialog}
14830    var dialog = new Roo.BasicDialog(...);
14831    dialog.restoreState();
14832  </code></pre>
14833  * @singleton
14834  */
14835 Roo.state.Manager = function(){
14836     var provider = new Roo.state.Provider();
14837     
14838     return {
14839         /**
14840          * Configures the default state provider for your application
14841          * @param {Provider} stateProvider The state provider to set
14842          */
14843         setProvider : function(stateProvider){
14844             provider = stateProvider;
14845         },
14846         
14847         /**
14848          * Returns the current value for a key
14849          * @param {String} name The key name
14850          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14851          * @return {Mixed} The state data
14852          */
14853         get : function(key, defaultValue){
14854             return provider.get(key, defaultValue);
14855         },
14856         
14857         /**
14858          * Sets the value for a key
14859          * @param {String} name The key name
14860          * @param {Mixed} value The state data
14861          */
14862          set : function(key, value){
14863             provider.set(key, value);
14864         },
14865         
14866         /**
14867          * Clears a value from the state
14868          * @param {String} name The key name
14869          */
14870         clear : function(key){
14871             provider.clear(key);
14872         },
14873         
14874         /**
14875          * Gets the currently configured state provider
14876          * @return {Provider} The state provider
14877          */
14878         getProvider : function(){
14879             return provider;
14880         }
14881     };
14882 }();
14883 /*
14884  * Based on:
14885  * Ext JS Library 1.1.1
14886  * Copyright(c) 2006-2007, Ext JS, LLC.
14887  *
14888  * Originally Released Under LGPL - original licence link has changed is not relivant.
14889  *
14890  * Fork - LGPL
14891  * <script type="text/javascript">
14892  */
14893 /**
14894  * @class Roo.state.CookieProvider
14895  * @extends Roo.state.Provider
14896  * The default Provider implementation which saves state via cookies.
14897  * <br />Usage:
14898  <pre><code>
14899    var cp = new Roo.state.CookieProvider({
14900        path: "/cgi-bin/",
14901        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14902        domain: "roojs.com"
14903    })
14904    Roo.state.Manager.setProvider(cp);
14905  </code></pre>
14906  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14907  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14908  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14909  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14910  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14911  * domain the page is running on including the 'www' like 'www.roojs.com')
14912  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14913  * @constructor
14914  * Create a new CookieProvider
14915  * @param {Object} config The configuration object
14916  */
14917 Roo.state.CookieProvider = function(config){
14918     Roo.state.CookieProvider.superclass.constructor.call(this);
14919     this.path = "/";
14920     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14921     this.domain = null;
14922     this.secure = false;
14923     Roo.apply(this, config);
14924     this.state = this.readCookies();
14925 };
14926
14927 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14928     // private
14929     set : function(name, value){
14930         if(typeof value == "undefined" || value === null){
14931             this.clear(name);
14932             return;
14933         }
14934         this.setCookie(name, value);
14935         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14936     },
14937
14938     // private
14939     clear : function(name){
14940         this.clearCookie(name);
14941         Roo.state.CookieProvider.superclass.clear.call(this, name);
14942     },
14943
14944     // private
14945     readCookies : function(){
14946         var cookies = {};
14947         var c = document.cookie + ";";
14948         var re = /\s?(.*?)=(.*?);/g;
14949         var matches;
14950         while((matches = re.exec(c)) != null){
14951             var name = matches[1];
14952             var value = matches[2];
14953             if(name && name.substring(0,3) == "ys-"){
14954                 cookies[name.substr(3)] = this.decodeValue(value);
14955             }
14956         }
14957         return cookies;
14958     },
14959
14960     // private
14961     setCookie : function(name, value){
14962         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
14963            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
14964            ((this.path == null) ? "" : ("; path=" + this.path)) +
14965            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14966            ((this.secure == true) ? "; secure" : "");
14967     },
14968
14969     // private
14970     clearCookie : function(name){
14971         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
14972            ((this.path == null) ? "" : ("; path=" + this.path)) +
14973            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
14974            ((this.secure == true) ? "; secure" : "");
14975     }
14976 });/*
14977  * Based on:
14978  * Ext JS Library 1.1.1
14979  * Copyright(c) 2006-2007, Ext JS, LLC.
14980  *
14981  * Originally Released Under LGPL - original licence link has changed is not relivant.
14982  *
14983  * Fork - LGPL
14984  * <script type="text/javascript">
14985  */
14986  
14987
14988 /**
14989  * @class Roo.ComponentMgr
14990  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
14991  * @singleton
14992  */
14993 Roo.ComponentMgr = function(){
14994     var all = new Roo.util.MixedCollection();
14995
14996     return {
14997         /**
14998          * Registers a component.
14999          * @param {Roo.Component} c The component
15000          */
15001         register : function(c){
15002             all.add(c);
15003         },
15004
15005         /**
15006          * Unregisters a component.
15007          * @param {Roo.Component} c The component
15008          */
15009         unregister : function(c){
15010             all.remove(c);
15011         },
15012
15013         /**
15014          * Returns a component by id
15015          * @param {String} id The component id
15016          */
15017         get : function(id){
15018             return all.get(id);
15019         },
15020
15021         /**
15022          * Registers a function that will be called when a specified component is added to ComponentMgr
15023          * @param {String} id The component id
15024          * @param {Funtction} fn The callback function
15025          * @param {Object} scope The scope of the callback
15026          */
15027         onAvailable : function(id, fn, scope){
15028             all.on("add", function(index, o){
15029                 if(o.id == id){
15030                     fn.call(scope || o, o);
15031                     all.un("add", fn, scope);
15032                 }
15033             });
15034         }
15035     };
15036 }();/*
15037  * Based on:
15038  * Ext JS Library 1.1.1
15039  * Copyright(c) 2006-2007, Ext JS, LLC.
15040  *
15041  * Originally Released Under LGPL - original licence link has changed is not relivant.
15042  *
15043  * Fork - LGPL
15044  * <script type="text/javascript">
15045  */
15046  
15047 /**
15048  * @class Roo.Component
15049  * @extends Roo.util.Observable
15050  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15051  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15052  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15053  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15054  * All visual components (widgets) that require rendering into a layout should subclass Component.
15055  * @constructor
15056  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15057  * 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
15058  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15059  */
15060 Roo.Component = function(config){
15061     config = config || {};
15062     if(config.tagName || config.dom || typeof config == "string"){ // element object
15063         config = {el: config, id: config.id || config};
15064     }
15065     this.initialConfig = config;
15066
15067     Roo.apply(this, config);
15068     this.addEvents({
15069         /**
15070          * @event disable
15071          * Fires after the component is disabled.
15072              * @param {Roo.Component} this
15073              */
15074         disable : true,
15075         /**
15076          * @event enable
15077          * Fires after the component is enabled.
15078              * @param {Roo.Component} this
15079              */
15080         enable : true,
15081         /**
15082          * @event beforeshow
15083          * Fires before the component is shown.  Return false to stop the show.
15084              * @param {Roo.Component} this
15085              */
15086         beforeshow : true,
15087         /**
15088          * @event show
15089          * Fires after the component is shown.
15090              * @param {Roo.Component} this
15091              */
15092         show : true,
15093         /**
15094          * @event beforehide
15095          * Fires before the component is hidden. Return false to stop the hide.
15096              * @param {Roo.Component} this
15097              */
15098         beforehide : true,
15099         /**
15100          * @event hide
15101          * Fires after the component is hidden.
15102              * @param {Roo.Component} this
15103              */
15104         hide : true,
15105         /**
15106          * @event beforerender
15107          * Fires before the component is rendered. Return false to stop the render.
15108              * @param {Roo.Component} this
15109              */
15110         beforerender : true,
15111         /**
15112          * @event render
15113          * Fires after the component is rendered.
15114              * @param {Roo.Component} this
15115              */
15116         render : true,
15117         /**
15118          * @event beforedestroy
15119          * Fires before the component is destroyed. Return false to stop the destroy.
15120              * @param {Roo.Component} this
15121              */
15122         beforedestroy : true,
15123         /**
15124          * @event destroy
15125          * Fires after the component is destroyed.
15126              * @param {Roo.Component} this
15127              */
15128         destroy : true
15129     });
15130     if(!this.id){
15131         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15132     }
15133     Roo.ComponentMgr.register(this);
15134     Roo.Component.superclass.constructor.call(this);
15135     this.initComponent();
15136     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15137         this.render(this.renderTo);
15138         delete this.renderTo;
15139     }
15140 };
15141
15142 /** @private */
15143 Roo.Component.AUTO_ID = 1000;
15144
15145 Roo.extend(Roo.Component, Roo.util.Observable, {
15146     /**
15147      * @scope Roo.Component.prototype
15148      * @type {Boolean}
15149      * true if this component is hidden. Read-only.
15150      */
15151     hidden : false,
15152     /**
15153      * @type {Boolean}
15154      * true if this component is disabled. Read-only.
15155      */
15156     disabled : false,
15157     /**
15158      * @type {Boolean}
15159      * true if this component has been rendered. Read-only.
15160      */
15161     rendered : false,
15162     
15163     /** @cfg {String} disableClass
15164      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15165      */
15166     disabledClass : "x-item-disabled",
15167         /** @cfg {Boolean} allowDomMove
15168          * Whether the component can move the Dom node when rendering (defaults to true).
15169          */
15170     allowDomMove : true,
15171     /** @cfg {String} hideMode
15172      * How this component should hidden. Supported values are
15173      * "visibility" (css visibility), "offsets" (negative offset position) and
15174      * "display" (css display) - defaults to "display".
15175      */
15176     hideMode: 'display',
15177
15178     /** @private */
15179     ctype : "Roo.Component",
15180
15181     /**
15182      * @cfg {String} actionMode 
15183      * which property holds the element that used for  hide() / show() / disable() / enable()
15184      * default is 'el' 
15185      */
15186     actionMode : "el",
15187
15188     /** @private */
15189     getActionEl : function(){
15190         return this[this.actionMode];
15191     },
15192
15193     initComponent : Roo.emptyFn,
15194     /**
15195      * If this is a lazy rendering component, render it to its container element.
15196      * @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.
15197      */
15198     render : function(container, position){
15199         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15200             if(!container && this.el){
15201                 this.el = Roo.get(this.el);
15202                 container = this.el.dom.parentNode;
15203                 this.allowDomMove = false;
15204             }
15205             this.container = Roo.get(container);
15206             this.rendered = true;
15207             if(position !== undefined){
15208                 if(typeof position == 'number'){
15209                     position = this.container.dom.childNodes[position];
15210                 }else{
15211                     position = Roo.getDom(position);
15212                 }
15213             }
15214             this.onRender(this.container, position || null);
15215             if(this.cls){
15216                 this.el.addClass(this.cls);
15217                 delete this.cls;
15218             }
15219             if(this.style){
15220                 this.el.applyStyles(this.style);
15221                 delete this.style;
15222             }
15223             this.fireEvent("render", this);
15224             this.afterRender(this.container);
15225             if(this.hidden){
15226                 this.hide();
15227             }
15228             if(this.disabled){
15229                 this.disable();
15230             }
15231         }
15232         return this;
15233     },
15234
15235     /** @private */
15236     // default function is not really useful
15237     onRender : function(ct, position){
15238         if(this.el){
15239             this.el = Roo.get(this.el);
15240             if(this.allowDomMove !== false){
15241                 ct.dom.insertBefore(this.el.dom, position);
15242             }
15243         }
15244     },
15245
15246     /** @private */
15247     getAutoCreate : function(){
15248         var cfg = typeof this.autoCreate == "object" ?
15249                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15250         if(this.id && !cfg.id){
15251             cfg.id = this.id;
15252         }
15253         return cfg;
15254     },
15255
15256     /** @private */
15257     afterRender : Roo.emptyFn,
15258
15259     /**
15260      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15261      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15262      */
15263     destroy : function(){
15264         if(this.fireEvent("beforedestroy", this) !== false){
15265             this.purgeListeners();
15266             this.beforeDestroy();
15267             if(this.rendered){
15268                 this.el.removeAllListeners();
15269                 this.el.remove();
15270                 if(this.actionMode == "container"){
15271                     this.container.remove();
15272                 }
15273             }
15274             this.onDestroy();
15275             Roo.ComponentMgr.unregister(this);
15276             this.fireEvent("destroy", this);
15277         }
15278     },
15279
15280         /** @private */
15281     beforeDestroy : function(){
15282
15283     },
15284
15285         /** @private */
15286         onDestroy : function(){
15287
15288     },
15289
15290     /**
15291      * Returns the underlying {@link Roo.Element}.
15292      * @return {Roo.Element} The element
15293      */
15294     getEl : function(){
15295         return this.el;
15296     },
15297
15298     /**
15299      * Returns the id of this component.
15300      * @return {String}
15301      */
15302     getId : function(){
15303         return this.id;
15304     },
15305
15306     /**
15307      * Try to focus this component.
15308      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15309      * @return {Roo.Component} this
15310      */
15311     focus : function(selectText){
15312         if(this.rendered){
15313             this.el.focus();
15314             if(selectText === true){
15315                 this.el.dom.select();
15316             }
15317         }
15318         return this;
15319     },
15320
15321     /** @private */
15322     blur : function(){
15323         if(this.rendered){
15324             this.el.blur();
15325         }
15326         return this;
15327     },
15328
15329     /**
15330      * Disable this component.
15331      * @return {Roo.Component} this
15332      */
15333     disable : function(){
15334         if(this.rendered){
15335             this.onDisable();
15336         }
15337         this.disabled = true;
15338         this.fireEvent("disable", this);
15339         return this;
15340     },
15341
15342         // private
15343     onDisable : function(){
15344         this.getActionEl().addClass(this.disabledClass);
15345         this.el.dom.disabled = true;
15346     },
15347
15348     /**
15349      * Enable this component.
15350      * @return {Roo.Component} this
15351      */
15352     enable : function(){
15353         if(this.rendered){
15354             this.onEnable();
15355         }
15356         this.disabled = false;
15357         this.fireEvent("enable", this);
15358         return this;
15359     },
15360
15361         // private
15362     onEnable : function(){
15363         this.getActionEl().removeClass(this.disabledClass);
15364         this.el.dom.disabled = false;
15365     },
15366
15367     /**
15368      * Convenience function for setting disabled/enabled by boolean.
15369      * @param {Boolean} disabled
15370      */
15371     setDisabled : function(disabled){
15372         this[disabled ? "disable" : "enable"]();
15373     },
15374
15375     /**
15376      * Show this component.
15377      * @return {Roo.Component} this
15378      */
15379     show: function(){
15380         if(this.fireEvent("beforeshow", this) !== false){
15381             this.hidden = false;
15382             if(this.rendered){
15383                 this.onShow();
15384             }
15385             this.fireEvent("show", this);
15386         }
15387         return this;
15388     },
15389
15390     // private
15391     onShow : function(){
15392         var ae = this.getActionEl();
15393         if(this.hideMode == 'visibility'){
15394             ae.dom.style.visibility = "visible";
15395         }else if(this.hideMode == 'offsets'){
15396             ae.removeClass('x-hidden');
15397         }else{
15398             ae.dom.style.display = "";
15399         }
15400     },
15401
15402     /**
15403      * Hide this component.
15404      * @return {Roo.Component} this
15405      */
15406     hide: function(){
15407         if(this.fireEvent("beforehide", this) !== false){
15408             this.hidden = true;
15409             if(this.rendered){
15410                 this.onHide();
15411             }
15412             this.fireEvent("hide", this);
15413         }
15414         return this;
15415     },
15416
15417     // private
15418     onHide : function(){
15419         var ae = this.getActionEl();
15420         if(this.hideMode == 'visibility'){
15421             ae.dom.style.visibility = "hidden";
15422         }else if(this.hideMode == 'offsets'){
15423             ae.addClass('x-hidden');
15424         }else{
15425             ae.dom.style.display = "none";
15426         }
15427     },
15428
15429     /**
15430      * Convenience function to hide or show this component by boolean.
15431      * @param {Boolean} visible True to show, false to hide
15432      * @return {Roo.Component} this
15433      */
15434     setVisible: function(visible){
15435         if(visible) {
15436             this.show();
15437         }else{
15438             this.hide();
15439         }
15440         return this;
15441     },
15442
15443     /**
15444      * Returns true if this component is visible.
15445      */
15446     isVisible : function(){
15447         return this.getActionEl().isVisible();
15448     },
15449
15450     cloneConfig : function(overrides){
15451         overrides = overrides || {};
15452         var id = overrides.id || Roo.id();
15453         var cfg = Roo.applyIf(overrides, this.initialConfig);
15454         cfg.id = id; // prevent dup id
15455         return new this.constructor(cfg);
15456     }
15457 });/*
15458  * Based on:
15459  * Ext JS Library 1.1.1
15460  * Copyright(c) 2006-2007, Ext JS, LLC.
15461  *
15462  * Originally Released Under LGPL - original licence link has changed is not relivant.
15463  *
15464  * Fork - LGPL
15465  * <script type="text/javascript">
15466  */
15467
15468 /**
15469  * @class Roo.BoxComponent
15470  * @extends Roo.Component
15471  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15472  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15473  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15474  * layout containers.
15475  * @constructor
15476  * @param {Roo.Element/String/Object} config The configuration options.
15477  */
15478 Roo.BoxComponent = function(config){
15479     Roo.Component.call(this, config);
15480     this.addEvents({
15481         /**
15482          * @event resize
15483          * Fires after the component is resized.
15484              * @param {Roo.Component} this
15485              * @param {Number} adjWidth The box-adjusted width that was set
15486              * @param {Number} adjHeight The box-adjusted height that was set
15487              * @param {Number} rawWidth The width that was originally specified
15488              * @param {Number} rawHeight The height that was originally specified
15489              */
15490         resize : true,
15491         /**
15492          * @event move
15493          * Fires after the component is moved.
15494              * @param {Roo.Component} this
15495              * @param {Number} x The new x position
15496              * @param {Number} y The new y position
15497              */
15498         move : true
15499     });
15500 };
15501
15502 Roo.extend(Roo.BoxComponent, Roo.Component, {
15503     // private, set in afterRender to signify that the component has been rendered
15504     boxReady : false,
15505     // private, used to defer height settings to subclasses
15506     deferHeight: false,
15507     /** @cfg {Number} width
15508      * width (optional) size of component
15509      */
15510      /** @cfg {Number} height
15511      * height (optional) size of component
15512      */
15513      
15514     /**
15515      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15516      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15517      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15518      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15519      * @return {Roo.BoxComponent} this
15520      */
15521     setSize : function(w, h){
15522         // support for standard size objects
15523         if(typeof w == 'object'){
15524             h = w.height;
15525             w = w.width;
15526         }
15527         // not rendered
15528         if(!this.boxReady){
15529             this.width = w;
15530             this.height = h;
15531             return this;
15532         }
15533
15534         // prevent recalcs when not needed
15535         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15536             return this;
15537         }
15538         this.lastSize = {width: w, height: h};
15539
15540         var adj = this.adjustSize(w, h);
15541         var aw = adj.width, ah = adj.height;
15542         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15543             var rz = this.getResizeEl();
15544             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15545                 rz.setSize(aw, ah);
15546             }else if(!this.deferHeight && ah !== undefined){
15547                 rz.setHeight(ah);
15548             }else if(aw !== undefined){
15549                 rz.setWidth(aw);
15550             }
15551             this.onResize(aw, ah, w, h);
15552             this.fireEvent('resize', this, aw, ah, w, h);
15553         }
15554         return this;
15555     },
15556
15557     /**
15558      * Gets the current size of the component's underlying element.
15559      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15560      */
15561     getSize : function(){
15562         return this.el.getSize();
15563     },
15564
15565     /**
15566      * Gets the current XY position of the component's underlying element.
15567      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15568      * @return {Array} The XY position of the element (e.g., [100, 200])
15569      */
15570     getPosition : function(local){
15571         if(local === true){
15572             return [this.el.getLeft(true), this.el.getTop(true)];
15573         }
15574         return this.xy || this.el.getXY();
15575     },
15576
15577     /**
15578      * Gets the current box measurements of the component's underlying element.
15579      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15580      * @returns {Object} box An object in the format {x, y, width, height}
15581      */
15582     getBox : function(local){
15583         var s = this.el.getSize();
15584         if(local){
15585             s.x = this.el.getLeft(true);
15586             s.y = this.el.getTop(true);
15587         }else{
15588             var xy = this.xy || this.el.getXY();
15589             s.x = xy[0];
15590             s.y = xy[1];
15591         }
15592         return s;
15593     },
15594
15595     /**
15596      * Sets the current box measurements of the component's underlying element.
15597      * @param {Object} box An object in the format {x, y, width, height}
15598      * @returns {Roo.BoxComponent} this
15599      */
15600     updateBox : function(box){
15601         this.setSize(box.width, box.height);
15602         this.setPagePosition(box.x, box.y);
15603         return this;
15604     },
15605
15606     // protected
15607     getResizeEl : function(){
15608         return this.resizeEl || this.el;
15609     },
15610
15611     // protected
15612     getPositionEl : function(){
15613         return this.positionEl || this.el;
15614     },
15615
15616     /**
15617      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15618      * This method fires the move event.
15619      * @param {Number} left The new left
15620      * @param {Number} top The new top
15621      * @returns {Roo.BoxComponent} this
15622      */
15623     setPosition : function(x, y){
15624         this.x = x;
15625         this.y = y;
15626         if(!this.boxReady){
15627             return this;
15628         }
15629         var adj = this.adjustPosition(x, y);
15630         var ax = adj.x, ay = adj.y;
15631
15632         var el = this.getPositionEl();
15633         if(ax !== undefined || ay !== undefined){
15634             if(ax !== undefined && ay !== undefined){
15635                 el.setLeftTop(ax, ay);
15636             }else if(ax !== undefined){
15637                 el.setLeft(ax);
15638             }else if(ay !== undefined){
15639                 el.setTop(ay);
15640             }
15641             this.onPosition(ax, ay);
15642             this.fireEvent('move', this, ax, ay);
15643         }
15644         return this;
15645     },
15646
15647     /**
15648      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15649      * This method fires the move event.
15650      * @param {Number} x The new x position
15651      * @param {Number} y The new y position
15652      * @returns {Roo.BoxComponent} this
15653      */
15654     setPagePosition : function(x, y){
15655         this.pageX = x;
15656         this.pageY = y;
15657         if(!this.boxReady){
15658             return;
15659         }
15660         if(x === undefined || y === undefined){ // cannot translate undefined points
15661             return;
15662         }
15663         var p = this.el.translatePoints(x, y);
15664         this.setPosition(p.left, p.top);
15665         return this;
15666     },
15667
15668     // private
15669     onRender : function(ct, position){
15670         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15671         if(this.resizeEl){
15672             this.resizeEl = Roo.get(this.resizeEl);
15673         }
15674         if(this.positionEl){
15675             this.positionEl = Roo.get(this.positionEl);
15676         }
15677     },
15678
15679     // private
15680     afterRender : function(){
15681         Roo.BoxComponent.superclass.afterRender.call(this);
15682         this.boxReady = true;
15683         this.setSize(this.width, this.height);
15684         if(this.x || this.y){
15685             this.setPosition(this.x, this.y);
15686         }
15687         if(this.pageX || this.pageY){
15688             this.setPagePosition(this.pageX, this.pageY);
15689         }
15690     },
15691
15692     /**
15693      * Force the component's size to recalculate based on the underlying element's current height and width.
15694      * @returns {Roo.BoxComponent} this
15695      */
15696     syncSize : function(){
15697         delete this.lastSize;
15698         this.setSize(this.el.getWidth(), this.el.getHeight());
15699         return this;
15700     },
15701
15702     /**
15703      * Called after the component is resized, this method is empty by default but can be implemented by any
15704      * subclass that needs to perform custom logic after a resize occurs.
15705      * @param {Number} adjWidth The box-adjusted width that was set
15706      * @param {Number} adjHeight The box-adjusted height that was set
15707      * @param {Number} rawWidth The width that was originally specified
15708      * @param {Number} rawHeight The height that was originally specified
15709      */
15710     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15711
15712     },
15713
15714     /**
15715      * Called after the component is moved, this method is empty by default but can be implemented by any
15716      * subclass that needs to perform custom logic after a move occurs.
15717      * @param {Number} x The new x position
15718      * @param {Number} y The new y position
15719      */
15720     onPosition : function(x, y){
15721
15722     },
15723
15724     // private
15725     adjustSize : function(w, h){
15726         if(this.autoWidth){
15727             w = 'auto';
15728         }
15729         if(this.autoHeight){
15730             h = 'auto';
15731         }
15732         return {width : w, height: h};
15733     },
15734
15735     // private
15736     adjustPosition : function(x, y){
15737         return {x : x, y: y};
15738     }
15739 });/*
15740  * Original code for Roojs - LGPL
15741  * <script type="text/javascript">
15742  */
15743  
15744 /**
15745  * @class Roo.XComponent
15746  * A delayed Element creator...
15747  * Or a way to group chunks of interface together.
15748  * 
15749  * Mypart.xyx = new Roo.XComponent({
15750
15751     parent : 'Mypart.xyz', // empty == document.element.!!
15752     order : '001',
15753     name : 'xxxx'
15754     region : 'xxxx'
15755     disabled : function() {} 
15756      
15757     tree : function() { // return an tree of xtype declared components
15758         var MODULE = this;
15759         return 
15760         {
15761             xtype : 'NestedLayoutPanel',
15762             // technicall
15763         }
15764      ]
15765  *})
15766  *
15767  *
15768  * It can be used to build a big heiracy, with parent etc.
15769  * or you can just use this to render a single compoent to a dom element
15770  * MYPART.render(Roo.Element | String(id) | dom_element )
15771  * 
15772  * @extends Roo.util.Observable
15773  * @constructor
15774  * @param cfg {Object} configuration of component
15775  * 
15776  */
15777 Roo.XComponent = function(cfg) {
15778     Roo.apply(this, cfg);
15779     this.addEvents({ 
15780         /**
15781              * @event built
15782              * Fires when this the componnt is built
15783              * @param {Roo.XComponent} c the component
15784              */
15785         'built' : true
15786         
15787     });
15788     this.region = this.region || 'center'; // default..
15789     Roo.XComponent.register(this);
15790     this.modules = false;
15791     this.el = false; // where the layout goes..
15792     
15793     
15794 }
15795 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15796     /**
15797      * @property el
15798      * The created element (with Roo.factory())
15799      * @type {Roo.Layout}
15800      */
15801     el  : false,
15802     
15803     /**
15804      * @property el
15805      * for BC  - use el in new code
15806      * @type {Roo.Layout}
15807      */
15808     panel : false,
15809     
15810     /**
15811      * @property layout
15812      * for BC  - use el in new code
15813      * @type {Roo.Layout}
15814      */
15815     layout : false,
15816     
15817      /**
15818      * @cfg {Function|boolean} disabled
15819      * If this module is disabled by some rule, return true from the funtion
15820      */
15821     disabled : false,
15822     
15823     /**
15824      * @cfg {String} parent 
15825      * Name of parent element which it get xtype added to..
15826      */
15827     parent: false,
15828     
15829     /**
15830      * @cfg {String} order
15831      * Used to set the order in which elements are created (usefull for multiple tabs)
15832      */
15833     
15834     order : false,
15835     /**
15836      * @cfg {String} name
15837      * String to display while loading.
15838      */
15839     name : false,
15840     /**
15841      * @cfg {String} region
15842      * Region to render component to (defaults to center)
15843      */
15844     region : 'center',
15845     
15846     /**
15847      * @cfg {Array} items
15848      * A single item array - the first element is the root of the tree..
15849      * It's done this way to stay compatible with the Xtype system...
15850      */
15851     items : false,
15852     
15853     /**
15854      * @property _tree
15855      * The method that retuns the tree of parts that make up this compoennt 
15856      * @type {function}
15857      */
15858     _tree  : false,
15859     
15860      /**
15861      * render
15862      * render element to dom or tree
15863      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15864      */
15865     
15866     render : function(el)
15867     {
15868         
15869         el = el || false;
15870         var hp = this.parent ? 1 : 0;
15871         
15872         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15873             // if parent is a '#.....' string, then let's use that..
15874             var ename = this.parent.substr(1)
15875             this.parent = (this.parent == '#bootstrap') ? { el : true}  : false; // flags it as a top module...
15876             el = Roo.get(ename);
15877             if (!el && !this.parent) {
15878                 Roo.log("Warning - element can not be found :#" + ename );
15879                 return;
15880             }
15881         }
15882         var tree = this._tree ? this._tree() : this.tree();
15883
15884         
15885         if (!this.parent && typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) {
15886             //el = Roo.get(document.body);
15887             this.parent = { el : true };
15888         }
15889             
15890             
15891         
15892         if (!this.parent) {
15893             
15894             Roo.log("no parent - creating one");
15895             
15896             el = el ? Roo.get(el) : false;      
15897             
15898             // it's a top level one..
15899             this.parent =  {
15900                 el : new Roo.BorderLayout(el || document.body, {
15901                 
15902                      center: {
15903                          titlebar: false,
15904                          autoScroll:false,
15905                          closeOnTab: true,
15906                          tabPosition: 'top',
15907                           //resizeTabs: true,
15908                          alwaysShowTabs: el && hp? false :  true,
15909                          hideTabs: el || !hp ? true :  false,
15910                          minTabWidth: 140
15911                      }
15912                  })
15913             }
15914         }
15915         
15916                 if (!this.parent.el) {
15917                         // probably an old style ctor, which has been disabled.
15918                         return;
15919                         
15920                 }
15921                 // The 'tree' method is  '_tree now' 
15922             
15923         tree.region = tree.region || this.region;
15924         
15925         if (this.parent.el === true) {
15926             // bootstrap... - body..
15927             this.parent.el = Roo.factory(tree);
15928         }
15929         
15930         this.el = this.parent.el.addxtype(tree);
15931         this.fireEvent('built', this);
15932         
15933         this.panel = this.el;
15934         this.layout = this.panel.layout;
15935                 this.parentLayout = this.parent.layout  || false;  
15936          
15937     }
15938     
15939 });
15940
15941 Roo.apply(Roo.XComponent, {
15942     /**
15943      * @property  hideProgress
15944      * true to disable the building progress bar.. usefull on single page renders.
15945      * @type Boolean
15946      */
15947     hideProgress : false,
15948     /**
15949      * @property  buildCompleted
15950      * True when the builder has completed building the interface.
15951      * @type Boolean
15952      */
15953     buildCompleted : false,
15954      
15955     /**
15956      * @property  topModule
15957      * the upper most module - uses document.element as it's constructor.
15958      * @type Object
15959      */
15960      
15961     topModule  : false,
15962       
15963     /**
15964      * @property  modules
15965      * array of modules to be created by registration system.
15966      * @type {Array} of Roo.XComponent
15967      */
15968     
15969     modules : [],
15970     /**
15971      * @property  elmodules
15972      * array of modules to be created by which use #ID 
15973      * @type {Array} of Roo.XComponent
15974      */
15975      
15976     elmodules : [],
15977
15978      /**
15979      * @property  build_from_html
15980      * Build elements from html - used by bootstrap HTML stuff 
15981      *    - this is cleared after build is completed
15982      * @type {boolean} true  (default false)
15983      */
15984      
15985     build_from_html : false,
15986
15987     /**
15988      * Register components to be built later.
15989      *
15990      * This solves the following issues
15991      * - Building is not done on page load, but after an authentication process has occured.
15992      * - Interface elements are registered on page load
15993      * - Parent Interface elements may not be loaded before child, so this handles that..
15994      * 
15995      *
15996      * example:
15997      * 
15998      * MyApp.register({
15999           order : '000001',
16000           module : 'Pman.Tab.projectMgr',
16001           region : 'center',
16002           parent : 'Pman.layout',
16003           disabled : false,  // or use a function..
16004         })
16005      
16006      * * @param {Object} details about module
16007      */
16008     register : function(obj) {
16009                 
16010         Roo.XComponent.event.fireEvent('register', obj);
16011         switch(typeof(obj.disabled) ) {
16012                 
16013             case 'undefined':
16014                 break;
16015             
16016             case 'function':
16017                 if ( obj.disabled() ) {
16018                         return;
16019                 }
16020                 break;
16021             
16022             default:
16023                 if (obj.disabled) {
16024                         return;
16025                 }
16026                 break;
16027         }
16028                 
16029         this.modules.push(obj);
16030          
16031     },
16032     /**
16033      * convert a string to an object..
16034      * eg. 'AAA.BBB' -> finds AAA.BBB
16035
16036      */
16037     
16038     toObject : function(str)
16039     {
16040         if (!str || typeof(str) == 'object') {
16041             return str;
16042         }
16043         if (str.substring(0,1) == '#') {
16044             return str;
16045         }
16046
16047         var ar = str.split('.');
16048         var rt, o;
16049         rt = ar.shift();
16050             /** eval:var:o */
16051         try {
16052             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16053         } catch (e) {
16054             throw "Module not found : " + str;
16055         }
16056         
16057         if (o === false) {
16058             throw "Module not found : " + str;
16059         }
16060         Roo.each(ar, function(e) {
16061             if (typeof(o[e]) == 'undefined') {
16062                 throw "Module not found : " + str;
16063             }
16064             o = o[e];
16065         });
16066         
16067         return o;
16068         
16069     },
16070     
16071     
16072     /**
16073      * move modules into their correct place in the tree..
16074      * 
16075      */
16076     preBuild : function ()
16077     {
16078         var _t = this;
16079         Roo.each(this.modules , function (obj)
16080         {
16081             Roo.XComponent.event.fireEvent('beforebuild', obj);
16082             
16083             var opar = obj.parent;
16084             try { 
16085                 obj.parent = this.toObject(opar);
16086             } catch(e) {
16087                 Roo.log("parent:toObject failed: " + e.toString());
16088                 return;
16089             }
16090             
16091             if (!obj.parent) {
16092                 Roo.debug && Roo.log("GOT top level module");
16093                 Roo.debug && Roo.log(obj);
16094                 obj.modules = new Roo.util.MixedCollection(false, 
16095                     function(o) { return o.order + '' }
16096                 );
16097                 this.topModule = obj;
16098                 return;
16099             }
16100                         // parent is a string (usually a dom element name..)
16101             if (typeof(obj.parent) == 'string') {
16102                 this.elmodules.push(obj);
16103                 return;
16104             }
16105             if (obj.parent.constructor != Roo.XComponent) {
16106                 Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16107             }
16108             if (!obj.parent.modules) {
16109                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16110                     function(o) { return o.order + '' }
16111                 );
16112             }
16113             if (obj.parent.disabled) {
16114                 obj.disabled = true;
16115             }
16116             obj.parent.modules.add(obj);
16117         }, this);
16118     },
16119     
16120      /**
16121      * make a list of modules to build.
16122      * @return {Array} list of modules. 
16123      */ 
16124     
16125     buildOrder : function()
16126     {
16127         var _this = this;
16128         var cmp = function(a,b) {   
16129             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16130         };
16131         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16132             throw "No top level modules to build";
16133         }
16134         
16135         // make a flat list in order of modules to build.
16136         var mods = this.topModule ? [ this.topModule ] : [];
16137                 
16138         
16139         // elmodules (is a list of DOM based modules )
16140         Roo.each(this.elmodules, function(e) {
16141             mods.push(e);
16142             if (!this.topModule &&
16143                 typeof(e.parent) == 'string' &&
16144                 e.parent.substring(0,1) == '#' &&
16145                 Roo.get(e.parent.substr(1))
16146                ) {
16147                 
16148                 _this.topModule = e;
16149             }
16150             
16151         });
16152
16153         
16154         // add modules to their parents..
16155         var addMod = function(m) {
16156             Roo.debug && Roo.log("build Order: add: " + m.name);
16157                 
16158             mods.push(m);
16159             if (m.modules && !m.disabled) {
16160                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16161                 m.modules.keySort('ASC',  cmp );
16162                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16163     
16164                 m.modules.each(addMod);
16165             } else {
16166                 Roo.debug && Roo.log("build Order: no child modules");
16167             }
16168             // not sure if this is used any more..
16169             if (m.finalize) {
16170                 m.finalize.name = m.name + " (clean up) ";
16171                 mods.push(m.finalize);
16172             }
16173             
16174         }
16175         if (this.topModule && this.topModule.modules) { 
16176             this.topModule.modules.keySort('ASC',  cmp );
16177             this.topModule.modules.each(addMod);
16178         } 
16179         return mods;
16180     },
16181     
16182      /**
16183      * Build the registered modules.
16184      * @param {Object} parent element.
16185      * @param {Function} optional method to call after module has been added.
16186      * 
16187      */ 
16188    
16189     build : function(opts) 
16190     {
16191         
16192         if (typeof(opts) != 'undefined') {
16193             Roo.apply(this,opts);
16194         }
16195         
16196         this.preBuild();
16197         var mods = this.buildOrder();
16198       
16199         //this.allmods = mods;
16200         //Roo.debug && Roo.log(mods);
16201         //return;
16202         if (!mods.length) { // should not happen
16203             throw "NO modules!!!";
16204         }
16205         
16206         
16207         var msg = "Building Interface...";
16208         // flash it up as modal - so we store the mask!?
16209         if (!this.hideProgress && Roo.MessageBox) {
16210             Roo.MessageBox.show({ title: 'loading' });
16211             Roo.MessageBox.show({
16212                title: "Please wait...",
16213                msg: msg,
16214                width:450,
16215                progress:true,
16216                closable:false,
16217                modal: false
16218               
16219             });
16220         }
16221         var total = mods.length;
16222         
16223         var _this = this;
16224         var progressRun = function() {
16225             if (!mods.length) {
16226                 Roo.debug && Roo.log('hide?');
16227                 if (!this.hideProgress && Roo.MessageBox) {
16228                     Roo.MessageBox.hide();
16229                 }
16230                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16231                 
16232                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16233                 
16234                 // THE END...
16235                 return false;   
16236             }
16237             
16238             var m = mods.shift();
16239             
16240             
16241             Roo.debug && Roo.log(m);
16242             // not sure if this is supported any more.. - modules that are are just function
16243             if (typeof(m) == 'function') { 
16244                 m.call(this);
16245                 return progressRun.defer(10, _this);
16246             } 
16247             
16248             
16249             msg = "Building Interface " + (total  - mods.length) + 
16250                     " of " + total + 
16251                     (m.name ? (' - ' + m.name) : '');
16252                         Roo.debug && Roo.log(msg);
16253             if (!this.hideProgress &&  Roo.MessageBox) { 
16254                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16255             }
16256             
16257          
16258             // is the module disabled?
16259             var disabled = (typeof(m.disabled) == 'function') ?
16260                 m.disabled.call(m.module.disabled) : m.disabled;    
16261             
16262             
16263             if (disabled) {
16264                 return progressRun(); // we do not update the display!
16265             }
16266             
16267             // now build 
16268             
16269                         
16270                         
16271             m.render();
16272             // it's 10 on top level, and 1 on others??? why...
16273             return progressRun.defer(10, _this);
16274              
16275         }
16276         progressRun.defer(1, _this);
16277      
16278         
16279         
16280     },
16281         
16282         
16283         /**
16284          * Event Object.
16285          *
16286          *
16287          */
16288         event: false, 
16289     /**
16290          * wrapper for event.on - aliased later..  
16291          * Typically use to register a event handler for register:
16292          *
16293          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16294          *
16295          */
16296     on : false
16297    
16298     
16299     
16300 });
16301
16302 Roo.XComponent.event = new Roo.util.Observable({
16303                 events : { 
16304                         /**
16305                          * @event register
16306                          * Fires when an Component is registered,
16307                          * set the disable property on the Component to stop registration.
16308                          * @param {Roo.XComponent} c the component being registerd.
16309                          * 
16310                          */
16311                         'register' : true,
16312             /**
16313                          * @event beforebuild
16314                          * Fires before each Component is built
16315                          * can be used to apply permissions.
16316                          * @param {Roo.XComponent} c the component being registerd.
16317                          * 
16318                          */
16319                         'beforebuild' : true,
16320                         /**
16321                          * @event buildcomplete
16322                          * Fires on the top level element when all elements have been built
16323                          * @param {Roo.XComponent} the top level component.
16324                          */
16325                         'buildcomplete' : true
16326                         
16327                 }
16328 });
16329
16330 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16331