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 =  (function() {
65             try {  
66                 document.createEvent("TouchEvent");  
67                 return true;  
68             } catch (e) {  
69                 return false;  
70             } 
71             
72         })();
73     // remove css image flicker
74         if(isIE && !isIE7){
75         try{
76             document.execCommand("BackgroundImageCache", false, true);
77         }catch(e){}
78     }
79     
80     Roo.apply(Roo, {
81         /**
82          * True if the browser is in strict mode
83          * @type Boolean
84          */
85         isStrict : isStrict,
86         /**
87          * True if the page is running over SSL
88          * @type Boolean
89          */
90         isSecure : isSecure,
91         /**
92          * True when the document is fully initialized and ready for action
93          * @type Boolean
94          */
95         isReady : false,
96         /**
97          * Turn on debugging output (currently only the factory uses this)
98          * @type Boolean
99          */
100         
101         debug: false,
102
103         /**
104          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
105          * @type Boolean
106          */
107         enableGarbageCollector : true,
108
109         /**
110          * True to automatically purge event listeners after uncaching an element (defaults to false).
111          * Note: this only happens if enableGarbageCollector is true.
112          * @type Boolean
113          */
114         enableListenerCollection:false,
115
116         /**
117          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
118          * the IE insecure content warning (defaults to javascript:false).
119          * @type String
120          */
121         SSL_SECURE_URL : "javascript:false",
122
123         /**
124          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
125          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
126          * @type String
127          */
128         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
129
130         emptyFn : function(){},
131         
132         /**
133          * Copies all the properties of config to obj if they don't already exist.
134          * @param {Object} obj The receiver of the properties
135          * @param {Object} config The source of the properties
136          * @return {Object} returns obj
137          */
138         applyIf : function(o, c){
139             if(o && c){
140                 for(var p in c){
141                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
142                 }
143             }
144             return o;
145         },
146
147         /**
148          * Applies event listeners to elements by selectors when the document is ready.
149          * The event name is specified with an @ suffix.
150 <pre><code>
151 Roo.addBehaviors({
152    // add a listener for click on all anchors in element with id foo
153    '#foo a@click' : function(e, t){
154        // do something
155    },
156
157    // add the same listener to multiple selectors (separated by comma BEFORE the @)
158    '#foo a, #bar span.some-class@mouseover' : function(){
159        // do something
160    }
161 });
162 </code></pre>
163          * @param {Object} obj The list of behaviors to apply
164          */
165         addBehaviors : function(o){
166             if(!Roo.isReady){
167                 Roo.onReady(function(){
168                     Roo.addBehaviors(o);
169                 });
170                 return;
171             }
172             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
173             for(var b in o){
174                 var parts = b.split('@');
175                 if(parts[1]){ // for Object prototype breakers
176                     var s = parts[0];
177                     if(!cache[s]){
178                         cache[s] = Roo.select(s);
179                     }
180                     cache[s].on(parts[1], o[b]);
181                 }
182             }
183             cache = null;
184         },
185
186         /**
187          * Generates unique ids. If the element already has an id, it is unchanged
188          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
189          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
190          * @return {String} The generated Id.
191          */
192         id : function(el, prefix){
193             prefix = prefix || "roo-gen";
194             el = Roo.getDom(el);
195             var id = prefix + (++idSeed);
196             return el ? (el.id ? el.id : (el.id = id)) : id;
197         },
198          
199        
200         /**
201          * Extends one class with another class and optionally overrides members with the passed literal. This class
202          * also adds the function "override()" to the class that can be used to override
203          * members on an instance.
204          * @param {Object} subclass The class inheriting the functionality
205          * @param {Object} superclass The class being extended
206          * @param {Object} overrides (optional) A literal with members
207          * @method extend
208          */
209         extend : function(){
210             // inline overrides
211             var io = function(o){
212                 for(var m in o){
213                     this[m] = o[m];
214                 }
215             };
216             return function(sb, sp, overrides){
217                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
218                     overrides = sp;
219                     sp = sb;
220                     sb = function(){sp.apply(this, arguments);};
221                 }
222                 var F = function(){}, sbp, spp = sp.prototype;
223                 F.prototype = spp;
224                 sbp = sb.prototype = new F();
225                 sbp.constructor=sb;
226                 sb.superclass=spp;
227                 
228                 if(spp.constructor == Object.prototype.constructor){
229                     spp.constructor=sp;
230                    
231                 }
232                 
233                 sb.override = function(o){
234                     Roo.override(sb, o);
235                 };
236                 sbp.override = io;
237                 Roo.override(sb, overrides);
238                 return sb;
239             };
240         }(),
241
242         /**
243          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
244          * Usage:<pre><code>
245 Roo.override(MyClass, {
246     newMethod1: function(){
247         // etc.
248     },
249     newMethod2: function(foo){
250         // etc.
251     }
252 });
253  </code></pre>
254          * @param {Object} origclass The class to override
255          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
256          * containing one or more methods.
257          * @method override
258          */
259         override : function(origclass, overrides){
260             if(overrides){
261                 var p = origclass.prototype;
262                 for(var method in overrides){
263                     p[method] = overrides[method];
264                 }
265             }
266         },
267         /**
268          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
269          * <pre><code>
270 Roo.namespace('Company', 'Company.data');
271 Company.Widget = function() { ... }
272 Company.data.CustomStore = function(config) { ... }
273 </code></pre>
274          * @param {String} namespace1
275          * @param {String} namespace2
276          * @param {String} etc
277          * @method namespace
278          */
279         namespace : function(){
280             var a=arguments, o=null, i, j, d, rt;
281             for (i=0; i<a.length; ++i) {
282                 d=a[i].split(".");
283                 rt = d[0];
284                 /** eval:var:o */
285                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
286                 for (j=1; j<d.length; ++j) {
287                     o[d[j]]=o[d[j]] || {};
288                     o=o[d[j]];
289                 }
290             }
291         },
292         /**
293          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
294          * <pre><code>
295 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
296 Roo.factory(conf, Roo.data);
297 </code></pre>
298          * @param {String} classname
299          * @param {String} namespace (optional)
300          * @method factory
301          */
302          
303         factory : function(c, ns)
304         {
305             // no xtype, no ns or c.xns - or forced off by c.xns
306             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
307                 return c;
308             }
309             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
310             if (c.constructor == ns[c.xtype]) {// already created...
311                 return c;
312             }
313             if (ns[c.xtype]) {
314                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
315                 var ret = new ns[c.xtype](c);
316                 ret.xns = false;
317                 return ret;
318             }
319             c.xns = false; // prevent recursion..
320             return c;
321         },
322          /**
323          * Logs to console if it can.
324          *
325          * @param {String|Object} string
326          * @method log
327          */
328         log : function(s)
329         {
330             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
331                 return; // alerT?
332             }
333             console.log(s);
334             
335         },
336         /**
337          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
338          * @param {Object} o
339          * @return {String}
340          */
341         urlEncode : function(o){
342             if(!o){
343                 return "";
344             }
345             var buf = [];
346             for(var key in o){
347                 var ov = o[key], k = Roo.encodeURIComponent(key);
348                 var type = typeof ov;
349                 if(type == 'undefined'){
350                     buf.push(k, "=&");
351                 }else if(type != "function" && type != "object"){
352                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
353                 }else if(ov instanceof Array){
354                     if (ov.length) {
355                             for(var i = 0, len = ov.length; i < len; i++) {
356                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
357                             }
358                         } else {
359                             buf.push(k, "=&");
360                         }
361                 }
362             }
363             buf.pop();
364             return buf.join("");
365         },
366          /**
367          * Safe version of encodeURIComponent
368          * @param {String} data 
369          * @return {String} 
370          */
371         
372         encodeURIComponent : function (data)
373         {
374             try {
375                 return encodeURIComponent(data);
376             } catch(e) {} // should be an uri encode error.
377             
378             if (data == '' || data == null){
379                return '';
380             }
381             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
382             function nibble_to_hex(nibble){
383                 var chars = '0123456789ABCDEF';
384                 return chars.charAt(nibble);
385             }
386             data = data.toString();
387             var buffer = '';
388             for(var i=0; i<data.length; i++){
389                 var c = data.charCodeAt(i);
390                 var bs = new Array();
391                 if (c > 0x10000){
392                         // 4 bytes
393                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
394                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
395                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
396                     bs[3] = 0x80 | (c & 0x3F);
397                 }else if (c > 0x800){
398                          // 3 bytes
399                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
400                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
401                     bs[2] = 0x80 | (c & 0x3F);
402                 }else if (c > 0x80){
403                        // 2 bytes
404                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
405                     bs[1] = 0x80 | (c & 0x3F);
406                 }else{
407                         // 1 byte
408                     bs[0] = c;
409                 }
410                 for(var j=0; j<bs.length; j++){
411                     var b = bs[j];
412                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
413                             + nibble_to_hex(b &0x0F);
414                     buffer += '%'+hex;
415                }
416             }
417             return buffer;    
418              
419         },
420
421         /**
422          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
423          * @param {String} string
424          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
425          * @return {Object} A literal with members
426          */
427         urlDecode : function(string, overwrite){
428             if(!string || !string.length){
429                 return {};
430             }
431             var obj = {};
432             var pairs = string.split('&');
433             var pair, name, value;
434             for(var i = 0, len = pairs.length; i < len; i++){
435                 pair = pairs[i].split('=');
436                 name = decodeURIComponent(pair[0]);
437                 value = decodeURIComponent(pair[1]);
438                 if(overwrite !== true){
439                     if(typeof obj[name] == "undefined"){
440                         obj[name] = value;
441                     }else if(typeof obj[name] == "string"){
442                         obj[name] = [obj[name]];
443                         obj[name].push(value);
444                     }else{
445                         obj[name].push(value);
446                     }
447                 }else{
448                     obj[name] = value;
449                 }
450             }
451             return obj;
452         },
453
454         /**
455          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
456          * passed array is not really an array, your function is called once with it.
457          * The supplied function is called with (Object item, Number index, Array allItems).
458          * @param {Array/NodeList/Mixed} array
459          * @param {Function} fn
460          * @param {Object} scope
461          */
462         each : function(array, fn, scope){
463             if(typeof array.length == "undefined" || typeof array == "string"){
464                 array = [array];
465             }
466             for(var i = 0, len = array.length; i < len; i++){
467                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
468             }
469         },
470
471         // deprecated
472         combine : function(){
473             var as = arguments, l = as.length, r = [];
474             for(var i = 0; i < l; i++){
475                 var a = as[i];
476                 if(a instanceof Array){
477                     r = r.concat(a);
478                 }else if(a.length !== undefined && !a.substr){
479                     r = r.concat(Array.prototype.slice.call(a, 0));
480                 }else{
481                     r.push(a);
482                 }
483             }
484             return r;
485         },
486
487         /**
488          * Escapes the passed string for use in a regular expression
489          * @param {String} str
490          * @return {String}
491          */
492         escapeRe : function(s) {
493             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
494         },
495
496         // internal
497         callback : function(cb, scope, args, delay){
498             if(typeof cb == "function"){
499                 if(delay){
500                     cb.defer(delay, scope, args || []);
501                 }else{
502                     cb.apply(scope, args || []);
503                 }
504             }
505         },
506
507         /**
508          * Return the dom node for the passed string (id), dom node, or Roo.Element
509          * @param {String/HTMLElement/Roo.Element} el
510          * @return HTMLElement
511          */
512         getDom : function(el){
513             if(!el){
514                 return null;
515             }
516             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
517         },
518
519         /**
520         * Shorthand for {@link Roo.ComponentMgr#get}
521         * @param {String} id
522         * @return Roo.Component
523         */
524         getCmp : function(id){
525             return Roo.ComponentMgr.get(id);
526         },
527          
528         num : function(v, defaultValue){
529             if(typeof v != 'number'){
530                 return defaultValue;
531             }
532             return v;
533         },
534
535         destroy : function(){
536             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
537                 var as = a[i];
538                 if(as){
539                     if(as.dom){
540                         as.removeAllListeners();
541                         as.remove();
542                         continue;
543                     }
544                     if(typeof as.purgeListeners == 'function'){
545                         as.purgeListeners();
546                     }
547                     if(typeof as.destroy == 'function'){
548                         as.destroy();
549                     }
550                 }
551             }
552         },
553
554         // inpired by a similar function in mootools library
555         /**
556          * Returns the type of object that is passed in. If the object passed in is null or undefined it
557          * return false otherwise it returns one of the following values:<ul>
558          * <li><b>string</b>: If the object passed is a string</li>
559          * <li><b>number</b>: If the object passed is a number</li>
560          * <li><b>boolean</b>: If the object passed is a boolean value</li>
561          * <li><b>function</b>: If the object passed is a function reference</li>
562          * <li><b>object</b>: If the object passed is an object</li>
563          * <li><b>array</b>: If the object passed is an array</li>
564          * <li><b>regexp</b>: If the object passed is a regular expression</li>
565          * <li><b>element</b>: If the object passed is a DOM Element</li>
566          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
567          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
568          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
569          * @param {Mixed} object
570          * @return {String}
571          */
572         type : function(o){
573             if(o === undefined || o === null){
574                 return false;
575             }
576             if(o.htmlElement){
577                 return 'element';
578             }
579             var t = typeof o;
580             if(t == 'object' && o.nodeName) {
581                 switch(o.nodeType) {
582                     case 1: return 'element';
583                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
584                 }
585             }
586             if(t == 'object' || t == 'function') {
587                 switch(o.constructor) {
588                     case Array: return 'array';
589                     case RegExp: return 'regexp';
590                 }
591                 if(typeof o.length == 'number' && typeof o.item == 'function') {
592                     return 'nodelist';
593                 }
594             }
595             return t;
596         },
597
598         /**
599          * Returns true if the passed value is null, undefined or an empty string (optional).
600          * @param {Mixed} value The value to test
601          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
602          * @return {Boolean}
603          */
604         isEmpty : function(v, allowBlank){
605             return v === null || v === undefined || (!allowBlank ? v === '' : false);
606         },
607         
608         /** @type Boolean */
609         isOpera : isOpera,
610         /** @type Boolean */
611         isSafari : isSafari,
612         /** @type Boolean */
613         isIE : isIE,
614         /** @type Boolean */
615         isIE7 : isIE7,
616         /** @type Boolean */
617         isGecko : isGecko,
618         /** @type Boolean */
619         isBorderBox : isBorderBox,
620         /** @type Boolean */
621         isWindows : isWindows,
622         /** @type Boolean */
623         isLinux : isLinux,
624         /** @type Boolean */
625         isMac : isMac,
626         /** @type Boolean */
627         isTouch : isTouch,
628
629         /**
630          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
631          * you may want to set this to true.
632          * @type Boolean
633          */
634         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
635         
636         
637                 
638         /**
639          * Selects a single element as a Roo Element
640          * This is about as close as you can get to jQuery's $('do crazy stuff')
641          * @param {String} selector The selector/xpath query
642          * @param {Node} root (optional) The start of the query (defaults to document).
643          * @return {Roo.Element}
644          */
645         selectNode : function(selector, root) 
646         {
647             var node = Roo.DomQuery.selectNode(selector,root);
648             return node ? Roo.get(node) : new Roo.Element(false);
649         }
650         
651     });
652
653
654 })();
655
656 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
657                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
658                 "Roo.app", "Roo.ux",
659                 "Roo.bootstrap",
660                 "Roo.bootstrap.dash");
661 /*
662  * Based on:
663  * Ext JS Library 1.1.1
664  * Copyright(c) 2006-2007, Ext JS, LLC.
665  *
666  * Originally Released Under LGPL - original licence link has changed is not relivant.
667  *
668  * Fork - LGPL
669  * <script type="text/javascript">
670  */
671
672 (function() {    
673     // wrappedn so fnCleanup is not in global scope...
674     if(Roo.isIE) {
675         function fnCleanUp() {
676             var p = Function.prototype;
677             delete p.createSequence;
678             delete p.defer;
679             delete p.createDelegate;
680             delete p.createCallback;
681             delete p.createInterceptor;
682
683             window.detachEvent("onunload", fnCleanUp);
684         }
685         window.attachEvent("onunload", fnCleanUp);
686     }
687 })();
688
689
690 /**
691  * @class Function
692  * These functions are available on every Function object (any JavaScript function).
693  */
694 Roo.apply(Function.prototype, {
695      /**
696      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
697      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
698      * Will create a function that is bound to those 2 args.
699      * @return {Function} The new function
700     */
701     createCallback : function(/*args...*/){
702         // make args available, in function below
703         var args = arguments;
704         var method = this;
705         return function() {
706             return method.apply(window, args);
707         };
708     },
709
710     /**
711      * Creates a delegate (callback) that sets the scope to obj.
712      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
713      * Will create a function that is automatically scoped to this.
714      * @param {Object} obj (optional) The object for which the scope is set
715      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
716      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
717      *                                             if a number the args are inserted at the specified position
718      * @return {Function} The new function
719      */
720     createDelegate : function(obj, args, appendArgs){
721         var method = this;
722         return function() {
723             var callArgs = args || arguments;
724             if(appendArgs === true){
725                 callArgs = Array.prototype.slice.call(arguments, 0);
726                 callArgs = callArgs.concat(args);
727             }else if(typeof appendArgs == "number"){
728                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
729                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
730                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
731             }
732             return method.apply(obj || window, callArgs);
733         };
734     },
735
736     /**
737      * Calls this function after the number of millseconds specified.
738      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
739      * @param {Object} obj (optional) The object for which the scope is set
740      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
741      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
742      *                                             if a number the args are inserted at the specified position
743      * @return {Number} The timeout id that can be used with clearTimeout
744      */
745     defer : function(millis, obj, args, appendArgs){
746         var fn = this.createDelegate(obj, args, appendArgs);
747         if(millis){
748             return setTimeout(fn, millis);
749         }
750         fn();
751         return 0;
752     },
753     /**
754      * Create a combined function call sequence of the original function + the passed function.
755      * The resulting function returns the results of the original function.
756      * The passed fcn is called with the parameters of the original function
757      * @param {Function} fcn The function to sequence
758      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
759      * @return {Function} The new function
760      */
761     createSequence : function(fcn, scope){
762         if(typeof fcn != "function"){
763             return this;
764         }
765         var method = this;
766         return function() {
767             var retval = method.apply(this || window, arguments);
768             fcn.apply(scope || this || window, arguments);
769             return retval;
770         };
771     },
772
773     /**
774      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
775      * The resulting function returns the results of the original function.
776      * The passed fcn is called with the parameters of the original function.
777      * @addon
778      * @param {Function} fcn The function to call before the original
779      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
780      * @return {Function} The new function
781      */
782     createInterceptor : function(fcn, scope){
783         if(typeof fcn != "function"){
784             return this;
785         }
786         var method = this;
787         return function() {
788             fcn.target = this;
789             fcn.method = method;
790             if(fcn.apply(scope || this || window, arguments) === false){
791                 return;
792             }
793             return method.apply(this || window, arguments);
794         };
795     }
796 });
797 /*
798  * Based on:
799  * Ext JS Library 1.1.1
800  * Copyright(c) 2006-2007, Ext JS, LLC.
801  *
802  * Originally Released Under LGPL - original licence link has changed is not relivant.
803  *
804  * Fork - LGPL
805  * <script type="text/javascript">
806  */
807
808 Roo.applyIf(String, {
809     
810     /** @scope String */
811     
812     /**
813      * Escapes the passed string for ' and \
814      * @param {String} string The string to escape
815      * @return {String} The escaped string
816      * @static
817      */
818     escape : function(string) {
819         return string.replace(/('|\\)/g, "\\$1");
820     },
821
822     /**
823      * Pads the left side of a string with a specified character.  This is especially useful
824      * for normalizing number and date strings.  Example usage:
825      * <pre><code>
826 var s = String.leftPad('123', 5, '0');
827 // s now contains the string: '00123'
828 </code></pre>
829      * @param {String} string The original string
830      * @param {Number} size The total length of the output string
831      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
832      * @return {String} The padded string
833      * @static
834      */
835     leftPad : function (val, size, ch) {
836         var result = new String(val);
837         if(ch === null || ch === undefined || ch === '') {
838             ch = " ";
839         }
840         while (result.length < size) {
841             result = ch + result;
842         }
843         return result;
844     },
845
846     /**
847      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
848      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
849      * <pre><code>
850 var cls = 'my-class', text = 'Some text';
851 var s = String.format('<div class="{0}">{1}</div>', cls, text);
852 // s now contains the string: '<div class="my-class">Some text</div>'
853 </code></pre>
854      * @param {String} string The tokenized string to be formatted
855      * @param {String} value1 The value to replace token {0}
856      * @param {String} value2 Etc...
857      * @return {String} The formatted string
858      * @static
859      */
860     format : function(format){
861         var args = Array.prototype.slice.call(arguments, 1);
862         return format.replace(/\{(\d+)\}/g, function(m, i){
863             return Roo.util.Format.htmlEncode(args[i]);
864         });
865     }
866 });
867
868 /**
869  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
870  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
871  * they are already different, the first value passed in is returned.  Note that this method returns the new value
872  * but does not change the current string.
873  * <pre><code>
874 // alternate sort directions
875 sort = sort.toggle('ASC', 'DESC');
876
877 // instead of conditional logic:
878 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
879 </code></pre>
880  * @param {String} value The value to compare to the current string
881  * @param {String} other The new value to use if the string already equals the first value passed in
882  * @return {String} The new value
883  */
884  
885 String.prototype.toggle = function(value, other){
886     return this == value ? other : value;
887 };/*
888  * Based on:
889  * Ext JS Library 1.1.1
890  * Copyright(c) 2006-2007, Ext JS, LLC.
891  *
892  * Originally Released Under LGPL - original licence link has changed is not relivant.
893  *
894  * Fork - LGPL
895  * <script type="text/javascript">
896  */
897
898  /**
899  * @class Number
900  */
901 Roo.applyIf(Number.prototype, {
902     /**
903      * Checks whether or not the current number is within a desired range.  If the number is already within the
904      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
905      * exceeded.  Note that this method returns the constrained value but does not change the current number.
906      * @param {Number} min The minimum number in the range
907      * @param {Number} max The maximum number in the range
908      * @return {Number} The constrained value if outside the range, otherwise the current value
909      */
910     constrain : function(min, max){
911         return Math.min(Math.max(this, min), max);
912     }
913 });/*
914  * Based on:
915  * Ext JS Library 1.1.1
916  * Copyright(c) 2006-2007, Ext JS, LLC.
917  *
918  * Originally Released Under LGPL - original licence link has changed is not relivant.
919  *
920  * Fork - LGPL
921  * <script type="text/javascript">
922  */
923  /**
924  * @class Array
925  */
926 Roo.applyIf(Array.prototype, {
927     /**
928      * 
929      * Checks whether or not the specified object exists in the array.
930      * @param {Object} o The object to check for
931      * @return {Number} The index of o in the array (or -1 if it is not found)
932      */
933     indexOf : function(o){
934        for (var i = 0, len = this.length; i < len; i++){
935               if(this[i] == o) return i;
936        }
937            return -1;
938     },
939
940     /**
941      * Removes the specified object from the array.  If the object is not found nothing happens.
942      * @param {Object} o The object to remove
943      */
944     remove : function(o){
945        var index = this.indexOf(o);
946        if(index != -1){
947            this.splice(index, 1);
948        }
949     },
950     /**
951      * Map (JS 1.6 compatibility)
952      * @param {Function} function  to call
953      */
954     map : function(fun )
955     {
956         var len = this.length >>> 0;
957         if (typeof fun != "function")
958             throw new TypeError();
959
960         var res = new Array(len);
961         var thisp = arguments[1];
962         for (var i = 0; i < len; i++)
963         {
964             if (i in this)
965                 res[i] = fun.call(thisp, this[i], i, this);
966         }
967
968         return res;
969     }
970     
971 });
972
973
974  /*
975  * Based on:
976  * Ext JS Library 1.1.1
977  * Copyright(c) 2006-2007, Ext JS, LLC.
978  *
979  * Originally Released Under LGPL - original licence link has changed is not relivant.
980  *
981  * Fork - LGPL
982  * <script type="text/javascript">
983  */
984
985 /**
986  * @class Date
987  *
988  * The date parsing and format syntax is a subset of
989  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
990  * supported will provide results equivalent to their PHP versions.
991  *
992  * Following is the list of all currently supported formats:
993  *<pre>
994 Sample date:
995 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
996
997 Format  Output      Description
998 ------  ----------  --------------------------------------------------------------
999   d      10         Day of the month, 2 digits with leading zeros
1000   D      Wed        A textual representation of a day, three letters
1001   j      10         Day of the month without leading zeros
1002   l      Wednesday  A full textual representation of the day of the week
1003   S      th         English ordinal day of month suffix, 2 chars (use with j)
1004   w      3          Numeric representation of the day of the week
1005   z      9          The julian date, or day of the year (0-365)
1006   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1007   F      January    A full textual representation of the month
1008   m      01         Numeric representation of a month, with leading zeros
1009   M      Jan        Month name abbreviation, three letters
1010   n      1          Numeric representation of a month, without leading zeros
1011   t      31         Number of days in the given month
1012   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1013   Y      2007       A full numeric representation of a year, 4 digits
1014   y      07         A two digit representation of a year
1015   a      pm         Lowercase Ante meridiem and Post meridiem
1016   A      PM         Uppercase Ante meridiem and Post meridiem
1017   g      3          12-hour format of an hour without leading zeros
1018   G      15         24-hour format of an hour without leading zeros
1019   h      03         12-hour format of an hour with leading zeros
1020   H      15         24-hour format of an hour with leading zeros
1021   i      05         Minutes with leading zeros
1022   s      01         Seconds, with leading zeros
1023   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1024   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1025   T      CST        Timezone setting of the machine running the code
1026   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1027 </pre>
1028  *
1029  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1030  * <pre><code>
1031 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1032 document.write(dt.format('Y-m-d'));                         //2007-01-10
1033 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1034 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
1035  </code></pre>
1036  *
1037  * Here are some standard date/time patterns that you might find helpful.  They
1038  * are not part of the source of Date.js, but to use them you can simply copy this
1039  * block of code into any script that is included after Date.js and they will also become
1040  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1041  * <pre><code>
1042 Date.patterns = {
1043     ISO8601Long:"Y-m-d H:i:s",
1044     ISO8601Short:"Y-m-d",
1045     ShortDate: "n/j/Y",
1046     LongDate: "l, F d, Y",
1047     FullDateTime: "l, F d, Y g:i:s A",
1048     MonthDay: "F d",
1049     ShortTime: "g:i A",
1050     LongTime: "g:i:s A",
1051     SortableDateTime: "Y-m-d\\TH:i:s",
1052     UniversalSortableDateTime: "Y-m-d H:i:sO",
1053     YearMonth: "F, Y"
1054 };
1055 </code></pre>
1056  *
1057  * Example usage:
1058  * <pre><code>
1059 var dt = new Date();
1060 document.write(dt.format(Date.patterns.ShortDate));
1061  </code></pre>
1062  */
1063
1064 /*
1065  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1066  * They generate precompiled functions from date formats instead of parsing and
1067  * processing the pattern every time you format a date.  These functions are available
1068  * on every Date object (any javascript function).
1069  *
1070  * The original article and download are here:
1071  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1072  *
1073  */
1074  
1075  
1076  // was in core
1077 /**
1078  Returns the number of milliseconds between this date and date
1079  @param {Date} date (optional) Defaults to now
1080  @return {Number} The diff in milliseconds
1081  @member Date getElapsed
1082  */
1083 Date.prototype.getElapsed = function(date) {
1084         return Math.abs((date || new Date()).getTime()-this.getTime());
1085 };
1086 // was in date file..
1087
1088
1089 // private
1090 Date.parseFunctions = {count:0};
1091 // private
1092 Date.parseRegexes = [];
1093 // private
1094 Date.formatFunctions = {count:0};
1095
1096 // private
1097 Date.prototype.dateFormat = function(format) {
1098     if (Date.formatFunctions[format] == null) {
1099         Date.createNewFormat(format);
1100     }
1101     var func = Date.formatFunctions[format];
1102     return this[func]();
1103 };
1104
1105
1106 /**
1107  * Formats a date given the supplied format string
1108  * @param {String} format The format string
1109  * @return {String} The formatted date
1110  * @method
1111  */
1112 Date.prototype.format = Date.prototype.dateFormat;
1113
1114 // private
1115 Date.createNewFormat = function(format) {
1116     var funcName = "format" + Date.formatFunctions.count++;
1117     Date.formatFunctions[format] = funcName;
1118     var code = "Date.prototype." + funcName + " = function(){return ";
1119     var special = false;
1120     var ch = '';
1121     for (var i = 0; i < format.length; ++i) {
1122         ch = format.charAt(i);
1123         if (!special && ch == "\\") {
1124             special = true;
1125         }
1126         else if (special) {
1127             special = false;
1128             code += "'" + String.escape(ch) + "' + ";
1129         }
1130         else {
1131             code += Date.getFormatCode(ch);
1132         }
1133     }
1134     /** eval:var:zzzzzzzzzzzzz */
1135     eval(code.substring(0, code.length - 3) + ";}");
1136 };
1137
1138 // private
1139 Date.getFormatCode = function(character) {
1140     switch (character) {
1141     case "d":
1142         return "String.leftPad(this.getDate(), 2, '0') + ";
1143     case "D":
1144         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1145     case "j":
1146         return "this.getDate() + ";
1147     case "l":
1148         return "Date.dayNames[this.getDay()] + ";
1149     case "S":
1150         return "this.getSuffix() + ";
1151     case "w":
1152         return "this.getDay() + ";
1153     case "z":
1154         return "this.getDayOfYear() + ";
1155     case "W":
1156         return "this.getWeekOfYear() + ";
1157     case "F":
1158         return "Date.monthNames[this.getMonth()] + ";
1159     case "m":
1160         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1161     case "M":
1162         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1163     case "n":
1164         return "(this.getMonth() + 1) + ";
1165     case "t":
1166         return "this.getDaysInMonth() + ";
1167     case "L":
1168         return "(this.isLeapYear() ? 1 : 0) + ";
1169     case "Y":
1170         return "this.getFullYear() + ";
1171     case "y":
1172         return "('' + this.getFullYear()).substring(2, 4) + ";
1173     case "a":
1174         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1175     case "A":
1176         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1177     case "g":
1178         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1179     case "G":
1180         return "this.getHours() + ";
1181     case "h":
1182         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1183     case "H":
1184         return "String.leftPad(this.getHours(), 2, '0') + ";
1185     case "i":
1186         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1187     case "s":
1188         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1189     case "O":
1190         return "this.getGMTOffset() + ";
1191     case "P":
1192         return "this.getGMTColonOffset() + ";
1193     case "T":
1194         return "this.getTimezone() + ";
1195     case "Z":
1196         return "(this.getTimezoneOffset() * -60) + ";
1197     default:
1198         return "'" + String.escape(character) + "' + ";
1199     }
1200 };
1201
1202 /**
1203  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1204  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1205  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1206  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1207  * string or the parse operation will fail.
1208  * Example Usage:
1209 <pre><code>
1210 //dt = Fri May 25 2007 (current date)
1211 var dt = new Date();
1212
1213 //dt = Thu May 25 2006 (today's month/day in 2006)
1214 dt = Date.parseDate("2006", "Y");
1215
1216 //dt = Sun Jan 15 2006 (all date parts specified)
1217 dt = Date.parseDate("2006-1-15", "Y-m-d");
1218
1219 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1220 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1221 </code></pre>
1222  * @param {String} input The unparsed date as a string
1223  * @param {String} format The format the date is in
1224  * @return {Date} The parsed date
1225  * @static
1226  */
1227 Date.parseDate = function(input, format) {
1228     if (Date.parseFunctions[format] == null) {
1229         Date.createParser(format);
1230     }
1231     var func = Date.parseFunctions[format];
1232     return Date[func](input);
1233 };
1234 /**
1235  * @private
1236  */
1237
1238 Date.createParser = function(format) {
1239     var funcName = "parse" + Date.parseFunctions.count++;
1240     var regexNum = Date.parseRegexes.length;
1241     var currentGroup = 1;
1242     Date.parseFunctions[format] = funcName;
1243
1244     var code = "Date." + funcName + " = function(input){\n"
1245         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1246         + "var d = new Date();\n"
1247         + "y = d.getFullYear();\n"
1248         + "m = d.getMonth();\n"
1249         + "d = d.getDate();\n"
1250         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1251         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1252         + "if (results && results.length > 0) {";
1253     var regex = "";
1254
1255     var special = false;
1256     var ch = '';
1257     for (var i = 0; i < format.length; ++i) {
1258         ch = format.charAt(i);
1259         if (!special && ch == "\\") {
1260             special = true;
1261         }
1262         else if (special) {
1263             special = false;
1264             regex += String.escape(ch);
1265         }
1266         else {
1267             var obj = Date.formatCodeToRegex(ch, currentGroup);
1268             currentGroup += obj.g;
1269             regex += obj.s;
1270             if (obj.g && obj.c) {
1271                 code += obj.c;
1272             }
1273         }
1274     }
1275
1276     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1277         + "{v = new Date(y, m, d, h, i, s);}\n"
1278         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1279         + "{v = new Date(y, m, d, h, i);}\n"
1280         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1281         + "{v = new Date(y, m, d, h);}\n"
1282         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1283         + "{v = new Date(y, m, d);}\n"
1284         + "else if (y >= 0 && m >= 0)\n"
1285         + "{v = new Date(y, m);}\n"
1286         + "else if (y >= 0)\n"
1287         + "{v = new Date(y);}\n"
1288         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1289         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1290         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1291         + ";}";
1292
1293     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1294     /** eval:var:zzzzzzzzzzzzz */
1295     eval(code);
1296 };
1297
1298 // private
1299 Date.formatCodeToRegex = function(character, currentGroup) {
1300     switch (character) {
1301     case "D":
1302         return {g:0,
1303         c:null,
1304         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1305     case "j":
1306         return {g:1,
1307             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1308             s:"(\\d{1,2})"}; // day of month without leading zeroes
1309     case "d":
1310         return {g:1,
1311             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1312             s:"(\\d{2})"}; // day of month with leading zeroes
1313     case "l":
1314         return {g:0,
1315             c:null,
1316             s:"(?:" + Date.dayNames.join("|") + ")"};
1317     case "S":
1318         return {g:0,
1319             c:null,
1320             s:"(?:st|nd|rd|th)"};
1321     case "w":
1322         return {g:0,
1323             c:null,
1324             s:"\\d"};
1325     case "z":
1326         return {g:0,
1327             c:null,
1328             s:"(?:\\d{1,3})"};
1329     case "W":
1330         return {g:0,
1331             c:null,
1332             s:"(?:\\d{2})"};
1333     case "F":
1334         return {g:1,
1335             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1336             s:"(" + Date.monthNames.join("|") + ")"};
1337     case "M":
1338         return {g:1,
1339             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1340             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1341     case "n":
1342         return {g:1,
1343             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1344             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1345     case "m":
1346         return {g:1,
1347             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1348             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1349     case "t":
1350         return {g:0,
1351             c:null,
1352             s:"\\d{1,2}"};
1353     case "L":
1354         return {g:0,
1355             c:null,
1356             s:"(?:1|0)"};
1357     case "Y":
1358         return {g:1,
1359             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1360             s:"(\\d{4})"};
1361     case "y":
1362         return {g:1,
1363             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1364                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1365             s:"(\\d{1,2})"};
1366     case "a":
1367         return {g:1,
1368             c:"if (results[" + currentGroup + "] == 'am') {\n"
1369                 + "if (h == 12) { h = 0; }\n"
1370                 + "} else { if (h < 12) { h += 12; }}",
1371             s:"(am|pm)"};
1372     case "A":
1373         return {g:1,
1374             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1375                 + "if (h == 12) { h = 0; }\n"
1376                 + "} else { if (h < 12) { h += 12; }}",
1377             s:"(AM|PM)"};
1378     case "g":
1379     case "G":
1380         return {g:1,
1381             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1382             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1383     case "h":
1384     case "H":
1385         return {g:1,
1386             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1387             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1388     case "i":
1389         return {g:1,
1390             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1391             s:"(\\d{2})"};
1392     case "s":
1393         return {g:1,
1394             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1395             s:"(\\d{2})"};
1396     case "O":
1397         return {g:1,
1398             c:[
1399                 "o = results[", currentGroup, "];\n",
1400                 "var sn = o.substring(0,1);\n", // get + / - sign
1401                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1402                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1403                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1404                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1405             ].join(""),
1406             s:"([+\-]\\d{2,4})"};
1407     
1408     
1409     case "P":
1410         return {g:1,
1411                 c:[
1412                    "o = results[", currentGroup, "];\n",
1413                    "var sn = o.substring(0,1);\n",
1414                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1415                    "var mn = o.substring(4,6) % 60;\n",
1416                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1417                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1418             ].join(""),
1419             s:"([+\-]\\d{4})"};
1420     case "T":
1421         return {g:0,
1422             c:null,
1423             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1424     case "Z":
1425         return {g:1,
1426             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1427                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1428             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1429     default:
1430         return {g:0,
1431             c:null,
1432             s:String.escape(character)};
1433     }
1434 };
1435
1436 /**
1437  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1438  * @return {String} The abbreviated timezone name (e.g. 'CST')
1439  */
1440 Date.prototype.getTimezone = function() {
1441     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1442 };
1443
1444 /**
1445  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1446  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1447  */
1448 Date.prototype.getGMTOffset = function() {
1449     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1450         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1451         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1452 };
1453
1454 /**
1455  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1456  * @return {String} 2-characters representing hours and 2-characters representing minutes
1457  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1458  */
1459 Date.prototype.getGMTColonOffset = function() {
1460         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1461                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1462                 + ":"
1463                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1464 }
1465
1466 /**
1467  * Get the numeric day number of the year, adjusted for leap year.
1468  * @return {Number} 0 through 364 (365 in leap years)
1469  */
1470 Date.prototype.getDayOfYear = function() {
1471     var num = 0;
1472     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1473     for (var i = 0; i < this.getMonth(); ++i) {
1474         num += Date.daysInMonth[i];
1475     }
1476     return num + this.getDate() - 1;
1477 };
1478
1479 /**
1480  * Get the string representation of the numeric week number of the year
1481  * (equivalent to the format specifier 'W').
1482  * @return {String} '00' through '52'
1483  */
1484 Date.prototype.getWeekOfYear = function() {
1485     // Skip to Thursday of this week
1486     var now = this.getDayOfYear() + (4 - this.getDay());
1487     // Find the first Thursday of the year
1488     var jan1 = new Date(this.getFullYear(), 0, 1);
1489     var then = (7 - jan1.getDay() + 4);
1490     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1491 };
1492
1493 /**
1494  * Whether or not the current date is in a leap year.
1495  * @return {Boolean} True if the current date is in a leap year, else false
1496  */
1497 Date.prototype.isLeapYear = function() {
1498     var year = this.getFullYear();
1499     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1500 };
1501
1502 /**
1503  * Get the first day of the current month, adjusted for leap year.  The returned value
1504  * is the numeric day index within the week (0-6) which can be used in conjunction with
1505  * the {@link #monthNames} array to retrieve the textual day name.
1506  * Example:
1507  *<pre><code>
1508 var dt = new Date('1/10/2007');
1509 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1510 </code></pre>
1511  * @return {Number} The day number (0-6)
1512  */
1513 Date.prototype.getFirstDayOfMonth = function() {
1514     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1515     return (day < 0) ? (day + 7) : day;
1516 };
1517
1518 /**
1519  * Get the last day of the current month, adjusted for leap year.  The returned value
1520  * is the numeric day index within the week (0-6) which can be used in conjunction with
1521  * the {@link #monthNames} array to retrieve the textual day name.
1522  * Example:
1523  *<pre><code>
1524 var dt = new Date('1/10/2007');
1525 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1526 </code></pre>
1527  * @return {Number} The day number (0-6)
1528  */
1529 Date.prototype.getLastDayOfMonth = function() {
1530     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1531     return (day < 0) ? (day + 7) : day;
1532 };
1533
1534
1535 /**
1536  * Get the first date of this date's month
1537  * @return {Date}
1538  */
1539 Date.prototype.getFirstDateOfMonth = function() {
1540     return new Date(this.getFullYear(), this.getMonth(), 1);
1541 };
1542
1543 /**
1544  * Get the last date of this date's month
1545  * @return {Date}
1546  */
1547 Date.prototype.getLastDateOfMonth = function() {
1548     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1549 };
1550 /**
1551  * Get the number of days in the current month, adjusted for leap year.
1552  * @return {Number} The number of days in the month
1553  */
1554 Date.prototype.getDaysInMonth = function() {
1555     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1556     return Date.daysInMonth[this.getMonth()];
1557 };
1558
1559 /**
1560  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1561  * @return {String} 'st, 'nd', 'rd' or 'th'
1562  */
1563 Date.prototype.getSuffix = function() {
1564     switch (this.getDate()) {
1565         case 1:
1566         case 21:
1567         case 31:
1568             return "st";
1569         case 2:
1570         case 22:
1571             return "nd";
1572         case 3:
1573         case 23:
1574             return "rd";
1575         default:
1576             return "th";
1577     }
1578 };
1579
1580 // private
1581 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1582
1583 /**
1584  * An array of textual month names.
1585  * Override these values for international dates, for example...
1586  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1587  * @type Array
1588  * @static
1589  */
1590 Date.monthNames =
1591    ["January",
1592     "February",
1593     "March",
1594     "April",
1595     "May",
1596     "June",
1597     "July",
1598     "August",
1599     "September",
1600     "October",
1601     "November",
1602     "December"];
1603
1604 /**
1605  * An array of textual day names.
1606  * Override these values for international dates, for example...
1607  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1608  * @type Array
1609  * @static
1610  */
1611 Date.dayNames =
1612    ["Sunday",
1613     "Monday",
1614     "Tuesday",
1615     "Wednesday",
1616     "Thursday",
1617     "Friday",
1618     "Saturday"];
1619
1620 // private
1621 Date.y2kYear = 50;
1622 // private
1623 Date.monthNumbers = {
1624     Jan:0,
1625     Feb:1,
1626     Mar:2,
1627     Apr:3,
1628     May:4,
1629     Jun:5,
1630     Jul:6,
1631     Aug:7,
1632     Sep:8,
1633     Oct:9,
1634     Nov:10,
1635     Dec:11};
1636
1637 /**
1638  * Creates and returns a new Date instance with the exact same date value as the called instance.
1639  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1640  * variable will also be changed.  When the intention is to create a new variable that will not
1641  * modify the original instance, you should create a clone.
1642  *
1643  * Example of correctly cloning a date:
1644  * <pre><code>
1645 //wrong way:
1646 var orig = new Date('10/1/2006');
1647 var copy = orig;
1648 copy.setDate(5);
1649 document.write(orig);  //returns 'Thu Oct 05 2006'!
1650
1651 //correct way:
1652 var orig = new Date('10/1/2006');
1653 var copy = orig.clone();
1654 copy.setDate(5);
1655 document.write(orig);  //returns 'Thu Oct 01 2006'
1656 </code></pre>
1657  * @return {Date} The new Date instance
1658  */
1659 Date.prototype.clone = function() {
1660         return new Date(this.getTime());
1661 };
1662
1663 /**
1664  * Clears any time information from this date
1665  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1666  @return {Date} this or the clone
1667  */
1668 Date.prototype.clearTime = function(clone){
1669     if(clone){
1670         return this.clone().clearTime();
1671     }
1672     this.setHours(0);
1673     this.setMinutes(0);
1674     this.setSeconds(0);
1675     this.setMilliseconds(0);
1676     return this;
1677 };
1678
1679 // private
1680 // safari setMonth is broken
1681 if(Roo.isSafari){
1682     Date.brokenSetMonth = Date.prototype.setMonth;
1683         Date.prototype.setMonth = function(num){
1684                 if(num <= -1){
1685                         var n = Math.ceil(-num);
1686                         var back_year = Math.ceil(n/12);
1687                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1688                         this.setFullYear(this.getFullYear() - back_year);
1689                         return Date.brokenSetMonth.call(this, month);
1690                 } else {
1691                         return Date.brokenSetMonth.apply(this, arguments);
1692                 }
1693         };
1694 }
1695
1696 /** Date interval constant 
1697 * @static 
1698 * @type String */
1699 Date.MILLI = "ms";
1700 /** Date interval constant 
1701 * @static 
1702 * @type String */
1703 Date.SECOND = "s";
1704 /** Date interval constant 
1705 * @static 
1706 * @type String */
1707 Date.MINUTE = "mi";
1708 /** Date interval constant 
1709 * @static 
1710 * @type String */
1711 Date.HOUR = "h";
1712 /** Date interval constant 
1713 * @static 
1714 * @type String */
1715 Date.DAY = "d";
1716 /** Date interval constant 
1717 * @static 
1718 * @type String */
1719 Date.MONTH = "mo";
1720 /** Date interval constant 
1721 * @static 
1722 * @type String */
1723 Date.YEAR = "y";
1724
1725 /**
1726  * Provides a convenient method of performing basic date arithmetic.  This method
1727  * does not modify the Date instance being called - it creates and returns
1728  * a new Date instance containing the resulting date value.
1729  *
1730  * Examples:
1731  * <pre><code>
1732 //Basic usage:
1733 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1734 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1735
1736 //Negative values will subtract correctly:
1737 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1738 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1739
1740 //You can even chain several calls together in one line!
1741 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1742 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1743  </code></pre>
1744  *
1745  * @param {String} interval   A valid date interval enum value
1746  * @param {Number} value      The amount to add to the current date
1747  * @return {Date} The new Date instance
1748  */
1749 Date.prototype.add = function(interval, value){
1750   var d = this.clone();
1751   if (!interval || value === 0) return d;
1752   switch(interval.toLowerCase()){
1753     case Date.MILLI:
1754       d.setMilliseconds(this.getMilliseconds() + value);
1755       break;
1756     case Date.SECOND:
1757       d.setSeconds(this.getSeconds() + value);
1758       break;
1759     case Date.MINUTE:
1760       d.setMinutes(this.getMinutes() + value);
1761       break;
1762     case Date.HOUR:
1763       d.setHours(this.getHours() + value);
1764       break;
1765     case Date.DAY:
1766       d.setDate(this.getDate() + value);
1767       break;
1768     case Date.MONTH:
1769       var day = this.getDate();
1770       if(day > 28){
1771           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1772       }
1773       d.setDate(day);
1774       d.setMonth(this.getMonth() + value);
1775       break;
1776     case Date.YEAR:
1777       d.setFullYear(this.getFullYear() + value);
1778       break;
1779   }
1780   return d;
1781 };
1782 /*
1783  * Based on:
1784  * Ext JS Library 1.1.1
1785  * Copyright(c) 2006-2007, Ext JS, LLC.
1786  *
1787  * Originally Released Under LGPL - original licence link has changed is not relivant.
1788  *
1789  * Fork - LGPL
1790  * <script type="text/javascript">
1791  */
1792
1793 /**
1794  * @class Roo.lib.Dom
1795  * @static
1796  * 
1797  * Dom utils (from YIU afaik)
1798  * 
1799  **/
1800 Roo.lib.Dom = {
1801     /**
1802      * Get the view width
1803      * @param {Boolean} full True will get the full document, otherwise it's the view width
1804      * @return {Number} The width
1805      */
1806      
1807     getViewWidth : function(full) {
1808         return full ? this.getDocumentWidth() : this.getViewportWidth();
1809     },
1810     /**
1811      * Get the view height
1812      * @param {Boolean} full True will get the full document, otherwise it's the view height
1813      * @return {Number} The height
1814      */
1815     getViewHeight : function(full) {
1816         return full ? this.getDocumentHeight() : this.getViewportHeight();
1817     },
1818
1819     getDocumentHeight: function() {
1820         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1821         return Math.max(scrollHeight, this.getViewportHeight());
1822     },
1823
1824     getDocumentWidth: function() {
1825         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1826         return Math.max(scrollWidth, this.getViewportWidth());
1827     },
1828
1829     getViewportHeight: function() {
1830         var height = self.innerHeight;
1831         var mode = document.compatMode;
1832
1833         if ((mode || Roo.isIE) && !Roo.isOpera) {
1834             height = (mode == "CSS1Compat") ?
1835                      document.documentElement.clientHeight :
1836                      document.body.clientHeight;
1837         }
1838
1839         return height;
1840     },
1841
1842     getViewportWidth: function() {
1843         var width = self.innerWidth;
1844         var mode = document.compatMode;
1845
1846         if (mode || Roo.isIE) {
1847             width = (mode == "CSS1Compat") ?
1848                     document.documentElement.clientWidth :
1849                     document.body.clientWidth;
1850         }
1851         return width;
1852     },
1853
1854     isAncestor : function(p, c) {
1855         p = Roo.getDom(p);
1856         c = Roo.getDom(c);
1857         if (!p || !c) {
1858             return false;
1859         }
1860
1861         if (p.contains && !Roo.isSafari) {
1862             return p.contains(c);
1863         } else if (p.compareDocumentPosition) {
1864             return !!(p.compareDocumentPosition(c) & 16);
1865         } else {
1866             var parent = c.parentNode;
1867             while (parent) {
1868                 if (parent == p) {
1869                     return true;
1870                 }
1871                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1872                     return false;
1873                 }
1874                 parent = parent.parentNode;
1875             }
1876             return false;
1877         }
1878     },
1879
1880     getRegion : function(el) {
1881         return Roo.lib.Region.getRegion(el);
1882     },
1883
1884     getY : function(el) {
1885         return this.getXY(el)[1];
1886     },
1887
1888     getX : function(el) {
1889         return this.getXY(el)[0];
1890     },
1891
1892     getXY : function(el) {
1893         var p, pe, b, scroll, bd = document.body;
1894         el = Roo.getDom(el);
1895         var fly = Roo.lib.AnimBase.fly;
1896         if (el.getBoundingClientRect) {
1897             b = el.getBoundingClientRect();
1898             scroll = fly(document).getScroll();
1899             return [b.left + scroll.left, b.top + scroll.top];
1900         }
1901         var x = 0, y = 0;
1902
1903         p = el;
1904
1905         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1906
1907         while (p) {
1908
1909             x += p.offsetLeft;
1910             y += p.offsetTop;
1911
1912             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1913                 hasAbsolute = true;
1914             }
1915
1916             if (Roo.isGecko) {
1917                 pe = fly(p);
1918
1919                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1920                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1921
1922
1923                 x += bl;
1924                 y += bt;
1925
1926
1927                 if (p != el && pe.getStyle('overflow') != 'visible') {
1928                     x += bl;
1929                     y += bt;
1930                 }
1931             }
1932             p = p.offsetParent;
1933         }
1934
1935         if (Roo.isSafari && hasAbsolute) {
1936             x -= bd.offsetLeft;
1937             y -= bd.offsetTop;
1938         }
1939
1940         if (Roo.isGecko && !hasAbsolute) {
1941             var dbd = fly(bd);
1942             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1943             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1944         }
1945
1946         p = el.parentNode;
1947         while (p && p != bd) {
1948             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1949                 x -= p.scrollLeft;
1950                 y -= p.scrollTop;
1951             }
1952             p = p.parentNode;
1953         }
1954         return [x, y];
1955     },
1956  
1957   
1958
1959
1960     setXY : function(el, xy) {
1961         el = Roo.fly(el, '_setXY');
1962         el.position();
1963         var pts = el.translatePoints(xy);
1964         if (xy[0] !== false) {
1965             el.dom.style.left = pts.left + "px";
1966         }
1967         if (xy[1] !== false) {
1968             el.dom.style.top = pts.top + "px";
1969         }
1970     },
1971
1972     setX : function(el, x) {
1973         this.setXY(el, [x, false]);
1974     },
1975
1976     setY : function(el, y) {
1977         this.setXY(el, [false, y]);
1978     }
1979 };
1980 /*
1981  * Portions of this file are based on pieces of Yahoo User Interface Library
1982  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1983  * YUI licensed under the BSD License:
1984  * http://developer.yahoo.net/yui/license.txt
1985  * <script type="text/javascript">
1986  *
1987  */
1988
1989 Roo.lib.Event = function() {
1990     var loadComplete = false;
1991     var listeners = [];
1992     var unloadListeners = [];
1993     var retryCount = 0;
1994     var onAvailStack = [];
1995     var counter = 0;
1996     var lastError = null;
1997
1998     return {
1999         POLL_RETRYS: 200,
2000         POLL_INTERVAL: 20,
2001         EL: 0,
2002         TYPE: 1,
2003         FN: 2,
2004         WFN: 3,
2005         OBJ: 3,
2006         ADJ_SCOPE: 4,
2007         _interval: null,
2008
2009         startInterval: function() {
2010             if (!this._interval) {
2011                 var self = this;
2012                 var callback = function() {
2013                     self._tryPreloadAttach();
2014                 };
2015                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2016
2017             }
2018         },
2019
2020         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2021             onAvailStack.push({ id:         p_id,
2022                 fn:         p_fn,
2023                 obj:        p_obj,
2024                 override:   p_override,
2025                 checkReady: false    });
2026
2027             retryCount = this.POLL_RETRYS;
2028             this.startInterval();
2029         },
2030
2031
2032         addListener: function(el, eventName, fn) {
2033             el = Roo.getDom(el);
2034             if (!el || !fn) {
2035                 return false;
2036             }
2037
2038             if ("unload" == eventName) {
2039                 unloadListeners[unloadListeners.length] =
2040                 [el, eventName, fn];
2041                 return true;
2042             }
2043
2044             var wrappedFn = function(e) {
2045                 return fn(Roo.lib.Event.getEvent(e));
2046             };
2047
2048             var li = [el, eventName, fn, wrappedFn];
2049
2050             var index = listeners.length;
2051             listeners[index] = li;
2052
2053             this.doAdd(el, eventName, wrappedFn, false);
2054             return true;
2055
2056         },
2057
2058
2059         removeListener: function(el, eventName, fn) {
2060             var i, len;
2061
2062             el = Roo.getDom(el);
2063
2064             if(!fn) {
2065                 return this.purgeElement(el, false, eventName);
2066             }
2067
2068
2069             if ("unload" == eventName) {
2070
2071                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2072                     var li = unloadListeners[i];
2073                     if (li &&
2074                         li[0] == el &&
2075                         li[1] == eventName &&
2076                         li[2] == fn) {
2077                         unloadListeners.splice(i, 1);
2078                         return true;
2079                     }
2080                 }
2081
2082                 return false;
2083             }
2084
2085             var cacheItem = null;
2086
2087
2088             var index = arguments[3];
2089
2090             if ("undefined" == typeof index) {
2091                 index = this._getCacheIndex(el, eventName, fn);
2092             }
2093
2094             if (index >= 0) {
2095                 cacheItem = listeners[index];
2096             }
2097
2098             if (!el || !cacheItem) {
2099                 return false;
2100             }
2101
2102             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2103
2104             delete listeners[index][this.WFN];
2105             delete listeners[index][this.FN];
2106             listeners.splice(index, 1);
2107
2108             return true;
2109
2110         },
2111
2112
2113         getTarget: function(ev, resolveTextNode) {
2114             ev = ev.browserEvent || ev;
2115             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2116             var t = ev.target || ev.srcElement;
2117             return this.resolveTextNode(t);
2118         },
2119
2120
2121         resolveTextNode: function(node) {
2122             if (Roo.isSafari && node && 3 == node.nodeType) {
2123                 return node.parentNode;
2124             } else {
2125                 return node;
2126             }
2127         },
2128
2129
2130         getPageX: function(ev) {
2131             ev = ev.browserEvent || ev;
2132             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2133             var x = ev.pageX;
2134             if (!x && 0 !== x) {
2135                 x = ev.clientX || 0;
2136
2137                 if (Roo.isIE) {
2138                     x += this.getScroll()[1];
2139                 }
2140             }
2141
2142             return x;
2143         },
2144
2145
2146         getPageY: function(ev) {
2147             ev = ev.browserEvent || ev;
2148             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2149             var y = ev.pageY;
2150             if (!y && 0 !== y) {
2151                 y = ev.clientY || 0;
2152
2153                 if (Roo.isIE) {
2154                     y += this.getScroll()[0];
2155                 }
2156             }
2157
2158
2159             return y;
2160         },
2161
2162
2163         getXY: function(ev) {
2164             ev = ev.browserEvent || ev;
2165             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2166             return [this.getPageX(ev), this.getPageY(ev)];
2167         },
2168
2169
2170         getRelatedTarget: function(ev) {
2171             ev = ev.browserEvent || ev;
2172             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2173             var t = ev.relatedTarget;
2174             if (!t) {
2175                 if (ev.type == "mouseout") {
2176                     t = ev.toElement;
2177                 } else if (ev.type == "mouseover") {
2178                     t = ev.fromElement;
2179                 }
2180             }
2181
2182             return this.resolveTextNode(t);
2183         },
2184
2185
2186         getTime: function(ev) {
2187             ev = ev.browserEvent || ev;
2188             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2189             if (!ev.time) {
2190                 var t = new Date().getTime();
2191                 try {
2192                     ev.time = t;
2193                 } catch(ex) {
2194                     this.lastError = ex;
2195                     return t;
2196                 }
2197             }
2198
2199             return ev.time;
2200         },
2201
2202
2203         stopEvent: function(ev) {
2204             this.stopPropagation(ev);
2205             this.preventDefault(ev);
2206         },
2207
2208
2209         stopPropagation: function(ev) {
2210             ev = ev.browserEvent || ev;
2211             if (ev.stopPropagation) {
2212                 ev.stopPropagation();
2213             } else {
2214                 ev.cancelBubble = true;
2215             }
2216         },
2217
2218
2219         preventDefault: function(ev) {
2220             ev = ev.browserEvent || ev;
2221             if(ev.preventDefault) {
2222                 ev.preventDefault();
2223             } else {
2224                 ev.returnValue = false;
2225             }
2226         },
2227
2228
2229         getEvent: function(e) {
2230             var ev = e || window.event;
2231             if (!ev) {
2232                 var c = this.getEvent.caller;
2233                 while (c) {
2234                     ev = c.arguments[0];
2235                     if (ev && Event == ev.constructor) {
2236                         break;
2237                     }
2238                     c = c.caller;
2239                 }
2240             }
2241             return ev;
2242         },
2243
2244
2245         getCharCode: function(ev) {
2246             ev = ev.browserEvent || ev;
2247             return ev.charCode || ev.keyCode || 0;
2248         },
2249
2250
2251         _getCacheIndex: function(el, eventName, fn) {
2252             for (var i = 0,len = listeners.length; i < len; ++i) {
2253                 var li = listeners[i];
2254                 if (li &&
2255                     li[this.FN] == fn &&
2256                     li[this.EL] == el &&
2257                     li[this.TYPE] == eventName) {
2258                     return i;
2259                 }
2260             }
2261
2262             return -1;
2263         },
2264
2265
2266         elCache: {},
2267
2268
2269         getEl: function(id) {
2270             return document.getElementById(id);
2271         },
2272
2273
2274         clearCache: function() {
2275         },
2276
2277
2278         _load: function(e) {
2279             loadComplete = true;
2280             var EU = Roo.lib.Event;
2281
2282
2283             if (Roo.isIE) {
2284                 EU.doRemove(window, "load", EU._load);
2285             }
2286         },
2287
2288
2289         _tryPreloadAttach: function() {
2290
2291             if (this.locked) {
2292                 return false;
2293             }
2294
2295             this.locked = true;
2296
2297
2298             var tryAgain = !loadComplete;
2299             if (!tryAgain) {
2300                 tryAgain = (retryCount > 0);
2301             }
2302
2303
2304             var notAvail = [];
2305             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2306                 var item = onAvailStack[i];
2307                 if (item) {
2308                     var el = this.getEl(item.id);
2309
2310                     if (el) {
2311                         if (!item.checkReady ||
2312                             loadComplete ||
2313                             el.nextSibling ||
2314                             (document && document.body)) {
2315
2316                             var scope = el;
2317                             if (item.override) {
2318                                 if (item.override === true) {
2319                                     scope = item.obj;
2320                                 } else {
2321                                     scope = item.override;
2322                                 }
2323                             }
2324                             item.fn.call(scope, item.obj);
2325                             onAvailStack[i] = null;
2326                         }
2327                     } else {
2328                         notAvail.push(item);
2329                     }
2330                 }
2331             }
2332
2333             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2334
2335             if (tryAgain) {
2336
2337                 this.startInterval();
2338             } else {
2339                 clearInterval(this._interval);
2340                 this._interval = null;
2341             }
2342
2343             this.locked = false;
2344
2345             return true;
2346
2347         },
2348
2349
2350         purgeElement: function(el, recurse, eventName) {
2351             var elListeners = this.getListeners(el, eventName);
2352             if (elListeners) {
2353                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2354                     var l = elListeners[i];
2355                     this.removeListener(el, l.type, l.fn);
2356                 }
2357             }
2358
2359             if (recurse && el && el.childNodes) {
2360                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2361                     this.purgeElement(el.childNodes[i], recurse, eventName);
2362                 }
2363             }
2364         },
2365
2366
2367         getListeners: function(el, eventName) {
2368             var results = [], searchLists;
2369             if (!eventName) {
2370                 searchLists = [listeners, unloadListeners];
2371             } else if (eventName == "unload") {
2372                 searchLists = [unloadListeners];
2373             } else {
2374                 searchLists = [listeners];
2375             }
2376
2377             for (var j = 0; j < searchLists.length; ++j) {
2378                 var searchList = searchLists[j];
2379                 if (searchList && searchList.length > 0) {
2380                     for (var i = 0,len = searchList.length; i < len; ++i) {
2381                         var l = searchList[i];
2382                         if (l && l[this.EL] === el &&
2383                             (!eventName || eventName === l[this.TYPE])) {
2384                             results.push({
2385                                 type:   l[this.TYPE],
2386                                 fn:     l[this.FN],
2387                                 obj:    l[this.OBJ],
2388                                 adjust: l[this.ADJ_SCOPE],
2389                                 index:  i
2390                             });
2391                         }
2392                     }
2393                 }
2394             }
2395
2396             return (results.length) ? results : null;
2397         },
2398
2399
2400         _unload: function(e) {
2401
2402             var EU = Roo.lib.Event, i, j, l, len, index;
2403
2404             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2405                 l = unloadListeners[i];
2406                 if (l) {
2407                     var scope = window;
2408                     if (l[EU.ADJ_SCOPE]) {
2409                         if (l[EU.ADJ_SCOPE] === true) {
2410                             scope = l[EU.OBJ];
2411                         } else {
2412                             scope = l[EU.ADJ_SCOPE];
2413                         }
2414                     }
2415                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2416                     unloadListeners[i] = null;
2417                     l = null;
2418                     scope = null;
2419                 }
2420             }
2421
2422             unloadListeners = null;
2423
2424             if (listeners && listeners.length > 0) {
2425                 j = listeners.length;
2426                 while (j) {
2427                     index = j - 1;
2428                     l = listeners[index];
2429                     if (l) {
2430                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2431                                 l[EU.FN], index);
2432                     }
2433                     j = j - 1;
2434                 }
2435                 l = null;
2436
2437                 EU.clearCache();
2438             }
2439
2440             EU.doRemove(window, "unload", EU._unload);
2441
2442         },
2443
2444
2445         getScroll: function() {
2446             var dd = document.documentElement, db = document.body;
2447             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2448                 return [dd.scrollTop, dd.scrollLeft];
2449             } else if (db) {
2450                 return [db.scrollTop, db.scrollLeft];
2451             } else {
2452                 return [0, 0];
2453             }
2454         },
2455
2456
2457         doAdd: function () {
2458             if (window.addEventListener) {
2459                 return function(el, eventName, fn, capture) {
2460                     el.addEventListener(eventName, fn, (capture));
2461                 };
2462             } else if (window.attachEvent) {
2463                 return function(el, eventName, fn, capture) {
2464                     el.attachEvent("on" + eventName, fn);
2465                 };
2466             } else {
2467                 return function() {
2468                 };
2469             }
2470         }(),
2471
2472
2473         doRemove: function() {
2474             if (window.removeEventListener) {
2475                 return function (el, eventName, fn, capture) {
2476                     el.removeEventListener(eventName, fn, (capture));
2477                 };
2478             } else if (window.detachEvent) {
2479                 return function (el, eventName, fn) {
2480                     el.detachEvent("on" + eventName, fn);
2481                 };
2482             } else {
2483                 return function() {
2484                 };
2485             }
2486         }()
2487     };
2488     
2489 }();
2490 (function() {     
2491    
2492     var E = Roo.lib.Event;
2493     E.on = E.addListener;
2494     E.un = E.removeListener;
2495
2496     if (document && document.body) {
2497         E._load();
2498     } else {
2499         E.doAdd(window, "load", E._load);
2500     }
2501     E.doAdd(window, "unload", E._unload);
2502     E._tryPreloadAttach();
2503 })();
2504
2505 /*
2506  * Portions of this file are based on pieces of Yahoo User Interface Library
2507  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2508  * YUI licensed under the BSD License:
2509  * http://developer.yahoo.net/yui/license.txt
2510  * <script type="text/javascript">
2511  *
2512  */
2513
2514 (function() {
2515     /**
2516      * @class Roo.lib.Ajax
2517      *
2518      */
2519     Roo.lib.Ajax = {
2520         /**
2521          * @static 
2522          */
2523         request : function(method, uri, cb, data, options) {
2524             if(options){
2525                 var hs = options.headers;
2526                 if(hs){
2527                     for(var h in hs){
2528                         if(hs.hasOwnProperty(h)){
2529                             this.initHeader(h, hs[h], false);
2530                         }
2531                     }
2532                 }
2533                 if(options.xmlData){
2534                     this.initHeader('Content-Type', 'text/xml', false);
2535                     method = 'POST';
2536                     data = options.xmlData;
2537                 }
2538             }
2539
2540             return this.asyncRequest(method, uri, cb, data);
2541         },
2542
2543         serializeForm : function(form) {
2544             if(typeof form == 'string') {
2545                 form = (document.getElementById(form) || document.forms[form]);
2546             }
2547
2548             var el, name, val, disabled, data = '', hasSubmit = false;
2549             for (var i = 0; i < form.elements.length; i++) {
2550                 el = form.elements[i];
2551                 disabled = form.elements[i].disabled;
2552                 name = form.elements[i].name;
2553                 val = form.elements[i].value;
2554
2555                 if (!disabled && name){
2556                     switch (el.type)
2557                             {
2558                         case 'select-one':
2559                         case 'select-multiple':
2560                             for (var j = 0; j < el.options.length; j++) {
2561                                 if (el.options[j].selected) {
2562                                     if (Roo.isIE) {
2563                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2564                                     }
2565                                     else {
2566                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2567                                     }
2568                                 }
2569                             }
2570                             break;
2571                         case 'radio':
2572                         case 'checkbox':
2573                             if (el.checked) {
2574                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2575                             }
2576                             break;
2577                         case 'file':
2578
2579                         case undefined:
2580
2581                         case 'reset':
2582
2583                         case 'button':
2584
2585                             break;
2586                         case 'submit':
2587                             if(hasSubmit == false) {
2588                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2589                                 hasSubmit = true;
2590                             }
2591                             break;
2592                         default:
2593                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2594                             break;
2595                     }
2596                 }
2597             }
2598             data = data.substr(0, data.length - 1);
2599             return data;
2600         },
2601
2602         headers:{},
2603
2604         hasHeaders:false,
2605
2606         useDefaultHeader:true,
2607
2608         defaultPostHeader:'application/x-www-form-urlencoded',
2609
2610         useDefaultXhrHeader:true,
2611
2612         defaultXhrHeader:'XMLHttpRequest',
2613
2614         hasDefaultHeaders:true,
2615
2616         defaultHeaders:{},
2617
2618         poll:{},
2619
2620         timeout:{},
2621
2622         pollInterval:50,
2623
2624         transactionId:0,
2625
2626         setProgId:function(id)
2627         {
2628             this.activeX.unshift(id);
2629         },
2630
2631         setDefaultPostHeader:function(b)
2632         {
2633             this.useDefaultHeader = b;
2634         },
2635
2636         setDefaultXhrHeader:function(b)
2637         {
2638             this.useDefaultXhrHeader = b;
2639         },
2640
2641         setPollingInterval:function(i)
2642         {
2643             if (typeof i == 'number' && isFinite(i)) {
2644                 this.pollInterval = i;
2645             }
2646         },
2647
2648         createXhrObject:function(transactionId)
2649         {
2650             var obj,http;
2651             try
2652             {
2653
2654                 http = new XMLHttpRequest();
2655
2656                 obj = { conn:http, tId:transactionId };
2657             }
2658             catch(e)
2659             {
2660                 for (var i = 0; i < this.activeX.length; ++i) {
2661                     try
2662                     {
2663
2664                         http = new ActiveXObject(this.activeX[i]);
2665
2666                         obj = { conn:http, tId:transactionId };
2667                         break;
2668                     }
2669                     catch(e) {
2670                     }
2671                 }
2672             }
2673             finally
2674             {
2675                 return obj;
2676             }
2677         },
2678
2679         getConnectionObject:function()
2680         {
2681             var o;
2682             var tId = this.transactionId;
2683
2684             try
2685             {
2686                 o = this.createXhrObject(tId);
2687                 if (o) {
2688                     this.transactionId++;
2689                 }
2690             }
2691             catch(e) {
2692             }
2693             finally
2694             {
2695                 return o;
2696             }
2697         },
2698
2699         asyncRequest:function(method, uri, callback, postData)
2700         {
2701             var o = this.getConnectionObject();
2702
2703             if (!o) {
2704                 return null;
2705             }
2706             else {
2707                 o.conn.open(method, uri, true);
2708
2709                 if (this.useDefaultXhrHeader) {
2710                     if (!this.defaultHeaders['X-Requested-With']) {
2711                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2712                     }
2713                 }
2714
2715                 if(postData && this.useDefaultHeader){
2716                     this.initHeader('Content-Type', this.defaultPostHeader);
2717                 }
2718
2719                  if (this.hasDefaultHeaders || this.hasHeaders) {
2720                     this.setHeader(o);
2721                 }
2722
2723                 this.handleReadyState(o, callback);
2724                 o.conn.send(postData || null);
2725
2726                 return o;
2727             }
2728         },
2729
2730         handleReadyState:function(o, callback)
2731         {
2732             var oConn = this;
2733
2734             if (callback && callback.timeout) {
2735                 
2736                 this.timeout[o.tId] = window.setTimeout(function() {
2737                     oConn.abort(o, callback, true);
2738                 }, callback.timeout);
2739             }
2740
2741             this.poll[o.tId] = window.setInterval(
2742                     function() {
2743                         if (o.conn && o.conn.readyState == 4) {
2744                             window.clearInterval(oConn.poll[o.tId]);
2745                             delete oConn.poll[o.tId];
2746
2747                             if(callback && callback.timeout) {
2748                                 window.clearTimeout(oConn.timeout[o.tId]);
2749                                 delete oConn.timeout[o.tId];
2750                             }
2751
2752                             oConn.handleTransactionResponse(o, callback);
2753                         }
2754                     }
2755                     , this.pollInterval);
2756         },
2757
2758         handleTransactionResponse:function(o, callback, isAbort)
2759         {
2760
2761             if (!callback) {
2762                 this.releaseObject(o);
2763                 return;
2764             }
2765
2766             var httpStatus, responseObject;
2767
2768             try
2769             {
2770                 if (o.conn.status !== undefined && o.conn.status != 0) {
2771                     httpStatus = o.conn.status;
2772                 }
2773                 else {
2774                     httpStatus = 13030;
2775                 }
2776             }
2777             catch(e) {
2778
2779
2780                 httpStatus = 13030;
2781             }
2782
2783             if (httpStatus >= 200 && httpStatus < 300) {
2784                 responseObject = this.createResponseObject(o, callback.argument);
2785                 if (callback.success) {
2786                     if (!callback.scope) {
2787                         callback.success(responseObject);
2788                     }
2789                     else {
2790
2791
2792                         callback.success.apply(callback.scope, [responseObject]);
2793                     }
2794                 }
2795             }
2796             else {
2797                 switch (httpStatus) {
2798
2799                     case 12002:
2800                     case 12029:
2801                     case 12030:
2802                     case 12031:
2803                     case 12152:
2804                     case 13030:
2805                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2806                         if (callback.failure) {
2807                             if (!callback.scope) {
2808                                 callback.failure(responseObject);
2809                             }
2810                             else {
2811                                 callback.failure.apply(callback.scope, [responseObject]);
2812                             }
2813                         }
2814                         break;
2815                     default:
2816                         responseObject = this.createResponseObject(o, callback.argument);
2817                         if (callback.failure) {
2818                             if (!callback.scope) {
2819                                 callback.failure(responseObject);
2820                             }
2821                             else {
2822                                 callback.failure.apply(callback.scope, [responseObject]);
2823                             }
2824                         }
2825                 }
2826             }
2827
2828             this.releaseObject(o);
2829             responseObject = null;
2830         },
2831
2832         createResponseObject:function(o, callbackArg)
2833         {
2834             var obj = {};
2835             var headerObj = {};
2836
2837             try
2838             {
2839                 var headerStr = o.conn.getAllResponseHeaders();
2840                 var header = headerStr.split('\n');
2841                 for (var i = 0; i < header.length; i++) {
2842                     var delimitPos = header[i].indexOf(':');
2843                     if (delimitPos != -1) {
2844                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2845                     }
2846                 }
2847             }
2848             catch(e) {
2849             }
2850
2851             obj.tId = o.tId;
2852             obj.status = o.conn.status;
2853             obj.statusText = o.conn.statusText;
2854             obj.getResponseHeader = headerObj;
2855             obj.getAllResponseHeaders = headerStr;
2856             obj.responseText = o.conn.responseText;
2857             obj.responseXML = o.conn.responseXML;
2858
2859             if (typeof callbackArg !== undefined) {
2860                 obj.argument = callbackArg;
2861             }
2862
2863             return obj;
2864         },
2865
2866         createExceptionObject:function(tId, callbackArg, isAbort)
2867         {
2868             var COMM_CODE = 0;
2869             var COMM_ERROR = 'communication failure';
2870             var ABORT_CODE = -1;
2871             var ABORT_ERROR = 'transaction aborted';
2872
2873             var obj = {};
2874
2875             obj.tId = tId;
2876             if (isAbort) {
2877                 obj.status = ABORT_CODE;
2878                 obj.statusText = ABORT_ERROR;
2879             }
2880             else {
2881                 obj.status = COMM_CODE;
2882                 obj.statusText = COMM_ERROR;
2883             }
2884
2885             if (callbackArg) {
2886                 obj.argument = callbackArg;
2887             }
2888
2889             return obj;
2890         },
2891
2892         initHeader:function(label, value, isDefault)
2893         {
2894             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2895
2896             if (headerObj[label] === undefined) {
2897                 headerObj[label] = value;
2898             }
2899             else {
2900
2901
2902                 headerObj[label] = value + "," + headerObj[label];
2903             }
2904
2905             if (isDefault) {
2906                 this.hasDefaultHeaders = true;
2907             }
2908             else {
2909                 this.hasHeaders = true;
2910             }
2911         },
2912
2913
2914         setHeader:function(o)
2915         {
2916             if (this.hasDefaultHeaders) {
2917                 for (var prop in this.defaultHeaders) {
2918                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2919                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2920                     }
2921                 }
2922             }
2923
2924             if (this.hasHeaders) {
2925                 for (var prop in this.headers) {
2926                     if (this.headers.hasOwnProperty(prop)) {
2927                         o.conn.setRequestHeader(prop, this.headers[prop]);
2928                     }
2929                 }
2930                 this.headers = {};
2931                 this.hasHeaders = false;
2932             }
2933         },
2934
2935         resetDefaultHeaders:function() {
2936             delete this.defaultHeaders;
2937             this.defaultHeaders = {};
2938             this.hasDefaultHeaders = false;
2939         },
2940
2941         abort:function(o, callback, isTimeout)
2942         {
2943             if(this.isCallInProgress(o)) {
2944                 o.conn.abort();
2945                 window.clearInterval(this.poll[o.tId]);
2946                 delete this.poll[o.tId];
2947                 if (isTimeout) {
2948                     delete this.timeout[o.tId];
2949                 }
2950
2951                 this.handleTransactionResponse(o, callback, true);
2952
2953                 return true;
2954             }
2955             else {
2956                 return false;
2957             }
2958         },
2959
2960
2961         isCallInProgress:function(o)
2962         {
2963             if (o && o.conn) {
2964                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2965             }
2966             else {
2967
2968                 return false;
2969             }
2970         },
2971
2972
2973         releaseObject:function(o)
2974         {
2975
2976             o.conn = null;
2977
2978             o = null;
2979         },
2980
2981         activeX:[
2982         'MSXML2.XMLHTTP.3.0',
2983         'MSXML2.XMLHTTP',
2984         'Microsoft.XMLHTTP'
2985         ]
2986
2987
2988     };
2989 })();/*
2990  * Portions of this file are based on pieces of Yahoo User Interface Library
2991  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2992  * YUI licensed under the BSD License:
2993  * http://developer.yahoo.net/yui/license.txt
2994  * <script type="text/javascript">
2995  *
2996  */
2997
2998 Roo.lib.Region = function(t, r, b, l) {
2999     this.top = t;
3000     this[1] = t;
3001     this.right = r;
3002     this.bottom = b;
3003     this.left = l;
3004     this[0] = l;
3005 };
3006
3007
3008 Roo.lib.Region.prototype = {
3009     contains : function(region) {
3010         return ( region.left >= this.left &&
3011                  region.right <= this.right &&
3012                  region.top >= this.top &&
3013                  region.bottom <= this.bottom    );
3014
3015     },
3016
3017     getArea : function() {
3018         return ( (this.bottom - this.top) * (this.right - this.left) );
3019     },
3020
3021     intersect : function(region) {
3022         var t = Math.max(this.top, region.top);
3023         var r = Math.min(this.right, region.right);
3024         var b = Math.min(this.bottom, region.bottom);
3025         var l = Math.max(this.left, region.left);
3026
3027         if (b >= t && r >= l) {
3028             return new Roo.lib.Region(t, r, b, l);
3029         } else {
3030             return null;
3031         }
3032     },
3033     union : function(region) {
3034         var t = Math.min(this.top, region.top);
3035         var r = Math.max(this.right, region.right);
3036         var b = Math.max(this.bottom, region.bottom);
3037         var l = Math.min(this.left, region.left);
3038
3039         return new Roo.lib.Region(t, r, b, l);
3040     },
3041
3042     adjust : function(t, l, b, r) {
3043         this.top += t;
3044         this.left += l;
3045         this.right += r;
3046         this.bottom += b;
3047         return this;
3048     }
3049 };
3050
3051 Roo.lib.Region.getRegion = function(el) {
3052     var p = Roo.lib.Dom.getXY(el);
3053
3054     var t = p[1];
3055     var r = p[0] + el.offsetWidth;
3056     var b = p[1] + el.offsetHeight;
3057     var l = p[0];
3058
3059     return new Roo.lib.Region(t, r, b, l);
3060 };
3061 /*
3062  * Portions of this file are based on pieces of Yahoo User Interface Library
3063  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3064  * YUI licensed under the BSD License:
3065  * http://developer.yahoo.net/yui/license.txt
3066  * <script type="text/javascript">
3067  *
3068  */
3069 //@@dep Roo.lib.Region
3070
3071
3072 Roo.lib.Point = function(x, y) {
3073     if (x instanceof Array) {
3074         y = x[1];
3075         x = x[0];
3076     }
3077     this.x = this.right = this.left = this[0] = x;
3078     this.y = this.top = this.bottom = this[1] = y;
3079 };
3080
3081 Roo.lib.Point.prototype = new Roo.lib.Region();
3082 /*
3083  * Portions of this file are based on pieces of Yahoo User Interface Library
3084  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3085  * YUI licensed under the BSD License:
3086  * http://developer.yahoo.net/yui/license.txt
3087  * <script type="text/javascript">
3088  *
3089  */
3090  
3091 (function() {   
3092
3093     Roo.lib.Anim = {
3094         scroll : function(el, args, duration, easing, cb, scope) {
3095             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3096         },
3097
3098         motion : function(el, args, duration, easing, cb, scope) {
3099             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3100         },
3101
3102         color : function(el, args, duration, easing, cb, scope) {
3103             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3104         },
3105
3106         run : function(el, args, duration, easing, cb, scope, type) {
3107             type = type || Roo.lib.AnimBase;
3108             if (typeof easing == "string") {
3109                 easing = Roo.lib.Easing[easing];
3110             }
3111             var anim = new type(el, args, duration, easing);
3112             anim.animateX(function() {
3113                 Roo.callback(cb, scope);
3114             });
3115             return anim;
3116         }
3117     };
3118 })();/*
3119  * Portions of this file are based on pieces of Yahoo User Interface Library
3120  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3121  * YUI licensed under the BSD License:
3122  * http://developer.yahoo.net/yui/license.txt
3123  * <script type="text/javascript">
3124  *
3125  */
3126
3127 (function() {    
3128     var libFlyweight;
3129     
3130     function fly(el) {
3131         if (!libFlyweight) {
3132             libFlyweight = new Roo.Element.Flyweight();
3133         }
3134         libFlyweight.dom = el;
3135         return libFlyweight;
3136     }
3137
3138     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3139     
3140    
3141     
3142     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3143         if (el) {
3144             this.init(el, attributes, duration, method);
3145         }
3146     };
3147
3148     Roo.lib.AnimBase.fly = fly;
3149     
3150     
3151     
3152     Roo.lib.AnimBase.prototype = {
3153
3154         toString: function() {
3155             var el = this.getEl();
3156             var id = el.id || el.tagName;
3157             return ("Anim " + id);
3158         },
3159
3160         patterns: {
3161             noNegatives:        /width|height|opacity|padding/i,
3162             offsetAttribute:  /^((width|height)|(top|left))$/,
3163             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3164             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3165         },
3166
3167
3168         doMethod: function(attr, start, end) {
3169             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3170         },
3171
3172
3173         setAttribute: function(attr, val, unit) {
3174             if (this.patterns.noNegatives.test(attr)) {
3175                 val = (val > 0) ? val : 0;
3176             }
3177
3178             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3179         },
3180
3181
3182         getAttribute: function(attr) {
3183             var el = this.getEl();
3184             var val = fly(el).getStyle(attr);
3185
3186             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3187                 return parseFloat(val);
3188             }
3189
3190             var a = this.patterns.offsetAttribute.exec(attr) || [];
3191             var pos = !!( a[3] );
3192             var box = !!( a[2] );
3193
3194
3195             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3196                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3197             } else {
3198                 val = 0;
3199             }
3200
3201             return val;
3202         },
3203
3204
3205         getDefaultUnit: function(attr) {
3206             if (this.patterns.defaultUnit.test(attr)) {
3207                 return 'px';
3208             }
3209
3210             return '';
3211         },
3212
3213         animateX : function(callback, scope) {
3214             var f = function() {
3215                 this.onComplete.removeListener(f);
3216                 if (typeof callback == "function") {
3217                     callback.call(scope || this, this);
3218                 }
3219             };
3220             this.onComplete.addListener(f, this);
3221             this.animate();
3222         },
3223
3224
3225         setRuntimeAttribute: function(attr) {
3226             var start;
3227             var end;
3228             var attributes = this.attributes;
3229
3230             this.runtimeAttributes[attr] = {};
3231
3232             var isset = function(prop) {
3233                 return (typeof prop !== 'undefined');
3234             };
3235
3236             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3237                 return false;
3238             }
3239
3240             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3241
3242
3243             if (isset(attributes[attr]['to'])) {
3244                 end = attributes[attr]['to'];
3245             } else if (isset(attributes[attr]['by'])) {
3246                 if (start.constructor == Array) {
3247                     end = [];
3248                     for (var i = 0, len = start.length; i < len; ++i) {
3249                         end[i] = start[i] + attributes[attr]['by'][i];
3250                     }
3251                 } else {
3252                     end = start + attributes[attr]['by'];
3253                 }
3254             }
3255
3256             this.runtimeAttributes[attr].start = start;
3257             this.runtimeAttributes[attr].end = end;
3258
3259
3260             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3261         },
3262
3263
3264         init: function(el, attributes, duration, method) {
3265
3266             var isAnimated = false;
3267
3268
3269             var startTime = null;
3270
3271
3272             var actualFrames = 0;
3273
3274
3275             el = Roo.getDom(el);
3276
3277
3278             this.attributes = attributes || {};
3279
3280
3281             this.duration = duration || 1;
3282
3283
3284             this.method = method || Roo.lib.Easing.easeNone;
3285
3286
3287             this.useSeconds = true;
3288
3289
3290             this.currentFrame = 0;
3291
3292
3293             this.totalFrames = Roo.lib.AnimMgr.fps;
3294
3295
3296             this.getEl = function() {
3297                 return el;
3298             };
3299
3300
3301             this.isAnimated = function() {
3302                 return isAnimated;
3303             };
3304
3305
3306             this.getStartTime = function() {
3307                 return startTime;
3308             };
3309
3310             this.runtimeAttributes = {};
3311
3312
3313             this.animate = function() {
3314                 if (this.isAnimated()) {
3315                     return false;
3316                 }
3317
3318                 this.currentFrame = 0;
3319
3320                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3321
3322                 Roo.lib.AnimMgr.registerElement(this);
3323             };
3324
3325
3326             this.stop = function(finish) {
3327                 if (finish) {
3328                     this.currentFrame = this.totalFrames;
3329                     this._onTween.fire();
3330                 }
3331                 Roo.lib.AnimMgr.stop(this);
3332             };
3333
3334             var onStart = function() {
3335                 this.onStart.fire();
3336
3337                 this.runtimeAttributes = {};
3338                 for (var attr in this.attributes) {
3339                     this.setRuntimeAttribute(attr);
3340                 }
3341
3342                 isAnimated = true;
3343                 actualFrames = 0;
3344                 startTime = new Date();
3345             };
3346
3347
3348             var onTween = function() {
3349                 var data = {
3350                     duration: new Date() - this.getStartTime(),
3351                     currentFrame: this.currentFrame
3352                 };
3353
3354                 data.toString = function() {
3355                     return (
3356                             'duration: ' + data.duration +
3357                             ', currentFrame: ' + data.currentFrame
3358                             );
3359                 };
3360
3361                 this.onTween.fire(data);
3362
3363                 var runtimeAttributes = this.runtimeAttributes;
3364
3365                 for (var attr in runtimeAttributes) {
3366                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3367                 }
3368
3369                 actualFrames += 1;
3370             };
3371
3372             var onComplete = function() {
3373                 var actual_duration = (new Date() - startTime) / 1000 ;
3374
3375                 var data = {
3376                     duration: actual_duration,
3377                     frames: actualFrames,
3378                     fps: actualFrames / actual_duration
3379                 };
3380
3381                 data.toString = function() {
3382                     return (
3383                             'duration: ' + data.duration +
3384                             ', frames: ' + data.frames +
3385                             ', fps: ' + data.fps
3386                             );
3387                 };
3388
3389                 isAnimated = false;
3390                 actualFrames = 0;
3391                 this.onComplete.fire(data);
3392             };
3393
3394
3395             this._onStart = new Roo.util.Event(this);
3396             this.onStart = new Roo.util.Event(this);
3397             this.onTween = new Roo.util.Event(this);
3398             this._onTween = new Roo.util.Event(this);
3399             this.onComplete = new Roo.util.Event(this);
3400             this._onComplete = new Roo.util.Event(this);
3401             this._onStart.addListener(onStart);
3402             this._onTween.addListener(onTween);
3403             this._onComplete.addListener(onComplete);
3404         }
3405     };
3406 })();
3407 /*
3408  * Portions of this file are based on pieces of Yahoo User Interface Library
3409  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3410  * YUI licensed under the BSD License:
3411  * http://developer.yahoo.net/yui/license.txt
3412  * <script type="text/javascript">
3413  *
3414  */
3415
3416 Roo.lib.AnimMgr = new function() {
3417
3418     var thread = null;
3419
3420
3421     var queue = [];
3422
3423
3424     var tweenCount = 0;
3425
3426
3427     this.fps = 1000;
3428
3429
3430     this.delay = 1;
3431
3432
3433     this.registerElement = function(tween) {
3434         queue[queue.length] = tween;
3435         tweenCount += 1;
3436         tween._onStart.fire();
3437         this.start();
3438     };
3439
3440
3441     this.unRegister = function(tween, index) {
3442         tween._onComplete.fire();
3443         index = index || getIndex(tween);
3444         if (index != -1) {
3445             queue.splice(index, 1);
3446         }
3447
3448         tweenCount -= 1;
3449         if (tweenCount <= 0) {
3450             this.stop();
3451         }
3452     };
3453
3454
3455     this.start = function() {
3456         if (thread === null) {
3457             thread = setInterval(this.run, this.delay);
3458         }
3459     };
3460
3461
3462     this.stop = function(tween) {
3463         if (!tween) {
3464             clearInterval(thread);
3465
3466             for (var i = 0, len = queue.length; i < len; ++i) {
3467                 if (queue[0].isAnimated()) {
3468                     this.unRegister(queue[0], 0);
3469                 }
3470             }
3471
3472             queue = [];
3473             thread = null;
3474             tweenCount = 0;
3475         }
3476         else {
3477             this.unRegister(tween);
3478         }
3479     };
3480
3481
3482     this.run = function() {
3483         for (var i = 0, len = queue.length; i < len; ++i) {
3484             var tween = queue[i];
3485             if (!tween || !tween.isAnimated()) {
3486                 continue;
3487             }
3488
3489             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3490             {
3491                 tween.currentFrame += 1;
3492
3493                 if (tween.useSeconds) {
3494                     correctFrame(tween);
3495                 }
3496                 tween._onTween.fire();
3497             }
3498             else {
3499                 Roo.lib.AnimMgr.stop(tween, i);
3500             }
3501         }
3502     };
3503
3504     var getIndex = function(anim) {
3505         for (var i = 0, len = queue.length; i < len; ++i) {
3506             if (queue[i] == anim) {
3507                 return i;
3508             }
3509         }
3510         return -1;
3511     };
3512
3513
3514     var correctFrame = function(tween) {
3515         var frames = tween.totalFrames;
3516         var frame = tween.currentFrame;
3517         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3518         var elapsed = (new Date() - tween.getStartTime());
3519         var tweak = 0;
3520
3521         if (elapsed < tween.duration * 1000) {
3522             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3523         } else {
3524             tweak = frames - (frame + 1);
3525         }
3526         if (tweak > 0 && isFinite(tweak)) {
3527             if (tween.currentFrame + tweak >= frames) {
3528                 tweak = frames - (frame + 1);
3529             }
3530
3531             tween.currentFrame += tweak;
3532         }
3533     };
3534 };
3535
3536     /*
3537  * Portions of this file are based on pieces of Yahoo User Interface Library
3538  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3539  * YUI licensed under the BSD License:
3540  * http://developer.yahoo.net/yui/license.txt
3541  * <script type="text/javascript">
3542  *
3543  */
3544 Roo.lib.Bezier = new function() {
3545
3546         this.getPosition = function(points, t) {
3547             var n = points.length;
3548             var tmp = [];
3549
3550             for (var i = 0; i < n; ++i) {
3551                 tmp[i] = [points[i][0], points[i][1]];
3552             }
3553
3554             for (var j = 1; j < n; ++j) {
3555                 for (i = 0; i < n - j; ++i) {
3556                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3557                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3558                 }
3559             }
3560
3561             return [ tmp[0][0], tmp[0][1] ];
3562
3563         };
3564     };/*
3565  * Portions of this file are based on pieces of Yahoo User Interface Library
3566  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3567  * YUI licensed under the BSD License:
3568  * http://developer.yahoo.net/yui/license.txt
3569  * <script type="text/javascript">
3570  *
3571  */
3572 (function() {
3573
3574     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3575         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3576     };
3577
3578     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3579
3580     var fly = Roo.lib.AnimBase.fly;
3581     var Y = Roo.lib;
3582     var superclass = Y.ColorAnim.superclass;
3583     var proto = Y.ColorAnim.prototype;
3584
3585     proto.toString = function() {
3586         var el = this.getEl();
3587         var id = el.id || el.tagName;
3588         return ("ColorAnim " + id);
3589     };
3590
3591     proto.patterns.color = /color$/i;
3592     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3593     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3594     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3595     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3596
3597
3598     proto.parseColor = function(s) {
3599         if (s.length == 3) {
3600             return s;
3601         }
3602
3603         var c = this.patterns.hex.exec(s);
3604         if (c && c.length == 4) {
3605             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3606         }
3607
3608         c = this.patterns.rgb.exec(s);
3609         if (c && c.length == 4) {
3610             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3611         }
3612
3613         c = this.patterns.hex3.exec(s);
3614         if (c && c.length == 4) {
3615             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3616         }
3617
3618         return null;
3619     };
3620     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3621     proto.getAttribute = function(attr) {
3622         var el = this.getEl();
3623         if (this.patterns.color.test(attr)) {
3624             var val = fly(el).getStyle(attr);
3625
3626             if (this.patterns.transparent.test(val)) {
3627                 var parent = el.parentNode;
3628                 val = fly(parent).getStyle(attr);
3629
3630                 while (parent && this.patterns.transparent.test(val)) {
3631                     parent = parent.parentNode;
3632                     val = fly(parent).getStyle(attr);
3633                     if (parent.tagName.toUpperCase() == 'HTML') {
3634                         val = '#fff';
3635                     }
3636                 }
3637             }
3638         } else {
3639             val = superclass.getAttribute.call(this, attr);
3640         }
3641
3642         return val;
3643     };
3644     proto.getAttribute = function(attr) {
3645         var el = this.getEl();
3646         if (this.patterns.color.test(attr)) {
3647             var val = fly(el).getStyle(attr);
3648
3649             if (this.patterns.transparent.test(val)) {
3650                 var parent = el.parentNode;
3651                 val = fly(parent).getStyle(attr);
3652
3653                 while (parent && this.patterns.transparent.test(val)) {
3654                     parent = parent.parentNode;
3655                     val = fly(parent).getStyle(attr);
3656                     if (parent.tagName.toUpperCase() == 'HTML') {
3657                         val = '#fff';
3658                     }
3659                 }
3660             }
3661         } else {
3662             val = superclass.getAttribute.call(this, attr);
3663         }
3664
3665         return val;
3666     };
3667
3668     proto.doMethod = function(attr, start, end) {
3669         var val;
3670
3671         if (this.patterns.color.test(attr)) {
3672             val = [];
3673             for (var i = 0, len = start.length; i < len; ++i) {
3674                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3675             }
3676
3677             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3678         }
3679         else {
3680             val = superclass.doMethod.call(this, attr, start, end);
3681         }
3682
3683         return val;
3684     };
3685
3686     proto.setRuntimeAttribute = function(attr) {
3687         superclass.setRuntimeAttribute.call(this, attr);
3688
3689         if (this.patterns.color.test(attr)) {
3690             var attributes = this.attributes;
3691             var start = this.parseColor(this.runtimeAttributes[attr].start);
3692             var end = this.parseColor(this.runtimeAttributes[attr].end);
3693
3694             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3695                 end = this.parseColor(attributes[attr].by);
3696
3697                 for (var i = 0, len = start.length; i < len; ++i) {
3698                     end[i] = start[i] + end[i];
3699                 }
3700             }
3701
3702             this.runtimeAttributes[attr].start = start;
3703             this.runtimeAttributes[attr].end = end;
3704         }
3705     };
3706 })();
3707
3708 /*
3709  * Portions of this file are based on pieces of Yahoo User Interface Library
3710  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3711  * YUI licensed under the BSD License:
3712  * http://developer.yahoo.net/yui/license.txt
3713  * <script type="text/javascript">
3714  *
3715  */
3716 Roo.lib.Easing = {
3717
3718
3719     easeNone: function (t, b, c, d) {
3720         return c * t / d + b;
3721     },
3722
3723
3724     easeIn: function (t, b, c, d) {
3725         return c * (t /= d) * t + b;
3726     },
3727
3728
3729     easeOut: function (t, b, c, d) {
3730         return -c * (t /= d) * (t - 2) + b;
3731     },
3732
3733
3734     easeBoth: function (t, b, c, d) {
3735         if ((t /= d / 2) < 1) {
3736             return c / 2 * t * t + b;
3737         }
3738
3739         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3740     },
3741
3742
3743     easeInStrong: function (t, b, c, d) {
3744         return c * (t /= d) * t * t * t + b;
3745     },
3746
3747
3748     easeOutStrong: function (t, b, c, d) {
3749         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3750     },
3751
3752
3753     easeBothStrong: function (t, b, c, d) {
3754         if ((t /= d / 2) < 1) {
3755             return c / 2 * t * t * t * t + b;
3756         }
3757
3758         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3759     },
3760
3761
3762
3763     elasticIn: function (t, b, c, d, a, p) {
3764         if (t == 0) {
3765             return b;
3766         }
3767         if ((t /= d) == 1) {
3768             return b + c;
3769         }
3770         if (!p) {
3771             p = d * .3;
3772         }
3773
3774         if (!a || a < Math.abs(c)) {
3775             a = c;
3776             var s = p / 4;
3777         }
3778         else {
3779             var s = p / (2 * Math.PI) * Math.asin(c / a);
3780         }
3781
3782         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3783     },
3784
3785
3786     elasticOut: function (t, b, c, d, a, p) {
3787         if (t == 0) {
3788             return b;
3789         }
3790         if ((t /= d) == 1) {
3791             return b + c;
3792         }
3793         if (!p) {
3794             p = d * .3;
3795         }
3796
3797         if (!a || a < Math.abs(c)) {
3798             a = c;
3799             var s = p / 4;
3800         }
3801         else {
3802             var s = p / (2 * Math.PI) * Math.asin(c / a);
3803         }
3804
3805         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3806     },
3807
3808
3809     elasticBoth: function (t, b, c, d, a, p) {
3810         if (t == 0) {
3811             return b;
3812         }
3813
3814         if ((t /= d / 2) == 2) {
3815             return b + c;
3816         }
3817
3818         if (!p) {
3819             p = d * (.3 * 1.5);
3820         }
3821
3822         if (!a || a < Math.abs(c)) {
3823             a = c;
3824             var s = p / 4;
3825         }
3826         else {
3827             var s = p / (2 * Math.PI) * Math.asin(c / a);
3828         }
3829
3830         if (t < 1) {
3831             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3832                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3833         }
3834         return a * Math.pow(2, -10 * (t -= 1)) *
3835                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3836     },
3837
3838
3839
3840     backIn: function (t, b, c, d, s) {
3841         if (typeof s == 'undefined') {
3842             s = 1.70158;
3843         }
3844         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3845     },
3846
3847
3848     backOut: function (t, b, c, d, s) {
3849         if (typeof s == 'undefined') {
3850             s = 1.70158;
3851         }
3852         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3853     },
3854
3855
3856     backBoth: function (t, b, c, d, s) {
3857         if (typeof s == 'undefined') {
3858             s = 1.70158;
3859         }
3860
3861         if ((t /= d / 2 ) < 1) {
3862             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3863         }
3864         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3865     },
3866
3867
3868     bounceIn: function (t, b, c, d) {
3869         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3870     },
3871
3872
3873     bounceOut: function (t, b, c, d) {
3874         if ((t /= d) < (1 / 2.75)) {
3875             return c * (7.5625 * t * t) + b;
3876         } else if (t < (2 / 2.75)) {
3877             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3878         } else if (t < (2.5 / 2.75)) {
3879             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3880         }
3881         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3882     },
3883
3884
3885     bounceBoth: function (t, b, c, d) {
3886         if (t < d / 2) {
3887             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3888         }
3889         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3890     }
3891 };/*
3892  * Portions of this file are based on pieces of Yahoo User Interface Library
3893  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3894  * YUI licensed under the BSD License:
3895  * http://developer.yahoo.net/yui/license.txt
3896  * <script type="text/javascript">
3897  *
3898  */
3899     (function() {
3900         Roo.lib.Motion = function(el, attributes, duration, method) {
3901             if (el) {
3902                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3903             }
3904         };
3905
3906         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3907
3908
3909         var Y = Roo.lib;
3910         var superclass = Y.Motion.superclass;
3911         var proto = Y.Motion.prototype;
3912
3913         proto.toString = function() {
3914             var el = this.getEl();
3915             var id = el.id || el.tagName;
3916             return ("Motion " + id);
3917         };
3918
3919         proto.patterns.points = /^points$/i;
3920
3921         proto.setAttribute = function(attr, val, unit) {
3922             if (this.patterns.points.test(attr)) {
3923                 unit = unit || 'px';
3924                 superclass.setAttribute.call(this, 'left', val[0], unit);
3925                 superclass.setAttribute.call(this, 'top', val[1], unit);
3926             } else {
3927                 superclass.setAttribute.call(this, attr, val, unit);
3928             }
3929         };
3930
3931         proto.getAttribute = function(attr) {
3932             if (this.patterns.points.test(attr)) {
3933                 var val = [
3934                         superclass.getAttribute.call(this, 'left'),
3935                         superclass.getAttribute.call(this, 'top')
3936                         ];
3937             } else {
3938                 val = superclass.getAttribute.call(this, attr);
3939             }
3940
3941             return val;
3942         };
3943
3944         proto.doMethod = function(attr, start, end) {
3945             var val = null;
3946
3947             if (this.patterns.points.test(attr)) {
3948                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3949                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3950             } else {
3951                 val = superclass.doMethod.call(this, attr, start, end);
3952             }
3953             return val;
3954         };
3955
3956         proto.setRuntimeAttribute = function(attr) {
3957             if (this.patterns.points.test(attr)) {
3958                 var el = this.getEl();
3959                 var attributes = this.attributes;
3960                 var start;
3961                 var control = attributes['points']['control'] || [];
3962                 var end;
3963                 var i, len;
3964
3965                 if (control.length > 0 && !(control[0] instanceof Array)) {
3966                     control = [control];
3967                 } else {
3968                     var tmp = [];
3969                     for (i = 0,len = control.length; i < len; ++i) {
3970                         tmp[i] = control[i];
3971                     }
3972                     control = tmp;
3973                 }
3974
3975                 Roo.fly(el).position();
3976
3977                 if (isset(attributes['points']['from'])) {
3978                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3979                 }
3980                 else {
3981                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3982                 }
3983
3984                 start = this.getAttribute('points');
3985
3986
3987                 if (isset(attributes['points']['to'])) {
3988                     end = translateValues.call(this, attributes['points']['to'], start);
3989
3990                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3991                     for (i = 0,len = control.length; i < len; ++i) {
3992                         control[i] = translateValues.call(this, control[i], start);
3993                     }
3994
3995
3996                 } else if (isset(attributes['points']['by'])) {
3997                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3998
3999                     for (i = 0,len = control.length; i < len; ++i) {
4000                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4001                     }
4002                 }
4003
4004                 this.runtimeAttributes[attr] = [start];
4005
4006                 if (control.length > 0) {
4007                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4008                 }
4009
4010                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4011             }
4012             else {
4013                 superclass.setRuntimeAttribute.call(this, attr);
4014             }
4015         };
4016
4017         var translateValues = function(val, start) {
4018             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4019             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4020
4021             return val;
4022         };
4023
4024         var isset = function(prop) {
4025             return (typeof prop !== 'undefined');
4026         };
4027     })();
4028 /*
4029  * Portions of this file are based on pieces of Yahoo User Interface Library
4030  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4031  * YUI licensed under the BSD License:
4032  * http://developer.yahoo.net/yui/license.txt
4033  * <script type="text/javascript">
4034  *
4035  */
4036     (function() {
4037         Roo.lib.Scroll = function(el, attributes, duration, method) {
4038             if (el) {
4039                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4040             }
4041         };
4042
4043         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4044
4045
4046         var Y = Roo.lib;
4047         var superclass = Y.Scroll.superclass;
4048         var proto = Y.Scroll.prototype;
4049
4050         proto.toString = function() {
4051             var el = this.getEl();
4052             var id = el.id || el.tagName;
4053             return ("Scroll " + id);
4054         };
4055
4056         proto.doMethod = function(attr, start, end) {
4057             var val = null;
4058
4059             if (attr == 'scroll') {
4060                 val = [
4061                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4062                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4063                         ];
4064
4065             } else {
4066                 val = superclass.doMethod.call(this, attr, start, end);
4067             }
4068             return val;
4069         };
4070
4071         proto.getAttribute = function(attr) {
4072             var val = null;
4073             var el = this.getEl();
4074
4075             if (attr == 'scroll') {
4076                 val = [ el.scrollLeft, el.scrollTop ];
4077             } else {
4078                 val = superclass.getAttribute.call(this, attr);
4079             }
4080
4081             return val;
4082         };
4083
4084         proto.setAttribute = function(attr, val, unit) {
4085             var el = this.getEl();
4086
4087             if (attr == 'scroll') {
4088                 el.scrollLeft = val[0];
4089                 el.scrollTop = val[1];
4090             } else {
4091                 superclass.setAttribute.call(this, attr, val, unit);
4092             }
4093         };
4094     })();
4095 /*
4096  * Based on:
4097  * Ext JS Library 1.1.1
4098  * Copyright(c) 2006-2007, Ext JS, LLC.
4099  *
4100  * Originally Released Under LGPL - original licence link has changed is not relivant.
4101  *
4102  * Fork - LGPL
4103  * <script type="text/javascript">
4104  */
4105
4106
4107 // nasty IE9 hack - what a pile of crap that is..
4108
4109  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4110     Range.prototype.createContextualFragment = function (html) {
4111         var doc = window.document;
4112         var container = doc.createElement("div");
4113         container.innerHTML = html;
4114         var frag = doc.createDocumentFragment(), n;
4115         while ((n = container.firstChild)) {
4116             frag.appendChild(n);
4117         }
4118         return frag;
4119     };
4120 }
4121
4122 /**
4123  * @class Roo.DomHelper
4124  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4125  * 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>.
4126  * @singleton
4127  */
4128 Roo.DomHelper = function(){
4129     var tempTableEl = null;
4130     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4131     var tableRe = /^table|tbody|tr|td$/i;
4132     var xmlns = {};
4133     // build as innerHTML where available
4134     /** @ignore */
4135     var createHtml = function(o){
4136         if(typeof o == 'string'){
4137             return o;
4138         }
4139         var b = "";
4140         if(!o.tag){
4141             o.tag = "div";
4142         }
4143         b += "<" + o.tag;
4144         for(var attr in o){
4145             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4146             if(attr == "style"){
4147                 var s = o["style"];
4148                 if(typeof s == "function"){
4149                     s = s.call();
4150                 }
4151                 if(typeof s == "string"){
4152                     b += ' style="' + s + '"';
4153                 }else if(typeof s == "object"){
4154                     b += ' style="';
4155                     for(var key in s){
4156                         if(typeof s[key] != "function"){
4157                             b += key + ":" + s[key] + ";";
4158                         }
4159                     }
4160                     b += '"';
4161                 }
4162             }else{
4163                 if(attr == "cls"){
4164                     b += ' class="' + o["cls"] + '"';
4165                 }else if(attr == "htmlFor"){
4166                     b += ' for="' + o["htmlFor"] + '"';
4167                 }else{
4168                     b += " " + attr + '="' + o[attr] + '"';
4169                 }
4170             }
4171         }
4172         if(emptyTags.test(o.tag)){
4173             b += "/>";
4174         }else{
4175             b += ">";
4176             var cn = o.children || o.cn;
4177             if(cn){
4178                 //http://bugs.kde.org/show_bug.cgi?id=71506
4179                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4180                     for(var i = 0, len = cn.length; i < len; i++) {
4181                         b += createHtml(cn[i], b);
4182                     }
4183                 }else{
4184                     b += createHtml(cn, b);
4185                 }
4186             }
4187             if(o.html){
4188                 b += o.html;
4189             }
4190             b += "</" + o.tag + ">";
4191         }
4192         return b;
4193     };
4194
4195     // build as dom
4196     /** @ignore */
4197     var createDom = function(o, parentNode){
4198          
4199         // defininition craeted..
4200         var ns = false;
4201         if (o.ns && o.ns != 'html') {
4202                
4203             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4204                 xmlns[o.ns] = o.xmlns;
4205                 ns = o.xmlns;
4206             }
4207             if (typeof(xmlns[o.ns]) == 'undefined') {
4208                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4209             }
4210             ns = xmlns[o.ns];
4211         }
4212         
4213         
4214         if (typeof(o) == 'string') {
4215             return parentNode.appendChild(document.createTextNode(o));
4216         }
4217         o.tag = o.tag || div;
4218         if (o.ns && Roo.isIE) {
4219             ns = false;
4220             o.tag = o.ns + ':' + o.tag;
4221             
4222         }
4223         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4224         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4225         for(var attr in o){
4226             
4227             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4228                     attr == "style" || typeof o[attr] == "function") continue;
4229                     
4230             if(attr=="cls" && Roo.isIE){
4231                 el.className = o["cls"];
4232             }else{
4233                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4234                 else el[attr] = o[attr];
4235             }
4236         }
4237         Roo.DomHelper.applyStyles(el, o.style);
4238         var cn = o.children || o.cn;
4239         if(cn){
4240             //http://bugs.kde.org/show_bug.cgi?id=71506
4241              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4242                 for(var i = 0, len = cn.length; i < len; i++) {
4243                     createDom(cn[i], el);
4244                 }
4245             }else{
4246                 createDom(cn, el);
4247             }
4248         }
4249         if(o.html){
4250             el.innerHTML = o.html;
4251         }
4252         if(parentNode){
4253            parentNode.appendChild(el);
4254         }
4255         return el;
4256     };
4257
4258     var ieTable = function(depth, s, h, e){
4259         tempTableEl.innerHTML = [s, h, e].join('');
4260         var i = -1, el = tempTableEl;
4261         while(++i < depth){
4262             el = el.firstChild;
4263         }
4264         return el;
4265     };
4266
4267     // kill repeat to save bytes
4268     var ts = '<table>',
4269         te = '</table>',
4270         tbs = ts+'<tbody>',
4271         tbe = '</tbody>'+te,
4272         trs = tbs + '<tr>',
4273         tre = '</tr>'+tbe;
4274
4275     /**
4276      * @ignore
4277      * Nasty code for IE's broken table implementation
4278      */
4279     var insertIntoTable = function(tag, where, el, html){
4280         if(!tempTableEl){
4281             tempTableEl = document.createElement('div');
4282         }
4283         var node;
4284         var before = null;
4285         if(tag == 'td'){
4286             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4287                 return;
4288             }
4289             if(where == 'beforebegin'){
4290                 before = el;
4291                 el = el.parentNode;
4292             } else{
4293                 before = el.nextSibling;
4294                 el = el.parentNode;
4295             }
4296             node = ieTable(4, trs, html, tre);
4297         }
4298         else if(tag == 'tr'){
4299             if(where == 'beforebegin'){
4300                 before = el;
4301                 el = el.parentNode;
4302                 node = ieTable(3, tbs, html, tbe);
4303             } else if(where == 'afterend'){
4304                 before = el.nextSibling;
4305                 el = el.parentNode;
4306                 node = ieTable(3, tbs, html, tbe);
4307             } else{ // INTO a TR
4308                 if(where == 'afterbegin'){
4309                     before = el.firstChild;
4310                 }
4311                 node = ieTable(4, trs, html, tre);
4312             }
4313         } else if(tag == 'tbody'){
4314             if(where == 'beforebegin'){
4315                 before = el;
4316                 el = el.parentNode;
4317                 node = ieTable(2, ts, html, te);
4318             } else if(where == 'afterend'){
4319                 before = el.nextSibling;
4320                 el = el.parentNode;
4321                 node = ieTable(2, ts, html, te);
4322             } else{
4323                 if(where == 'afterbegin'){
4324                     before = el.firstChild;
4325                 }
4326                 node = ieTable(3, tbs, html, tbe);
4327             }
4328         } else{ // TABLE
4329             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4330                 return;
4331             }
4332             if(where == 'afterbegin'){
4333                 before = el.firstChild;
4334             }
4335             node = ieTable(2, ts, html, te);
4336         }
4337         el.insertBefore(node, before);
4338         return node;
4339     };
4340
4341     return {
4342     /** True to force the use of DOM instead of html fragments @type Boolean */
4343     useDom : false,
4344
4345     /**
4346      * Returns the markup for the passed Element(s) config
4347      * @param {Object} o The Dom object spec (and children)
4348      * @return {String}
4349      */
4350     markup : function(o){
4351         return createHtml(o);
4352     },
4353
4354     /**
4355      * Applies a style specification to an element
4356      * @param {String/HTMLElement} el The element to apply styles to
4357      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4358      * a function which returns such a specification.
4359      */
4360     applyStyles : function(el, styles){
4361         if(styles){
4362            el = Roo.fly(el);
4363            if(typeof styles == "string"){
4364                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4365                var matches;
4366                while ((matches = re.exec(styles)) != null){
4367                    el.setStyle(matches[1], matches[2]);
4368                }
4369            }else if (typeof styles == "object"){
4370                for (var style in styles){
4371                   el.setStyle(style, styles[style]);
4372                }
4373            }else if (typeof styles == "function"){
4374                 Roo.DomHelper.applyStyles(el, styles.call());
4375            }
4376         }
4377     },
4378
4379     /**
4380      * Inserts an HTML fragment into the Dom
4381      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4382      * @param {HTMLElement} el The context element
4383      * @param {String} html The HTML fragmenet
4384      * @return {HTMLElement} The new node
4385      */
4386     insertHtml : function(where, el, html){
4387         where = where.toLowerCase();
4388         if(el.insertAdjacentHTML){
4389             if(tableRe.test(el.tagName)){
4390                 var rs;
4391                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4392                     return rs;
4393                 }
4394             }
4395             switch(where){
4396                 case "beforebegin":
4397                     el.insertAdjacentHTML('BeforeBegin', html);
4398                     return el.previousSibling;
4399                 case "afterbegin":
4400                     el.insertAdjacentHTML('AfterBegin', html);
4401                     return el.firstChild;
4402                 case "beforeend":
4403                     el.insertAdjacentHTML('BeforeEnd', html);
4404                     return el.lastChild;
4405                 case "afterend":
4406                     el.insertAdjacentHTML('AfterEnd', html);
4407                     return el.nextSibling;
4408             }
4409             throw 'Illegal insertion point -> "' + where + '"';
4410         }
4411         var range = el.ownerDocument.createRange();
4412         var frag;
4413         switch(where){
4414              case "beforebegin":
4415                 range.setStartBefore(el);
4416                 frag = range.createContextualFragment(html);
4417                 el.parentNode.insertBefore(frag, el);
4418                 return el.previousSibling;
4419              case "afterbegin":
4420                 if(el.firstChild){
4421                     range.setStartBefore(el.firstChild);
4422                     frag = range.createContextualFragment(html);
4423                     el.insertBefore(frag, el.firstChild);
4424                     return el.firstChild;
4425                 }else{
4426                     el.innerHTML = html;
4427                     return el.firstChild;
4428                 }
4429             case "beforeend":
4430                 if(el.lastChild){
4431                     range.setStartAfter(el.lastChild);
4432                     frag = range.createContextualFragment(html);
4433                     el.appendChild(frag);
4434                     return el.lastChild;
4435                 }else{
4436                     el.innerHTML = html;
4437                     return el.lastChild;
4438                 }
4439             case "afterend":
4440                 range.setStartAfter(el);
4441                 frag = range.createContextualFragment(html);
4442                 el.parentNode.insertBefore(frag, el.nextSibling);
4443                 return el.nextSibling;
4444             }
4445             throw 'Illegal insertion point -> "' + where + '"';
4446     },
4447
4448     /**
4449      * Creates new Dom element(s) and inserts them before el
4450      * @param {String/HTMLElement/Element} el The context element
4451      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4452      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4453      * @return {HTMLElement/Roo.Element} The new node
4454      */
4455     insertBefore : function(el, o, returnElement){
4456         return this.doInsert(el, o, returnElement, "beforeBegin");
4457     },
4458
4459     /**
4460      * Creates new Dom element(s) and inserts them after el
4461      * @param {String/HTMLElement/Element} el The context element
4462      * @param {Object} o The Dom object spec (and children)
4463      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464      * @return {HTMLElement/Roo.Element} The new node
4465      */
4466     insertAfter : function(el, o, returnElement){
4467         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4468     },
4469
4470     /**
4471      * Creates new Dom element(s) and inserts them as the first child of el
4472      * @param {String/HTMLElement/Element} el The context element
4473      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4474      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475      * @return {HTMLElement/Roo.Element} The new node
4476      */
4477     insertFirst : function(el, o, returnElement){
4478         return this.doInsert(el, o, returnElement, "afterBegin");
4479     },
4480
4481     // private
4482     doInsert : function(el, o, returnElement, pos, sibling){
4483         el = Roo.getDom(el);
4484         var newNode;
4485         if(this.useDom || o.ns){
4486             newNode = createDom(o, null);
4487             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4488         }else{
4489             var html = createHtml(o);
4490             newNode = this.insertHtml(pos, el, html);
4491         }
4492         return returnElement ? Roo.get(newNode, true) : newNode;
4493     },
4494
4495     /**
4496      * Creates new Dom element(s) and appends them to el
4497      * @param {String/HTMLElement/Element} el The context element
4498      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4499      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4500      * @return {HTMLElement/Roo.Element} The new node
4501      */
4502     append : function(el, o, returnElement){
4503         el = Roo.getDom(el);
4504         var newNode;
4505         if(this.useDom || o.ns){
4506             newNode = createDom(o, null);
4507             el.appendChild(newNode);
4508         }else{
4509             var html = createHtml(o);
4510             newNode = this.insertHtml("beforeEnd", el, html);
4511         }
4512         return returnElement ? Roo.get(newNode, true) : newNode;
4513     },
4514
4515     /**
4516      * Creates new Dom element(s) and overwrites the contents of el with them
4517      * @param {String/HTMLElement/Element} el The context element
4518      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4519      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4520      * @return {HTMLElement/Roo.Element} The new node
4521      */
4522     overwrite : function(el, o, returnElement){
4523         el = Roo.getDom(el);
4524         if (o.ns) {
4525           
4526             while (el.childNodes.length) {
4527                 el.removeChild(el.firstChild);
4528             }
4529             createDom(o, el);
4530         } else {
4531             el.innerHTML = createHtml(o);   
4532         }
4533         
4534         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4535     },
4536
4537     /**
4538      * Creates a new Roo.DomHelper.Template from the Dom object spec
4539      * @param {Object} o The Dom object spec (and children)
4540      * @return {Roo.DomHelper.Template} The new template
4541      */
4542     createTemplate : function(o){
4543         var html = createHtml(o);
4544         return new Roo.Template(html);
4545     }
4546     };
4547 }();
4548 /*
4549  * Based on:
4550  * Ext JS Library 1.1.1
4551  * Copyright(c) 2006-2007, Ext JS, LLC.
4552  *
4553  * Originally Released Under LGPL - original licence link has changed is not relivant.
4554  *
4555  * Fork - LGPL
4556  * <script type="text/javascript">
4557  */
4558  
4559 /**
4560 * @class Roo.Template
4561 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4562 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4563 * Usage:
4564 <pre><code>
4565 var t = new Roo.Template({
4566     html :  '&lt;div name="{id}"&gt;' + 
4567         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4568         '&lt;/div&gt;',
4569     myformat: function (value, allValues) {
4570         return 'XX' + value;
4571     }
4572 });
4573 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4574 </code></pre>
4575 * For more information see this blog post with examples:
4576 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4577      - Create Elements using DOM, HTML fragments and Templates</a>. 
4578 * @constructor
4579 * @param {Object} cfg - Configuration object.
4580 */
4581 Roo.Template = function(cfg){
4582     // BC!
4583     if(cfg instanceof Array){
4584         cfg = cfg.join("");
4585     }else if(arguments.length > 1){
4586         cfg = Array.prototype.join.call(arguments, "");
4587     }
4588     
4589     
4590     if (typeof(cfg) == 'object') {
4591         Roo.apply(this,cfg)
4592     } else {
4593         // bc
4594         this.html = cfg;
4595     }
4596     if (this.url) {
4597         this.load();
4598     }
4599     
4600 };
4601 Roo.Template.prototype = {
4602     
4603     /**
4604      * @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..
4605      *                    it should be fixed so that template is observable...
4606      */
4607     url : false,
4608     /**
4609      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4610      */
4611     html : '',
4612     /**
4613      * Returns an HTML fragment of this template with the specified values applied.
4614      * @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'})
4615      * @return {String} The HTML fragment
4616      */
4617     applyTemplate : function(values){
4618         try {
4619            
4620             if(this.compiled){
4621                 return this.compiled(values);
4622             }
4623             var useF = this.disableFormats !== true;
4624             var fm = Roo.util.Format, tpl = this;
4625             var fn = function(m, name, format, args){
4626                 if(format && useF){
4627                     if(format.substr(0, 5) == "this."){
4628                         return tpl.call(format.substr(5), values[name], values);
4629                     }else{
4630                         if(args){
4631                             // quoted values are required for strings in compiled templates, 
4632                             // but for non compiled we need to strip them
4633                             // quoted reversed for jsmin
4634                             var re = /^\s*['"](.*)["']\s*$/;
4635                             args = args.split(',');
4636                             for(var i = 0, len = args.length; i < len; i++){
4637                                 args[i] = args[i].replace(re, "$1");
4638                             }
4639                             args = [values[name]].concat(args);
4640                         }else{
4641                             args = [values[name]];
4642                         }
4643                         return fm[format].apply(fm, args);
4644                     }
4645                 }else{
4646                     return values[name] !== undefined ? values[name] : "";
4647                 }
4648             };
4649             return this.html.replace(this.re, fn);
4650         } catch (e) {
4651             Roo.log(e);
4652             throw e;
4653         }
4654          
4655     },
4656     
4657     loading : false,
4658       
4659     load : function ()
4660     {
4661          
4662         if (this.loading) {
4663             return;
4664         }
4665         var _t = this;
4666         
4667         this.loading = true;
4668         this.compiled = false;
4669         
4670         var cx = new Roo.data.Connection();
4671         cx.request({
4672             url : this.url,
4673             method : 'GET',
4674             success : function (response) {
4675                 _t.loading = false;
4676                 _t.html = response.responseText;
4677                 _t.url = false;
4678                 _t.compile();
4679              },
4680             failure : function(response) {
4681                 Roo.log("Template failed to load from " + _t.url);
4682                 _t.loading = false;
4683             }
4684         });
4685     },
4686
4687     /**
4688      * Sets the HTML used as the template and optionally compiles it.
4689      * @param {String} html
4690      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4691      * @return {Roo.Template} this
4692      */
4693     set : function(html, compile){
4694         this.html = html;
4695         this.compiled = null;
4696         if(compile){
4697             this.compile();
4698         }
4699         return this;
4700     },
4701     
4702     /**
4703      * True to disable format functions (defaults to false)
4704      * @type Boolean
4705      */
4706     disableFormats : false,
4707     
4708     /**
4709     * The regular expression used to match template variables 
4710     * @type RegExp
4711     * @property 
4712     */
4713     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4714     
4715     /**
4716      * Compiles the template into an internal function, eliminating the RegEx overhead.
4717      * @return {Roo.Template} this
4718      */
4719     compile : function(){
4720         var fm = Roo.util.Format;
4721         var useF = this.disableFormats !== true;
4722         var sep = Roo.isGecko ? "+" : ",";
4723         var fn = function(m, name, format, args){
4724             if(format && useF){
4725                 args = args ? ',' + args : "";
4726                 if(format.substr(0, 5) != "this."){
4727                     format = "fm." + format + '(';
4728                 }else{
4729                     format = 'this.call("'+ format.substr(5) + '", ';
4730                     args = ", values";
4731                 }
4732             }else{
4733                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4734             }
4735             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4736         };
4737         var body;
4738         // branched to use + in gecko and [].join() in others
4739         if(Roo.isGecko){
4740             body = "this.compiled = function(values){ return '" +
4741                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4742                     "';};";
4743         }else{
4744             body = ["this.compiled = function(values){ return ['"];
4745             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4746             body.push("'].join('');};");
4747             body = body.join('');
4748         }
4749         /**
4750          * eval:var:values
4751          * eval:var:fm
4752          */
4753         eval(body);
4754         return this;
4755     },
4756     
4757     // private function used to call members
4758     call : function(fnName, value, allValues){
4759         return this[fnName](value, allValues);
4760     },
4761     
4762     /**
4763      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4764      * @param {String/HTMLElement/Roo.Element} el The context element
4765      * @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'})
4766      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4767      * @return {HTMLElement/Roo.Element} The new node or Element
4768      */
4769     insertFirst: function(el, values, returnElement){
4770         return this.doInsert('afterBegin', el, values, returnElement);
4771     },
4772
4773     /**
4774      * Applies the supplied values to the template and inserts the new node(s) before el.
4775      * @param {String/HTMLElement/Roo.Element} el The context element
4776      * @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'})
4777      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778      * @return {HTMLElement/Roo.Element} The new node or Element
4779      */
4780     insertBefore: function(el, values, returnElement){
4781         return this.doInsert('beforeBegin', el, values, returnElement);
4782     },
4783
4784     /**
4785      * Applies the supplied values to the template and inserts the new node(s) after el.
4786      * @param {String/HTMLElement/Roo.Element} el The context element
4787      * @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'})
4788      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789      * @return {HTMLElement/Roo.Element} The new node or Element
4790      */
4791     insertAfter : function(el, values, returnElement){
4792         return this.doInsert('afterEnd', el, values, returnElement);
4793     },
4794     
4795     /**
4796      * Applies the supplied values to the template and appends the new node(s) to el.
4797      * @param {String/HTMLElement/Roo.Element} el The context element
4798      * @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'})
4799      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4800      * @return {HTMLElement/Roo.Element} The new node or Element
4801      */
4802     append : function(el, values, returnElement){
4803         return this.doInsert('beforeEnd', el, values, returnElement);
4804     },
4805
4806     doInsert : function(where, el, values, returnEl){
4807         el = Roo.getDom(el);
4808         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4809         return returnEl ? Roo.get(newNode, true) : newNode;
4810     },
4811
4812     /**
4813      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4814      * @param {String/HTMLElement/Roo.Element} el The context element
4815      * @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'})
4816      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4817      * @return {HTMLElement/Roo.Element} The new node or Element
4818      */
4819     overwrite : function(el, values, returnElement){
4820         el = Roo.getDom(el);
4821         el.innerHTML = this.applyTemplate(values);
4822         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4823     }
4824 };
4825 /**
4826  * Alias for {@link #applyTemplate}
4827  * @method
4828  */
4829 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4830
4831 // backwards compat
4832 Roo.DomHelper.Template = Roo.Template;
4833
4834 /**
4835  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4836  * @param {String/HTMLElement} el A DOM element or its id
4837  * @returns {Roo.Template} The created template
4838  * @static
4839  */
4840 Roo.Template.from = function(el){
4841     el = Roo.getDom(el);
4842     return new Roo.Template(el.value || el.innerHTML);
4843 };/*
4844  * Based on:
4845  * Ext JS Library 1.1.1
4846  * Copyright(c) 2006-2007, Ext JS, LLC.
4847  *
4848  * Originally Released Under LGPL - original licence link has changed is not relivant.
4849  *
4850  * Fork - LGPL
4851  * <script type="text/javascript">
4852  */
4853  
4854
4855 /*
4856  * This is code is also distributed under MIT license for use
4857  * with jQuery and prototype JavaScript libraries.
4858  */
4859 /**
4860  * @class Roo.DomQuery
4861 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).
4862 <p>
4863 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>
4864
4865 <p>
4866 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.
4867 </p>
4868 <h4>Element Selectors:</h4>
4869 <ul class="list">
4870     <li> <b>*</b> any element</li>
4871     <li> <b>E</b> an element with the tag E</li>
4872     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4873     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4874     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4875     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4876 </ul>
4877 <h4>Attribute Selectors:</h4>
4878 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4879 <ul class="list">
4880     <li> <b>E[foo]</b> has an attribute "foo"</li>
4881     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4882     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4883     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4884     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4885     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4886     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4887 </ul>
4888 <h4>Pseudo Classes:</h4>
4889 <ul class="list">
4890     <li> <b>E:first-child</b> E is the first child of its parent</li>
4891     <li> <b>E:last-child</b> E is the last child of its parent</li>
4892     <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>
4893     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4894     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4895     <li> <b>E:only-child</b> E is the only child of its parent</li>
4896     <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>
4897     <li> <b>E:first</b> the first E in the resultset</li>
4898     <li> <b>E:last</b> the last E in the resultset</li>
4899     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4900     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4901     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4902     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4903     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4904     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4905     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4906     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4907     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4908 </ul>
4909 <h4>CSS Value Selectors:</h4>
4910 <ul class="list">
4911     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4912     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4913     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4914     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4915     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4916     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4917 </ul>
4918  * @singleton
4919  */
4920 Roo.DomQuery = function(){
4921     var cache = {}, simpleCache = {}, valueCache = {};
4922     var nonSpace = /\S/;
4923     var trimRe = /^\s+|\s+$/g;
4924     var tplRe = /\{(\d+)\}/g;
4925     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4926     var tagTokenRe = /^(#)?([\w-\*]+)/;
4927     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4928
4929     function child(p, index){
4930         var i = 0;
4931         var n = p.firstChild;
4932         while(n){
4933             if(n.nodeType == 1){
4934                if(++i == index){
4935                    return n;
4936                }
4937             }
4938             n = n.nextSibling;
4939         }
4940         return null;
4941     };
4942
4943     function next(n){
4944         while((n = n.nextSibling) && n.nodeType != 1);
4945         return n;
4946     };
4947
4948     function prev(n){
4949         while((n = n.previousSibling) && n.nodeType != 1);
4950         return n;
4951     };
4952
4953     function children(d){
4954         var n = d.firstChild, ni = -1;
4955             while(n){
4956                 var nx = n.nextSibling;
4957                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4958                     d.removeChild(n);
4959                 }else{
4960                     n.nodeIndex = ++ni;
4961                 }
4962                 n = nx;
4963             }
4964             return this;
4965         };
4966
4967     function byClassName(c, a, v){
4968         if(!v){
4969             return c;
4970         }
4971         var r = [], ri = -1, cn;
4972         for(var i = 0, ci; ci = c[i]; i++){
4973             if((' '+ci.className+' ').indexOf(v) != -1){
4974                 r[++ri] = ci;
4975             }
4976         }
4977         return r;
4978     };
4979
4980     function attrValue(n, attr){
4981         if(!n.tagName && typeof n.length != "undefined"){
4982             n = n[0];
4983         }
4984         if(!n){
4985             return null;
4986         }
4987         if(attr == "for"){
4988             return n.htmlFor;
4989         }
4990         if(attr == "class" || attr == "className"){
4991             return n.className;
4992         }
4993         return n.getAttribute(attr) || n[attr];
4994
4995     };
4996
4997     function getNodes(ns, mode, tagName){
4998         var result = [], ri = -1, cs;
4999         if(!ns){
5000             return result;
5001         }
5002         tagName = tagName || "*";
5003         if(typeof ns.getElementsByTagName != "undefined"){
5004             ns = [ns];
5005         }
5006         if(!mode){
5007             for(var i = 0, ni; ni = ns[i]; i++){
5008                 cs = ni.getElementsByTagName(tagName);
5009                 for(var j = 0, ci; ci = cs[j]; j++){
5010                     result[++ri] = ci;
5011                 }
5012             }
5013         }else if(mode == "/" || mode == ">"){
5014             var utag = tagName.toUpperCase();
5015             for(var i = 0, ni, cn; ni = ns[i]; i++){
5016                 cn = ni.children || ni.childNodes;
5017                 for(var j = 0, cj; cj = cn[j]; j++){
5018                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5019                         result[++ri] = cj;
5020                     }
5021                 }
5022             }
5023         }else if(mode == "+"){
5024             var utag = tagName.toUpperCase();
5025             for(var i = 0, n; n = ns[i]; i++){
5026                 while((n = n.nextSibling) && n.nodeType != 1);
5027                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5028                     result[++ri] = n;
5029                 }
5030             }
5031         }else if(mode == "~"){
5032             for(var i = 0, n; n = ns[i]; i++){
5033                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5034                 if(n){
5035                     result[++ri] = n;
5036                 }
5037             }
5038         }
5039         return result;
5040     };
5041
5042     function concat(a, b){
5043         if(b.slice){
5044             return a.concat(b);
5045         }
5046         for(var i = 0, l = b.length; i < l; i++){
5047             a[a.length] = b[i];
5048         }
5049         return a;
5050     }
5051
5052     function byTag(cs, tagName){
5053         if(cs.tagName || cs == document){
5054             cs = [cs];
5055         }
5056         if(!tagName){
5057             return cs;
5058         }
5059         var r = [], ri = -1;
5060         tagName = tagName.toLowerCase();
5061         for(var i = 0, ci; ci = cs[i]; i++){
5062             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5063                 r[++ri] = ci;
5064             }
5065         }
5066         return r;
5067     };
5068
5069     function byId(cs, attr, id){
5070         if(cs.tagName || cs == document){
5071             cs = [cs];
5072         }
5073         if(!id){
5074             return cs;
5075         }
5076         var r = [], ri = -1;
5077         for(var i = 0,ci; ci = cs[i]; i++){
5078             if(ci && ci.id == id){
5079                 r[++ri] = ci;
5080                 return r;
5081             }
5082         }
5083         return r;
5084     };
5085
5086     function byAttribute(cs, attr, value, op, custom){
5087         var r = [], ri = -1, st = custom=="{";
5088         var f = Roo.DomQuery.operators[op];
5089         for(var i = 0, ci; ci = cs[i]; i++){
5090             var a;
5091             if(st){
5092                 a = Roo.DomQuery.getStyle(ci, attr);
5093             }
5094             else if(attr == "class" || attr == "className"){
5095                 a = ci.className;
5096             }else if(attr == "for"){
5097                 a = ci.htmlFor;
5098             }else if(attr == "href"){
5099                 a = ci.getAttribute("href", 2);
5100             }else{
5101                 a = ci.getAttribute(attr);
5102             }
5103             if((f && f(a, value)) || (!f && a)){
5104                 r[++ri] = ci;
5105             }
5106         }
5107         return r;
5108     };
5109
5110     function byPseudo(cs, name, value){
5111         return Roo.DomQuery.pseudos[name](cs, value);
5112     };
5113
5114     // This is for IE MSXML which does not support expandos.
5115     // IE runs the same speed using setAttribute, however FF slows way down
5116     // and Safari completely fails so they need to continue to use expandos.
5117     var isIE = window.ActiveXObject ? true : false;
5118
5119     // this eval is stop the compressor from
5120     // renaming the variable to something shorter
5121     
5122     /** eval:var:batch */
5123     var batch = 30803; 
5124
5125     var key = 30803;
5126
5127     function nodupIEXml(cs){
5128         var d = ++key;
5129         cs[0].setAttribute("_nodup", d);
5130         var r = [cs[0]];
5131         for(var i = 1, len = cs.length; i < len; i++){
5132             var c = cs[i];
5133             if(!c.getAttribute("_nodup") != d){
5134                 c.setAttribute("_nodup", d);
5135                 r[r.length] = c;
5136             }
5137         }
5138         for(var i = 0, len = cs.length; i < len; i++){
5139             cs[i].removeAttribute("_nodup");
5140         }
5141         return r;
5142     }
5143
5144     function nodup(cs){
5145         if(!cs){
5146             return [];
5147         }
5148         var len = cs.length, c, i, r = cs, cj, ri = -1;
5149         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5150             return cs;
5151         }
5152         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5153             return nodupIEXml(cs);
5154         }
5155         var d = ++key;
5156         cs[0]._nodup = d;
5157         for(i = 1; c = cs[i]; i++){
5158             if(c._nodup != d){
5159                 c._nodup = d;
5160             }else{
5161                 r = [];
5162                 for(var j = 0; j < i; j++){
5163                     r[++ri] = cs[j];
5164                 }
5165                 for(j = i+1; cj = cs[j]; j++){
5166                     if(cj._nodup != d){
5167                         cj._nodup = d;
5168                         r[++ri] = cj;
5169                     }
5170                 }
5171                 return r;
5172             }
5173         }
5174         return r;
5175     }
5176
5177     function quickDiffIEXml(c1, c2){
5178         var d = ++key;
5179         for(var i = 0, len = c1.length; i < len; i++){
5180             c1[i].setAttribute("_qdiff", d);
5181         }
5182         var r = [];
5183         for(var i = 0, len = c2.length; i < len; i++){
5184             if(c2[i].getAttribute("_qdiff") != d){
5185                 r[r.length] = c2[i];
5186             }
5187         }
5188         for(var i = 0, len = c1.length; i < len; i++){
5189            c1[i].removeAttribute("_qdiff");
5190         }
5191         return r;
5192     }
5193
5194     function quickDiff(c1, c2){
5195         var len1 = c1.length;
5196         if(!len1){
5197             return c2;
5198         }
5199         if(isIE && c1[0].selectSingleNode){
5200             return quickDiffIEXml(c1, c2);
5201         }
5202         var d = ++key;
5203         for(var i = 0; i < len1; i++){
5204             c1[i]._qdiff = d;
5205         }
5206         var r = [];
5207         for(var i = 0, len = c2.length; i < len; i++){
5208             if(c2[i]._qdiff != d){
5209                 r[r.length] = c2[i];
5210             }
5211         }
5212         return r;
5213     }
5214
5215     function quickId(ns, mode, root, id){
5216         if(ns == root){
5217            var d = root.ownerDocument || root;
5218            return d.getElementById(id);
5219         }
5220         ns = getNodes(ns, mode, "*");
5221         return byId(ns, null, id);
5222     }
5223
5224     return {
5225         getStyle : function(el, name){
5226             return Roo.fly(el).getStyle(name);
5227         },
5228         /**
5229          * Compiles a selector/xpath query into a reusable function. The returned function
5230          * takes one parameter "root" (optional), which is the context node from where the query should start.
5231          * @param {String} selector The selector/xpath query
5232          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5233          * @return {Function}
5234          */
5235         compile : function(path, type){
5236             type = type || "select";
5237             
5238             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5239             var q = path, mode, lq;
5240             var tk = Roo.DomQuery.matchers;
5241             var tklen = tk.length;
5242             var mm;
5243
5244             // accept leading mode switch
5245             var lmode = q.match(modeRe);
5246             if(lmode && lmode[1]){
5247                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5248                 q = q.replace(lmode[1], "");
5249             }
5250             // strip leading slashes
5251             while(path.substr(0, 1)=="/"){
5252                 path = path.substr(1);
5253             }
5254
5255             while(q && lq != q){
5256                 lq = q;
5257                 var tm = q.match(tagTokenRe);
5258                 if(type == "select"){
5259                     if(tm){
5260                         if(tm[1] == "#"){
5261                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5262                         }else{
5263                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5264                         }
5265                         q = q.replace(tm[0], "");
5266                     }else if(q.substr(0, 1) != '@'){
5267                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5268                     }
5269                 }else{
5270                     if(tm){
5271                         if(tm[1] == "#"){
5272                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5273                         }else{
5274                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5275                         }
5276                         q = q.replace(tm[0], "");
5277                     }
5278                 }
5279                 while(!(mm = q.match(modeRe))){
5280                     var matched = false;
5281                     for(var j = 0; j < tklen; j++){
5282                         var t = tk[j];
5283                         var m = q.match(t.re);
5284                         if(m){
5285                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5286                                                     return m[i];
5287                                                 });
5288                             q = q.replace(m[0], "");
5289                             matched = true;
5290                             break;
5291                         }
5292                     }
5293                     // prevent infinite loop on bad selector
5294                     if(!matched){
5295                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5296                     }
5297                 }
5298                 if(mm[1]){
5299                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5300                     q = q.replace(mm[1], "");
5301                 }
5302             }
5303             fn[fn.length] = "return nodup(n);\n}";
5304             
5305              /** 
5306               * list of variables that need from compression as they are used by eval.
5307              *  eval:var:batch 
5308              *  eval:var:nodup
5309              *  eval:var:byTag
5310              *  eval:var:ById
5311              *  eval:var:getNodes
5312              *  eval:var:quickId
5313              *  eval:var:mode
5314              *  eval:var:root
5315              *  eval:var:n
5316              *  eval:var:byClassName
5317              *  eval:var:byPseudo
5318              *  eval:var:byAttribute
5319              *  eval:var:attrValue
5320              * 
5321              **/ 
5322             eval(fn.join(""));
5323             return f;
5324         },
5325
5326         /**
5327          * Selects a group of elements.
5328          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5329          * @param {Node} root (optional) The start of the query (defaults to document).
5330          * @return {Array}
5331          */
5332         select : function(path, root, type){
5333             if(!root || root == document){
5334                 root = document;
5335             }
5336             if(typeof root == "string"){
5337                 root = document.getElementById(root);
5338             }
5339             var paths = path.split(",");
5340             var results = [];
5341             for(var i = 0, len = paths.length; i < len; i++){
5342                 var p = paths[i].replace(trimRe, "");
5343                 if(!cache[p]){
5344                     cache[p] = Roo.DomQuery.compile(p);
5345                     if(!cache[p]){
5346                         throw p + " is not a valid selector";
5347                     }
5348                 }
5349                 var result = cache[p](root);
5350                 if(result && result != document){
5351                     results = results.concat(result);
5352                 }
5353             }
5354             if(paths.length > 1){
5355                 return nodup(results);
5356             }
5357             return results;
5358         },
5359
5360         /**
5361          * Selects a single element.
5362          * @param {String} selector The selector/xpath query
5363          * @param {Node} root (optional) The start of the query (defaults to document).
5364          * @return {Element}
5365          */
5366         selectNode : function(path, root){
5367             return Roo.DomQuery.select(path, root)[0];
5368         },
5369
5370         /**
5371          * Selects the value of a node, optionally replacing null with the defaultValue.
5372          * @param {String} selector The selector/xpath query
5373          * @param {Node} root (optional) The start of the query (defaults to document).
5374          * @param {String} defaultValue
5375          */
5376         selectValue : function(path, root, defaultValue){
5377             path = path.replace(trimRe, "");
5378             if(!valueCache[path]){
5379                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5380             }
5381             var n = valueCache[path](root);
5382             n = n[0] ? n[0] : n;
5383             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5384             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5385         },
5386
5387         /**
5388          * Selects the value of a node, parsing integers and floats.
5389          * @param {String} selector The selector/xpath query
5390          * @param {Node} root (optional) The start of the query (defaults to document).
5391          * @param {Number} defaultValue
5392          * @return {Number}
5393          */
5394         selectNumber : function(path, root, defaultValue){
5395             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5396             return parseFloat(v);
5397         },
5398
5399         /**
5400          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5401          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5402          * @param {String} selector The simple selector to test
5403          * @return {Boolean}
5404          */
5405         is : function(el, ss){
5406             if(typeof el == "string"){
5407                 el = document.getElementById(el);
5408             }
5409             var isArray = (el instanceof Array);
5410             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5411             return isArray ? (result.length == el.length) : (result.length > 0);
5412         },
5413
5414         /**
5415          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5416          * @param {Array} el An array of elements to filter
5417          * @param {String} selector The simple selector to test
5418          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5419          * the selector instead of the ones that match
5420          * @return {Array}
5421          */
5422         filter : function(els, ss, nonMatches){
5423             ss = ss.replace(trimRe, "");
5424             if(!simpleCache[ss]){
5425                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5426             }
5427             var result = simpleCache[ss](els);
5428             return nonMatches ? quickDiff(result, els) : result;
5429         },
5430
5431         /**
5432          * Collection of matching regular expressions and code snippets.
5433          */
5434         matchers : [{
5435                 re: /^\.([\w-]+)/,
5436                 select: 'n = byClassName(n, null, " {1} ");'
5437             }, {
5438                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5439                 select: 'n = byPseudo(n, "{1}", "{2}");'
5440             },{
5441                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5442                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5443             }, {
5444                 re: /^#([\w-]+)/,
5445                 select: 'n = byId(n, null, "{1}");'
5446             },{
5447                 re: /^@([\w-]+)/,
5448                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5449             }
5450         ],
5451
5452         /**
5453          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5454          * 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;.
5455          */
5456         operators : {
5457             "=" : function(a, v){
5458                 return a == v;
5459             },
5460             "!=" : function(a, v){
5461                 return a != v;
5462             },
5463             "^=" : function(a, v){
5464                 return a && a.substr(0, v.length) == v;
5465             },
5466             "$=" : function(a, v){
5467                 return a && a.substr(a.length-v.length) == v;
5468             },
5469             "*=" : function(a, v){
5470                 return a && a.indexOf(v) !== -1;
5471             },
5472             "%=" : function(a, v){
5473                 return (a % v) == 0;
5474             },
5475             "|=" : function(a, v){
5476                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5477             },
5478             "~=" : function(a, v){
5479                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5480             }
5481         },
5482
5483         /**
5484          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5485          * and the argument (if any) supplied in the selector.
5486          */
5487         pseudos : {
5488             "first-child" : function(c){
5489                 var r = [], ri = -1, n;
5490                 for(var i = 0, ci; ci = n = c[i]; i++){
5491                     while((n = n.previousSibling) && n.nodeType != 1);
5492                     if(!n){
5493                         r[++ri] = ci;
5494                     }
5495                 }
5496                 return r;
5497             },
5498
5499             "last-child" : function(c){
5500                 var r = [], ri = -1, n;
5501                 for(var i = 0, ci; ci = n = c[i]; i++){
5502                     while((n = n.nextSibling) && n.nodeType != 1);
5503                     if(!n){
5504                         r[++ri] = ci;
5505                     }
5506                 }
5507                 return r;
5508             },
5509
5510             "nth-child" : function(c, a) {
5511                 var r = [], ri = -1;
5512                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5513                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5514                 for(var i = 0, n; n = c[i]; i++){
5515                     var pn = n.parentNode;
5516                     if (batch != pn._batch) {
5517                         var j = 0;
5518                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5519                             if(cn.nodeType == 1){
5520                                cn.nodeIndex = ++j;
5521                             }
5522                         }
5523                         pn._batch = batch;
5524                     }
5525                     if (f == 1) {
5526                         if (l == 0 || n.nodeIndex == l){
5527                             r[++ri] = n;
5528                         }
5529                     } else if ((n.nodeIndex + l) % f == 0){
5530                         r[++ri] = n;
5531                     }
5532                 }
5533
5534                 return r;
5535             },
5536
5537             "only-child" : function(c){
5538                 var r = [], ri = -1;;
5539                 for(var i = 0, ci; ci = c[i]; i++){
5540                     if(!prev(ci) && !next(ci)){
5541                         r[++ri] = ci;
5542                     }
5543                 }
5544                 return r;
5545             },
5546
5547             "empty" : function(c){
5548                 var r = [], ri = -1;
5549                 for(var i = 0, ci; ci = c[i]; i++){
5550                     var cns = ci.childNodes, j = 0, cn, empty = true;
5551                     while(cn = cns[j]){
5552                         ++j;
5553                         if(cn.nodeType == 1 || cn.nodeType == 3){
5554                             empty = false;
5555                             break;
5556                         }
5557                     }
5558                     if(empty){
5559                         r[++ri] = ci;
5560                     }
5561                 }
5562                 return r;
5563             },
5564
5565             "contains" : function(c, v){
5566                 var r = [], ri = -1;
5567                 for(var i = 0, ci; ci = c[i]; i++){
5568                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5569                         r[++ri] = ci;
5570                     }
5571                 }
5572                 return r;
5573             },
5574
5575             "nodeValue" : function(c, v){
5576                 var r = [], ri = -1;
5577                 for(var i = 0, ci; ci = c[i]; i++){
5578                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5579                         r[++ri] = ci;
5580                     }
5581                 }
5582                 return r;
5583             },
5584
5585             "checked" : function(c){
5586                 var r = [], ri = -1;
5587                 for(var i = 0, ci; ci = c[i]; i++){
5588                     if(ci.checked == true){
5589                         r[++ri] = ci;
5590                     }
5591                 }
5592                 return r;
5593             },
5594
5595             "not" : function(c, ss){
5596                 return Roo.DomQuery.filter(c, ss, true);
5597             },
5598
5599             "odd" : function(c){
5600                 return this["nth-child"](c, "odd");
5601             },
5602
5603             "even" : function(c){
5604                 return this["nth-child"](c, "even");
5605             },
5606
5607             "nth" : function(c, a){
5608                 return c[a-1] || [];
5609             },
5610
5611             "first" : function(c){
5612                 return c[0] || [];
5613             },
5614
5615             "last" : function(c){
5616                 return c[c.length-1] || [];
5617             },
5618
5619             "has" : function(c, ss){
5620                 var s = Roo.DomQuery.select;
5621                 var r = [], ri = -1;
5622                 for(var i = 0, ci; ci = c[i]; i++){
5623                     if(s(ss, ci).length > 0){
5624                         r[++ri] = ci;
5625                     }
5626                 }
5627                 return r;
5628             },
5629
5630             "next" : function(c, ss){
5631                 var is = Roo.DomQuery.is;
5632                 var r = [], ri = -1;
5633                 for(var i = 0, ci; ci = c[i]; i++){
5634                     var n = next(ci);
5635                     if(n && is(n, ss)){
5636                         r[++ri] = ci;
5637                     }
5638                 }
5639                 return r;
5640             },
5641
5642             "prev" : function(c, ss){
5643                 var is = Roo.DomQuery.is;
5644                 var r = [], ri = -1;
5645                 for(var i = 0, ci; ci = c[i]; i++){
5646                     var n = prev(ci);
5647                     if(n && is(n, ss)){
5648                         r[++ri] = ci;
5649                     }
5650                 }
5651                 return r;
5652             }
5653         }
5654     };
5655 }();
5656
5657 /**
5658  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5659  * @param {String} path The selector/xpath query
5660  * @param {Node} root (optional) The start of the query (defaults to document).
5661  * @return {Array}
5662  * @member Roo
5663  * @method query
5664  */
5665 Roo.query = Roo.DomQuery.select;
5666 /*
5667  * Based on:
5668  * Ext JS Library 1.1.1
5669  * Copyright(c) 2006-2007, Ext JS, LLC.
5670  *
5671  * Originally Released Under LGPL - original licence link has changed is not relivant.
5672  *
5673  * Fork - LGPL
5674  * <script type="text/javascript">
5675  */
5676
5677 /**
5678  * @class Roo.util.Observable
5679  * Base class that provides a common interface for publishing events. Subclasses are expected to
5680  * to have a property "events" with all the events defined.<br>
5681  * For example:
5682  * <pre><code>
5683  Employee = function(name){
5684     this.name = name;
5685     this.addEvents({
5686         "fired" : true,
5687         "quit" : true
5688     });
5689  }
5690  Roo.extend(Employee, Roo.util.Observable);
5691 </code></pre>
5692  * @param {Object} config properties to use (incuding events / listeners)
5693  */
5694
5695 Roo.util.Observable = function(cfg){
5696     
5697     cfg = cfg|| {};
5698     this.addEvents(cfg.events || {});
5699     if (cfg.events) {
5700         delete cfg.events; // make sure
5701     }
5702      
5703     Roo.apply(this, cfg);
5704     
5705     if(this.listeners){
5706         this.on(this.listeners);
5707         delete this.listeners;
5708     }
5709 };
5710 Roo.util.Observable.prototype = {
5711     /** 
5712  * @cfg {Object} listeners  list of events and functions to call for this object, 
5713  * For example :
5714  * <pre><code>
5715     listeners :  { 
5716        'click' : function(e) {
5717            ..... 
5718         } ,
5719         .... 
5720     } 
5721   </code></pre>
5722  */
5723     
5724     
5725     /**
5726      * Fires the specified event with the passed parameters (minus the event name).
5727      * @param {String} eventName
5728      * @param {Object...} args Variable number of parameters are passed to handlers
5729      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5730      */
5731     fireEvent : function(){
5732         var ce = this.events[arguments[0].toLowerCase()];
5733         if(typeof ce == "object"){
5734             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5735         }else{
5736             return true;
5737         }
5738     },
5739
5740     // private
5741     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5742
5743     /**
5744      * Appends an event handler to this component
5745      * @param {String}   eventName The type of event to listen for
5746      * @param {Function} handler The method the event invokes
5747      * @param {Object}   scope (optional) The scope in which to execute the handler
5748      * function. The handler function's "this" context.
5749      * @param {Object}   options (optional) An object containing handler configuration
5750      * properties. This may contain any of the following properties:<ul>
5751      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5752      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5753      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5754      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5755      * by the specified number of milliseconds. If the event fires again within that time, the original
5756      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5757      * </ul><br>
5758      * <p>
5759      * <b>Combining Options</b><br>
5760      * Using the options argument, it is possible to combine different types of listeners:<br>
5761      * <br>
5762      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5763                 <pre><code>
5764                 el.on('click', this.onClick, this, {
5765                         single: true,
5766                 delay: 100,
5767                 forumId: 4
5768                 });
5769                 </code></pre>
5770      * <p>
5771      * <b>Attaching multiple handlers in 1 call</b><br>
5772      * The method also allows for a single argument to be passed which is a config object containing properties
5773      * which specify multiple handlers.
5774      * <pre><code>
5775                 el.on({
5776                         'click': {
5777                         fn: this.onClick,
5778                         scope: this,
5779                         delay: 100
5780                 }, 
5781                 'mouseover': {
5782                         fn: this.onMouseOver,
5783                         scope: this
5784                 },
5785                 'mouseout': {
5786                         fn: this.onMouseOut,
5787                         scope: this
5788                 }
5789                 });
5790                 </code></pre>
5791      * <p>
5792      * Or a shorthand syntax which passes the same scope object to all handlers:
5793         <pre><code>
5794                 el.on({
5795                         'click': this.onClick,
5796                 'mouseover': this.onMouseOver,
5797                 'mouseout': this.onMouseOut,
5798                 scope: this
5799                 });
5800                 </code></pre>
5801      */
5802     addListener : function(eventName, fn, scope, o){
5803         if(typeof eventName == "object"){
5804             o = eventName;
5805             for(var e in o){
5806                 if(this.filterOptRe.test(e)){
5807                     continue;
5808                 }
5809                 if(typeof o[e] == "function"){
5810                     // shared options
5811                     this.addListener(e, o[e], o.scope,  o);
5812                 }else{
5813                     // individual options
5814                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5815                 }
5816             }
5817             return;
5818         }
5819         o = (!o || typeof o == "boolean") ? {} : o;
5820         eventName = eventName.toLowerCase();
5821         var ce = this.events[eventName] || true;
5822         if(typeof ce == "boolean"){
5823             ce = new Roo.util.Event(this, eventName);
5824             this.events[eventName] = ce;
5825         }
5826         ce.addListener(fn, scope, o);
5827     },
5828
5829     /**
5830      * Removes a listener
5831      * @param {String}   eventName     The type of event to listen for
5832      * @param {Function} handler        The handler to remove
5833      * @param {Object}   scope  (optional) The scope (this object) for the handler
5834      */
5835     removeListener : function(eventName, fn, scope){
5836         var ce = this.events[eventName.toLowerCase()];
5837         if(typeof ce == "object"){
5838             ce.removeListener(fn, scope);
5839         }
5840     },
5841
5842     /**
5843      * Removes all listeners for this object
5844      */
5845     purgeListeners : function(){
5846         for(var evt in this.events){
5847             if(typeof this.events[evt] == "object"){
5848                  this.events[evt].clearListeners();
5849             }
5850         }
5851     },
5852
5853     relayEvents : function(o, events){
5854         var createHandler = function(ename){
5855             return function(){
5856                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5857             };
5858         };
5859         for(var i = 0, len = events.length; i < len; i++){
5860             var ename = events[i];
5861             if(!this.events[ename]){ this.events[ename] = true; };
5862             o.on(ename, createHandler(ename), this);
5863         }
5864     },
5865
5866     /**
5867      * Used to define events on this Observable
5868      * @param {Object} object The object with the events defined
5869      */
5870     addEvents : function(o){
5871         if(!this.events){
5872             this.events = {};
5873         }
5874         Roo.applyIf(this.events, o);
5875     },
5876
5877     /**
5878      * Checks to see if this object has any listeners for a specified event
5879      * @param {String} eventName The name of the event to check for
5880      * @return {Boolean} True if the event is being listened for, else false
5881      */
5882     hasListener : function(eventName){
5883         var e = this.events[eventName];
5884         return typeof e == "object" && e.listeners.length > 0;
5885     }
5886 };
5887 /**
5888  * Appends an event handler to this element (shorthand for addListener)
5889  * @param {String}   eventName     The type of event to listen for
5890  * @param {Function} handler        The method the event invokes
5891  * @param {Object}   scope (optional) The scope in which to execute the handler
5892  * function. The handler function's "this" context.
5893  * @param {Object}   options  (optional)
5894  * @method
5895  */
5896 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5897 /**
5898  * Removes a listener (shorthand for removeListener)
5899  * @param {String}   eventName     The type of event to listen for
5900  * @param {Function} handler        The handler to remove
5901  * @param {Object}   scope  (optional) The scope (this object) for the handler
5902  * @method
5903  */
5904 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5905
5906 /**
5907  * Starts capture on the specified Observable. All events will be passed
5908  * to the supplied function with the event name + standard signature of the event
5909  * <b>before</b> the event is fired. If the supplied function returns false,
5910  * the event will not fire.
5911  * @param {Observable} o The Observable to capture
5912  * @param {Function} fn The function to call
5913  * @param {Object} scope (optional) The scope (this object) for the fn
5914  * @static
5915  */
5916 Roo.util.Observable.capture = function(o, fn, scope){
5917     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5918 };
5919
5920 /**
5921  * Removes <b>all</b> added captures from the Observable.
5922  * @param {Observable} o The Observable to release
5923  * @static
5924  */
5925 Roo.util.Observable.releaseCapture = function(o){
5926     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5927 };
5928
5929 (function(){
5930
5931     var createBuffered = function(h, o, scope){
5932         var task = new Roo.util.DelayedTask();
5933         return function(){
5934             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5935         };
5936     };
5937
5938     var createSingle = function(h, e, fn, scope){
5939         return function(){
5940             e.removeListener(fn, scope);
5941             return h.apply(scope, arguments);
5942         };
5943     };
5944
5945     var createDelayed = function(h, o, scope){
5946         return function(){
5947             var args = Array.prototype.slice.call(arguments, 0);
5948             setTimeout(function(){
5949                 h.apply(scope, args);
5950             }, o.delay || 10);
5951         };
5952     };
5953
5954     Roo.util.Event = function(obj, name){
5955         this.name = name;
5956         this.obj = obj;
5957         this.listeners = [];
5958     };
5959
5960     Roo.util.Event.prototype = {
5961         addListener : function(fn, scope, options){
5962             var o = options || {};
5963             scope = scope || this.obj;
5964             if(!this.isListening(fn, scope)){
5965                 var l = {fn: fn, scope: scope, options: o};
5966                 var h = fn;
5967                 if(o.delay){
5968                     h = createDelayed(h, o, scope);
5969                 }
5970                 if(o.single){
5971                     h = createSingle(h, this, fn, scope);
5972                 }
5973                 if(o.buffer){
5974                     h = createBuffered(h, o, scope);
5975                 }
5976                 l.fireFn = h;
5977                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5978                     this.listeners.push(l);
5979                 }else{
5980                     this.listeners = this.listeners.slice(0);
5981                     this.listeners.push(l);
5982                 }
5983             }
5984         },
5985
5986         findListener : function(fn, scope){
5987             scope = scope || this.obj;
5988             var ls = this.listeners;
5989             for(var i = 0, len = ls.length; i < len; i++){
5990                 var l = ls[i];
5991                 if(l.fn == fn && l.scope == scope){
5992                     return i;
5993                 }
5994             }
5995             return -1;
5996         },
5997
5998         isListening : function(fn, scope){
5999             return this.findListener(fn, scope) != -1;
6000         },
6001
6002         removeListener : function(fn, scope){
6003             var index;
6004             if((index = this.findListener(fn, scope)) != -1){
6005                 if(!this.firing){
6006                     this.listeners.splice(index, 1);
6007                 }else{
6008                     this.listeners = this.listeners.slice(0);
6009                     this.listeners.splice(index, 1);
6010                 }
6011                 return true;
6012             }
6013             return false;
6014         },
6015
6016         clearListeners : function(){
6017             this.listeners = [];
6018         },
6019
6020         fire : function(){
6021             var ls = this.listeners, scope, len = ls.length;
6022             if(len > 0){
6023                 this.firing = true;
6024                 var args = Array.prototype.slice.call(arguments, 0);
6025                 for(var i = 0; i < len; i++){
6026                     var l = ls[i];
6027                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6028                         this.firing = false;
6029                         return false;
6030                     }
6031                 }
6032                 this.firing = false;
6033             }
6034             return true;
6035         }
6036     };
6037 })();/*
6038  * Based on:
6039  * Ext JS Library 1.1.1
6040  * Copyright(c) 2006-2007, Ext JS, LLC.
6041  *
6042  * Originally Released Under LGPL - original licence link has changed is not relivant.
6043  *
6044  * Fork - LGPL
6045  * <script type="text/javascript">
6046  */
6047
6048 /**
6049  * @class Roo.EventManager
6050  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6051  * several useful events directly.
6052  * See {@link Roo.EventObject} for more details on normalized event objects.
6053  * @singleton
6054  */
6055 Roo.EventManager = function(){
6056     var docReadyEvent, docReadyProcId, docReadyState = false;
6057     var resizeEvent, resizeTask, textEvent, textSize;
6058     var E = Roo.lib.Event;
6059     var D = Roo.lib.Dom;
6060
6061     
6062     
6063
6064     var fireDocReady = function(){
6065         if(!docReadyState){
6066             docReadyState = true;
6067             Roo.isReady = true;
6068             if(docReadyProcId){
6069                 clearInterval(docReadyProcId);
6070             }
6071             if(Roo.isGecko || Roo.isOpera) {
6072                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6073             }
6074             if(Roo.isIE){
6075                 var defer = document.getElementById("ie-deferred-loader");
6076                 if(defer){
6077                     defer.onreadystatechange = null;
6078                     defer.parentNode.removeChild(defer);
6079                 }
6080             }
6081             if(docReadyEvent){
6082                 docReadyEvent.fire();
6083                 docReadyEvent.clearListeners();
6084             }
6085         }
6086     };
6087     
6088     var initDocReady = function(){
6089         docReadyEvent = new Roo.util.Event();
6090         if(Roo.isGecko || Roo.isOpera) {
6091             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6092         }else if(Roo.isIE){
6093             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6094             var defer = document.getElementById("ie-deferred-loader");
6095             defer.onreadystatechange = function(){
6096                 if(this.readyState == "complete"){
6097                     fireDocReady();
6098                 }
6099             };
6100         }else if(Roo.isSafari){ 
6101             docReadyProcId = setInterval(function(){
6102                 var rs = document.readyState;
6103                 if(rs == "complete") {
6104                     fireDocReady();     
6105                  }
6106             }, 10);
6107         }
6108         // no matter what, make sure it fires on load
6109         E.on(window, "load", fireDocReady);
6110     };
6111
6112     var createBuffered = function(h, o){
6113         var task = new Roo.util.DelayedTask(h);
6114         return function(e){
6115             // create new event object impl so new events don't wipe out properties
6116             e = new Roo.EventObjectImpl(e);
6117             task.delay(o.buffer, h, null, [e]);
6118         };
6119     };
6120
6121     var createSingle = function(h, el, ename, fn){
6122         return function(e){
6123             Roo.EventManager.removeListener(el, ename, fn);
6124             h(e);
6125         };
6126     };
6127
6128     var createDelayed = function(h, o){
6129         return function(e){
6130             // create new event object impl so new events don't wipe out properties
6131             e = new Roo.EventObjectImpl(e);
6132             setTimeout(function(){
6133                 h(e);
6134             }, o.delay || 10);
6135         };
6136     };
6137     var transitionEndVal = false;
6138     
6139     var transitionEnd = function()
6140     {
6141         if (transitionEndVal) {
6142             return transitionEndVal;
6143         }
6144         var el = document.createElement('div');
6145
6146         var transEndEventNames = {
6147             WebkitTransition : 'webkitTransitionEnd',
6148             MozTransition    : 'transitionend',
6149             OTransition      : 'oTransitionEnd otransitionend',
6150             transition       : 'transitionend'
6151         };
6152     
6153         for (var name in transEndEventNames) {
6154             if (el.style[name] !== undefined) {
6155                 transitionEndVal = transEndEventNames[name];
6156                 return  transitionEndVal ;
6157             }
6158         }
6159     }
6160     
6161
6162     var listen = function(element, ename, opt, fn, scope){
6163         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6164         fn = fn || o.fn; scope = scope || o.scope;
6165         var el = Roo.getDom(element);
6166         
6167         
6168         if(!el){
6169             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6170         }
6171         
6172         if (ename == 'transitionend') {
6173             ename = transitionEnd();
6174         }
6175         var h = function(e){
6176             e = Roo.EventObject.setEvent(e);
6177             var t;
6178             if(o.delegate){
6179                 t = e.getTarget(o.delegate, el);
6180                 if(!t){
6181                     return;
6182                 }
6183             }else{
6184                 t = e.target;
6185             }
6186             if(o.stopEvent === true){
6187                 e.stopEvent();
6188             }
6189             if(o.preventDefault === true){
6190                e.preventDefault();
6191             }
6192             if(o.stopPropagation === true){
6193                 e.stopPropagation();
6194             }
6195
6196             if(o.normalized === false){
6197                 e = e.browserEvent;
6198             }
6199
6200             fn.call(scope || el, e, t, o);
6201         };
6202         if(o.delay){
6203             h = createDelayed(h, o);
6204         }
6205         if(o.single){
6206             h = createSingle(h, el, ename, fn);
6207         }
6208         if(o.buffer){
6209             h = createBuffered(h, o);
6210         }
6211         fn._handlers = fn._handlers || [];
6212         
6213         
6214         fn._handlers.push([Roo.id(el), ename, h]);
6215         
6216         
6217          
6218         E.on(el, ename, h);
6219         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6220             el.addEventListener("DOMMouseScroll", h, false);
6221             E.on(window, 'unload', function(){
6222                 el.removeEventListener("DOMMouseScroll", h, false);
6223             });
6224         }
6225         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6226             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6227         }
6228         return h;
6229     };
6230
6231     var stopListening = function(el, ename, fn){
6232         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6233         if(hds){
6234             for(var i = 0, len = hds.length; i < len; i++){
6235                 var h = hds[i];
6236                 if(h[0] == id && h[1] == ename){
6237                     hd = h[2];
6238                     hds.splice(i, 1);
6239                     break;
6240                 }
6241             }
6242         }
6243         E.un(el, ename, hd);
6244         el = Roo.getDom(el);
6245         if(ename == "mousewheel" && el.addEventListener){
6246             el.removeEventListener("DOMMouseScroll", hd, false);
6247         }
6248         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6249             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6250         }
6251     };
6252
6253     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6254     
6255     var pub = {
6256         
6257         
6258         /** 
6259          * Fix for doc tools
6260          * @scope Roo.EventManager
6261          */
6262         
6263         
6264         /** 
6265          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6266          * object with a Roo.EventObject
6267          * @param {Function} fn        The method the event invokes
6268          * @param {Object}   scope    An object that becomes the scope of the handler
6269          * @param {boolean}  override If true, the obj passed in becomes
6270          *                             the execution scope of the listener
6271          * @return {Function} The wrapped function
6272          * @deprecated
6273          */
6274         wrap : function(fn, scope, override){
6275             return function(e){
6276                 Roo.EventObject.setEvent(e);
6277                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6278             };
6279         },
6280         
6281         /**
6282      * Appends an event handler to an element (shorthand for addListener)
6283      * @param {String/HTMLElement}   element        The html element or id to assign the
6284      * @param {String}   eventName The type of event to listen for
6285      * @param {Function} handler The method the event invokes
6286      * @param {Object}   scope (optional) The scope in which to execute the handler
6287      * function. The handler function's "this" context.
6288      * @param {Object}   options (optional) An object containing handler configuration
6289      * properties. This may contain any of the following properties:<ul>
6290      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6291      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6292      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6293      * <li>preventDefault {Boolean} True to prevent the default action</li>
6294      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6295      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6296      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6297      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6298      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6299      * by the specified number of milliseconds. If the event fires again within that time, the original
6300      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6301      * </ul><br>
6302      * <p>
6303      * <b>Combining Options</b><br>
6304      * Using the options argument, it is possible to combine different types of listeners:<br>
6305      * <br>
6306      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6307      * Code:<pre><code>
6308 el.on('click', this.onClick, this, {
6309     single: true,
6310     delay: 100,
6311     stopEvent : true,
6312     forumId: 4
6313 });</code></pre>
6314      * <p>
6315      * <b>Attaching multiple handlers in 1 call</b><br>
6316       * The method also allows for a single argument to be passed which is a config object containing properties
6317      * which specify multiple handlers.
6318      * <p>
6319      * Code:<pre><code>
6320 el.on({
6321     'click' : {
6322         fn: this.onClick
6323         scope: this,
6324         delay: 100
6325     },
6326     'mouseover' : {
6327         fn: this.onMouseOver
6328         scope: this
6329     },
6330     'mouseout' : {
6331         fn: this.onMouseOut
6332         scope: this
6333     }
6334 });</code></pre>
6335      * <p>
6336      * Or a shorthand syntax:<br>
6337      * Code:<pre><code>
6338 el.on({
6339     'click' : this.onClick,
6340     'mouseover' : this.onMouseOver,
6341     'mouseout' : this.onMouseOut
6342     scope: this
6343 });</code></pre>
6344      */
6345         addListener : function(element, eventName, fn, scope, options){
6346             if(typeof eventName == "object"){
6347                 var o = eventName;
6348                 for(var e in o){
6349                     if(propRe.test(e)){
6350                         continue;
6351                     }
6352                     if(typeof o[e] == "function"){
6353                         // shared options
6354                         listen(element, e, o, o[e], o.scope);
6355                     }else{
6356                         // individual options
6357                         listen(element, e, o[e]);
6358                     }
6359                 }
6360                 return;
6361             }
6362             return listen(element, eventName, options, fn, scope);
6363         },
6364         
6365         /**
6366          * Removes an event handler
6367          *
6368          * @param {String/HTMLElement}   element        The id or html element to remove the 
6369          *                             event from
6370          * @param {String}   eventName     The type of event
6371          * @param {Function} fn
6372          * @return {Boolean} True if a listener was actually removed
6373          */
6374         removeListener : function(element, eventName, fn){
6375             return stopListening(element, eventName, fn);
6376         },
6377         
6378         /**
6379          * Fires when the document is ready (before onload and before images are loaded). Can be 
6380          * accessed shorthanded Roo.onReady().
6381          * @param {Function} fn        The method the event invokes
6382          * @param {Object}   scope    An  object that becomes the scope of the handler
6383          * @param {boolean}  options
6384          */
6385         onDocumentReady : function(fn, scope, options){
6386             if(docReadyState){ // if it already fired
6387                 docReadyEvent.addListener(fn, scope, options);
6388                 docReadyEvent.fire();
6389                 docReadyEvent.clearListeners();
6390                 return;
6391             }
6392             if(!docReadyEvent){
6393                 initDocReady();
6394             }
6395             docReadyEvent.addListener(fn, scope, options);
6396         },
6397         
6398         /**
6399          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6400          * @param {Function} fn        The method the event invokes
6401          * @param {Object}   scope    An object that becomes the scope of the handler
6402          * @param {boolean}  options
6403          */
6404         onWindowResize : function(fn, scope, options){
6405             if(!resizeEvent){
6406                 resizeEvent = new Roo.util.Event();
6407                 resizeTask = new Roo.util.DelayedTask(function(){
6408                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6409                 });
6410                 E.on(window, "resize", function(){
6411                     if(Roo.isIE){
6412                         resizeTask.delay(50);
6413                     }else{
6414                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6415                     }
6416                 });
6417             }
6418             resizeEvent.addListener(fn, scope, options);
6419         },
6420
6421         /**
6422          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6423          * @param {Function} fn        The method the event invokes
6424          * @param {Object}   scope    An object that becomes the scope of the handler
6425          * @param {boolean}  options
6426          */
6427         onTextResize : function(fn, scope, options){
6428             if(!textEvent){
6429                 textEvent = new Roo.util.Event();
6430                 var textEl = new Roo.Element(document.createElement('div'));
6431                 textEl.dom.className = 'x-text-resize';
6432                 textEl.dom.innerHTML = 'X';
6433                 textEl.appendTo(document.body);
6434                 textSize = textEl.dom.offsetHeight;
6435                 setInterval(function(){
6436                     if(textEl.dom.offsetHeight != textSize){
6437                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6438                     }
6439                 }, this.textResizeInterval);
6440             }
6441             textEvent.addListener(fn, scope, options);
6442         },
6443
6444         /**
6445          * Removes the passed window resize listener.
6446          * @param {Function} fn        The method the event invokes
6447          * @param {Object}   scope    The scope of handler
6448          */
6449         removeResizeListener : function(fn, scope){
6450             if(resizeEvent){
6451                 resizeEvent.removeListener(fn, scope);
6452             }
6453         },
6454
6455         // private
6456         fireResize : function(){
6457             if(resizeEvent){
6458                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6459             }   
6460         },
6461         /**
6462          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6463          */
6464         ieDeferSrc : false,
6465         /**
6466          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6467          */
6468         textResizeInterval : 50
6469     };
6470     
6471     /**
6472      * Fix for doc tools
6473      * @scopeAlias pub=Roo.EventManager
6474      */
6475     
6476      /**
6477      * Appends an event handler to an element (shorthand for addListener)
6478      * @param {String/HTMLElement}   element        The html element or id to assign the
6479      * @param {String}   eventName The type of event to listen for
6480      * @param {Function} handler The method the event invokes
6481      * @param {Object}   scope (optional) The scope in which to execute the handler
6482      * function. The handler function's "this" context.
6483      * @param {Object}   options (optional) An object containing handler configuration
6484      * properties. This may contain any of the following properties:<ul>
6485      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6486      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6487      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6488      * <li>preventDefault {Boolean} True to prevent the default action</li>
6489      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6490      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6491      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6492      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6493      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6494      * by the specified number of milliseconds. If the event fires again within that time, the original
6495      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6496      * </ul><br>
6497      * <p>
6498      * <b>Combining Options</b><br>
6499      * Using the options argument, it is possible to combine different types of listeners:<br>
6500      * <br>
6501      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6502      * Code:<pre><code>
6503 el.on('click', this.onClick, this, {
6504     single: true,
6505     delay: 100,
6506     stopEvent : true,
6507     forumId: 4
6508 });</code></pre>
6509      * <p>
6510      * <b>Attaching multiple handlers in 1 call</b><br>
6511       * The method also allows for a single argument to be passed which is a config object containing properties
6512      * which specify multiple handlers.
6513      * <p>
6514      * Code:<pre><code>
6515 el.on({
6516     'click' : {
6517         fn: this.onClick
6518         scope: this,
6519         delay: 100
6520     },
6521     'mouseover' : {
6522         fn: this.onMouseOver
6523         scope: this
6524     },
6525     'mouseout' : {
6526         fn: this.onMouseOut
6527         scope: this
6528     }
6529 });</code></pre>
6530      * <p>
6531      * Or a shorthand syntax:<br>
6532      * Code:<pre><code>
6533 el.on({
6534     'click' : this.onClick,
6535     'mouseover' : this.onMouseOver,
6536     'mouseout' : this.onMouseOut
6537     scope: this
6538 });</code></pre>
6539      */
6540     pub.on = pub.addListener;
6541     pub.un = pub.removeListener;
6542
6543     pub.stoppedMouseDownEvent = new Roo.util.Event();
6544     return pub;
6545 }();
6546 /**
6547   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6548   * @param {Function} fn        The method the event invokes
6549   * @param {Object}   scope    An  object that becomes the scope of the handler
6550   * @param {boolean}  override If true, the obj passed in becomes
6551   *                             the execution scope of the listener
6552   * @member Roo
6553   * @method onReady
6554  */
6555 Roo.onReady = Roo.EventManager.onDocumentReady;
6556
6557 Roo.onReady(function(){
6558     var bd = Roo.get(document.body);
6559     if(!bd){ return; }
6560
6561     var cls = [
6562             Roo.isIE ? "roo-ie"
6563             : Roo.isGecko ? "roo-gecko"
6564             : Roo.isOpera ? "roo-opera"
6565             : Roo.isSafari ? "roo-safari" : ""];
6566
6567     if(Roo.isMac){
6568         cls.push("roo-mac");
6569     }
6570     if(Roo.isLinux){
6571         cls.push("roo-linux");
6572     }
6573     if(Roo.isBorderBox){
6574         cls.push('roo-border-box');
6575     }
6576     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6577         var p = bd.dom.parentNode;
6578         if(p){
6579             p.className += ' roo-strict';
6580         }
6581     }
6582     bd.addClass(cls.join(' '));
6583 });
6584
6585 /**
6586  * @class Roo.EventObject
6587  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6588  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6589  * Example:
6590  * <pre><code>
6591  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6592     e.preventDefault();
6593     var target = e.getTarget();
6594     ...
6595  }
6596  var myDiv = Roo.get("myDiv");
6597  myDiv.on("click", handleClick);
6598  //or
6599  Roo.EventManager.on("myDiv", 'click', handleClick);
6600  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6601  </code></pre>
6602  * @singleton
6603  */
6604 Roo.EventObject = function(){
6605     
6606     var E = Roo.lib.Event;
6607     
6608     // safari keypress events for special keys return bad keycodes
6609     var safariKeys = {
6610         63234 : 37, // left
6611         63235 : 39, // right
6612         63232 : 38, // up
6613         63233 : 40, // down
6614         63276 : 33, // page up
6615         63277 : 34, // page down
6616         63272 : 46, // delete
6617         63273 : 36, // home
6618         63275 : 35  // end
6619     };
6620
6621     // normalize button clicks
6622     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6623                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6624
6625     Roo.EventObjectImpl = function(e){
6626         if(e){
6627             this.setEvent(e.browserEvent || e);
6628         }
6629     };
6630     Roo.EventObjectImpl.prototype = {
6631         /**
6632          * Used to fix doc tools.
6633          * @scope Roo.EventObject.prototype
6634          */
6635             
6636
6637         
6638         
6639         /** The normal browser event */
6640         browserEvent : null,
6641         /** The button pressed in a mouse event */
6642         button : -1,
6643         /** True if the shift key was down during the event */
6644         shiftKey : false,
6645         /** True if the control key was down during the event */
6646         ctrlKey : false,
6647         /** True if the alt key was down during the event */
6648         altKey : false,
6649
6650         /** Key constant 
6651         * @type Number */
6652         BACKSPACE : 8,
6653         /** Key constant 
6654         * @type Number */
6655         TAB : 9,
6656         /** Key constant 
6657         * @type Number */
6658         RETURN : 13,
6659         /** Key constant 
6660         * @type Number */
6661         ENTER : 13,
6662         /** Key constant 
6663         * @type Number */
6664         SHIFT : 16,
6665         /** Key constant 
6666         * @type Number */
6667         CONTROL : 17,
6668         /** Key constant 
6669         * @type Number */
6670         ESC : 27,
6671         /** Key constant 
6672         * @type Number */
6673         SPACE : 32,
6674         /** Key constant 
6675         * @type Number */
6676         PAGEUP : 33,
6677         /** Key constant 
6678         * @type Number */
6679         PAGEDOWN : 34,
6680         /** Key constant 
6681         * @type Number */
6682         END : 35,
6683         /** Key constant 
6684         * @type Number */
6685         HOME : 36,
6686         /** Key constant 
6687         * @type Number */
6688         LEFT : 37,
6689         /** Key constant 
6690         * @type Number */
6691         UP : 38,
6692         /** Key constant 
6693         * @type Number */
6694         RIGHT : 39,
6695         /** Key constant 
6696         * @type Number */
6697         DOWN : 40,
6698         /** Key constant 
6699         * @type Number */
6700         DELETE : 46,
6701         /** Key constant 
6702         * @type Number */
6703         F5 : 116,
6704
6705            /** @private */
6706         setEvent : function(e){
6707             if(e == this || (e && e.browserEvent)){ // already wrapped
6708                 return e;
6709             }
6710             this.browserEvent = e;
6711             if(e){
6712                 // normalize buttons
6713                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6714                 if(e.type == 'click' && this.button == -1){
6715                     this.button = 0;
6716                 }
6717                 this.type = e.type;
6718                 this.shiftKey = e.shiftKey;
6719                 // mac metaKey behaves like ctrlKey
6720                 this.ctrlKey = e.ctrlKey || e.metaKey;
6721                 this.altKey = e.altKey;
6722                 // in getKey these will be normalized for the mac
6723                 this.keyCode = e.keyCode;
6724                 // keyup warnings on firefox.
6725                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6726                 // cache the target for the delayed and or buffered events
6727                 this.target = E.getTarget(e);
6728                 // same for XY
6729                 this.xy = E.getXY(e);
6730             }else{
6731                 this.button = -1;
6732                 this.shiftKey = false;
6733                 this.ctrlKey = false;
6734                 this.altKey = false;
6735                 this.keyCode = 0;
6736                 this.charCode =0;
6737                 this.target = null;
6738                 this.xy = [0, 0];
6739             }
6740             return this;
6741         },
6742
6743         /**
6744          * Stop the event (preventDefault and stopPropagation)
6745          */
6746         stopEvent : function(){
6747             if(this.browserEvent){
6748                 if(this.browserEvent.type == 'mousedown'){
6749                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6750                 }
6751                 E.stopEvent(this.browserEvent);
6752             }
6753         },
6754
6755         /**
6756          * Prevents the browsers default handling of the event.
6757          */
6758         preventDefault : function(){
6759             if(this.browserEvent){
6760                 E.preventDefault(this.browserEvent);
6761             }
6762         },
6763
6764         /** @private */
6765         isNavKeyPress : function(){
6766             var k = this.keyCode;
6767             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6768             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6769         },
6770
6771         isSpecialKey : function(){
6772             var k = this.keyCode;
6773             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6774             (k == 16) || (k == 17) ||
6775             (k >= 18 && k <= 20) ||
6776             (k >= 33 && k <= 35) ||
6777             (k >= 36 && k <= 39) ||
6778             (k >= 44 && k <= 45);
6779         },
6780         /**
6781          * Cancels bubbling of the event.
6782          */
6783         stopPropagation : function(){
6784             if(this.browserEvent){
6785                 if(this.type == 'mousedown'){
6786                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6787                 }
6788                 E.stopPropagation(this.browserEvent);
6789             }
6790         },
6791
6792         /**
6793          * Gets the key code for the event.
6794          * @return {Number}
6795          */
6796         getCharCode : function(){
6797             return this.charCode || this.keyCode;
6798         },
6799
6800         /**
6801          * Returns a normalized keyCode for the event.
6802          * @return {Number} The key code
6803          */
6804         getKey : function(){
6805             var k = this.keyCode || this.charCode;
6806             return Roo.isSafari ? (safariKeys[k] || k) : k;
6807         },
6808
6809         /**
6810          * Gets the x coordinate of the event.
6811          * @return {Number}
6812          */
6813         getPageX : function(){
6814             return this.xy[0];
6815         },
6816
6817         /**
6818          * Gets the y coordinate of the event.
6819          * @return {Number}
6820          */
6821         getPageY : function(){
6822             return this.xy[1];
6823         },
6824
6825         /**
6826          * Gets the time of the event.
6827          * @return {Number}
6828          */
6829         getTime : function(){
6830             if(this.browserEvent){
6831                 return E.getTime(this.browserEvent);
6832             }
6833             return null;
6834         },
6835
6836         /**
6837          * Gets the page coordinates of the event.
6838          * @return {Array} The xy values like [x, y]
6839          */
6840         getXY : function(){
6841             return this.xy;
6842         },
6843
6844         /**
6845          * Gets the target for the event.
6846          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6847          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6848                 search as a number or element (defaults to 10 || document.body)
6849          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6850          * @return {HTMLelement}
6851          */
6852         getTarget : function(selector, maxDepth, returnEl){
6853             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6854         },
6855         /**
6856          * Gets the related target.
6857          * @return {HTMLElement}
6858          */
6859         getRelatedTarget : function(){
6860             if(this.browserEvent){
6861                 return E.getRelatedTarget(this.browserEvent);
6862             }
6863             return null;
6864         },
6865
6866         /**
6867          * Normalizes mouse wheel delta across browsers
6868          * @return {Number} The delta
6869          */
6870         getWheelDelta : function(){
6871             var e = this.browserEvent;
6872             var delta = 0;
6873             if(e.wheelDelta){ /* IE/Opera. */
6874                 delta = e.wheelDelta/120;
6875             }else if(e.detail){ /* Mozilla case. */
6876                 delta = -e.detail/3;
6877             }
6878             return delta;
6879         },
6880
6881         /**
6882          * Returns true if the control, meta, shift or alt key was pressed during this event.
6883          * @return {Boolean}
6884          */
6885         hasModifier : function(){
6886             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6887         },
6888
6889         /**
6890          * Returns true if the target of this event equals el or is a child of el
6891          * @param {String/HTMLElement/Element} el
6892          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6893          * @return {Boolean}
6894          */
6895         within : function(el, related){
6896             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6897             return t && Roo.fly(el).contains(t);
6898         },
6899
6900         getPoint : function(){
6901             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6902         }
6903     };
6904
6905     return new Roo.EventObjectImpl();
6906 }();
6907             
6908     /*
6909  * Based on:
6910  * Ext JS Library 1.1.1
6911  * Copyright(c) 2006-2007, Ext JS, LLC.
6912  *
6913  * Originally Released Under LGPL - original licence link has changed is not relivant.
6914  *
6915  * Fork - LGPL
6916  * <script type="text/javascript">
6917  */
6918
6919  
6920 // was in Composite Element!??!?!
6921  
6922 (function(){
6923     var D = Roo.lib.Dom;
6924     var E = Roo.lib.Event;
6925     var A = Roo.lib.Anim;
6926
6927     // local style camelizing for speed
6928     var propCache = {};
6929     var camelRe = /(-[a-z])/gi;
6930     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6931     var view = document.defaultView;
6932
6933 /**
6934  * @class Roo.Element
6935  * Represents an Element in the DOM.<br><br>
6936  * Usage:<br>
6937 <pre><code>
6938 var el = Roo.get("my-div");
6939
6940 // or with getEl
6941 var el = getEl("my-div");
6942
6943 // or with a DOM element
6944 var el = Roo.get(myDivElement);
6945 </code></pre>
6946  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6947  * each call instead of constructing a new one.<br><br>
6948  * <b>Animations</b><br />
6949  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6950  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6951 <pre>
6952 Option    Default   Description
6953 --------- --------  ---------------------------------------------
6954 duration  .35       The duration of the animation in seconds
6955 easing    easeOut   The YUI easing method
6956 callback  none      A function to execute when the anim completes
6957 scope     this      The scope (this) of the callback function
6958 </pre>
6959 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6960 * manipulate the animation. Here's an example:
6961 <pre><code>
6962 var el = Roo.get("my-div");
6963
6964 // no animation
6965 el.setWidth(100);
6966
6967 // default animation
6968 el.setWidth(100, true);
6969
6970 // animation with some options set
6971 el.setWidth(100, {
6972     duration: 1,
6973     callback: this.foo,
6974     scope: this
6975 });
6976
6977 // using the "anim" property to get the Anim object
6978 var opt = {
6979     duration: 1,
6980     callback: this.foo,
6981     scope: this
6982 };
6983 el.setWidth(100, opt);
6984 ...
6985 if(opt.anim.isAnimated()){
6986     opt.anim.stop();
6987 }
6988 </code></pre>
6989 * <b> Composite (Collections of) Elements</b><br />
6990  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6991  * @constructor Create a new Element directly.
6992  * @param {String/HTMLElement} element
6993  * @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).
6994  */
6995     Roo.Element = function(element, forceNew){
6996         var dom = typeof element == "string" ?
6997                 document.getElementById(element) : element;
6998         if(!dom){ // invalid id/element
6999             return null;
7000         }
7001         var id = dom.id;
7002         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7003             return Roo.Element.cache[id];
7004         }
7005
7006         /**
7007          * The DOM element
7008          * @type HTMLElement
7009          */
7010         this.dom = dom;
7011
7012         /**
7013          * The DOM element ID
7014          * @type String
7015          */
7016         this.id = id || Roo.id(dom);
7017     };
7018
7019     var El = Roo.Element;
7020
7021     El.prototype = {
7022         /**
7023          * The element's default display mode  (defaults to "")
7024          * @type String
7025          */
7026         originalDisplay : "",
7027
7028         visibilityMode : 1,
7029         /**
7030          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7031          * @type String
7032          */
7033         defaultUnit : "px",
7034         /**
7035          * Sets the element's visibility mode. When setVisible() is called it
7036          * will use this to determine whether to set the visibility or the display property.
7037          * @param visMode Element.VISIBILITY or Element.DISPLAY
7038          * @return {Roo.Element} this
7039          */
7040         setVisibilityMode : function(visMode){
7041             this.visibilityMode = visMode;
7042             return this;
7043         },
7044         /**
7045          * Convenience method for setVisibilityMode(Element.DISPLAY)
7046          * @param {String} display (optional) What to set display to when visible
7047          * @return {Roo.Element} this
7048          */
7049         enableDisplayMode : function(display){
7050             this.setVisibilityMode(El.DISPLAY);
7051             if(typeof display != "undefined") this.originalDisplay = display;
7052             return this;
7053         },
7054
7055         /**
7056          * 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)
7057          * @param {String} selector The simple selector to test
7058          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7059                 search as a number or element (defaults to 10 || document.body)
7060          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7061          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7062          */
7063         findParent : function(simpleSelector, maxDepth, returnEl){
7064             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7065             maxDepth = maxDepth || 50;
7066             if(typeof maxDepth != "number"){
7067                 stopEl = Roo.getDom(maxDepth);
7068                 maxDepth = 10;
7069             }
7070             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7071                 if(dq.is(p, simpleSelector)){
7072                     return returnEl ? Roo.get(p) : p;
7073                 }
7074                 depth++;
7075                 p = p.parentNode;
7076             }
7077             return null;
7078         },
7079
7080
7081         /**
7082          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7083          * @param {String} selector The simple selector to test
7084          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7085                 search as a number or element (defaults to 10 || document.body)
7086          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7087          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7088          */
7089         findParentNode : function(simpleSelector, maxDepth, returnEl){
7090             var p = Roo.fly(this.dom.parentNode, '_internal');
7091             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7092         },
7093
7094         /**
7095          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7096          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7097          * @param {String} selector The simple selector to test
7098          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7099                 search as a number or element (defaults to 10 || document.body)
7100          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7101          */
7102         up : function(simpleSelector, maxDepth){
7103             return this.findParentNode(simpleSelector, maxDepth, true);
7104         },
7105
7106
7107
7108         /**
7109          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7110          * @param {String} selector The simple selector to test
7111          * @return {Boolean} True if this element matches the selector, else false
7112          */
7113         is : function(simpleSelector){
7114             return Roo.DomQuery.is(this.dom, simpleSelector);
7115         },
7116
7117         /**
7118          * Perform animation on this element.
7119          * @param {Object} args The YUI animation control args
7120          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7121          * @param {Function} onComplete (optional) Function to call when animation completes
7122          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7123          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7124          * @return {Roo.Element} this
7125          */
7126         animate : function(args, duration, onComplete, easing, animType){
7127             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7128             return this;
7129         },
7130
7131         /*
7132          * @private Internal animation call
7133          */
7134         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7135             animType = animType || 'run';
7136             opt = opt || {};
7137             var anim = Roo.lib.Anim[animType](
7138                 this.dom, args,
7139                 (opt.duration || defaultDur) || .35,
7140                 (opt.easing || defaultEase) || 'easeOut',
7141                 function(){
7142                     Roo.callback(cb, this);
7143                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7144                 },
7145                 this
7146             );
7147             opt.anim = anim;
7148             return anim;
7149         },
7150
7151         // private legacy anim prep
7152         preanim : function(a, i){
7153             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7154         },
7155
7156         /**
7157          * Removes worthless text nodes
7158          * @param {Boolean} forceReclean (optional) By default the element
7159          * keeps track if it has been cleaned already so
7160          * you can call this over and over. However, if you update the element and
7161          * need to force a reclean, you can pass true.
7162          */
7163         clean : function(forceReclean){
7164             if(this.isCleaned && forceReclean !== true){
7165                 return this;
7166             }
7167             var ns = /\S/;
7168             var d = this.dom, n = d.firstChild, ni = -1;
7169             while(n){
7170                 var nx = n.nextSibling;
7171                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7172                     d.removeChild(n);
7173                 }else{
7174                     n.nodeIndex = ++ni;
7175                 }
7176                 n = nx;
7177             }
7178             this.isCleaned = true;
7179             return this;
7180         },
7181
7182         // private
7183         calcOffsetsTo : function(el){
7184             el = Roo.get(el);
7185             var d = el.dom;
7186             var restorePos = false;
7187             if(el.getStyle('position') == 'static'){
7188                 el.position('relative');
7189                 restorePos = true;
7190             }
7191             var x = 0, y =0;
7192             var op = this.dom;
7193             while(op && op != d && op.tagName != 'HTML'){
7194                 x+= op.offsetLeft;
7195                 y+= op.offsetTop;
7196                 op = op.offsetParent;
7197             }
7198             if(restorePos){
7199                 el.position('static');
7200             }
7201             return [x, y];
7202         },
7203
7204         /**
7205          * Scrolls this element into view within the passed container.
7206          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7207          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7208          * @return {Roo.Element} this
7209          */
7210         scrollIntoView : function(container, hscroll){
7211             var c = Roo.getDom(container) || document.body;
7212             var el = this.dom;
7213
7214             var o = this.calcOffsetsTo(c),
7215                 l = o[0],
7216                 t = o[1],
7217                 b = t+el.offsetHeight,
7218                 r = l+el.offsetWidth;
7219
7220             var ch = c.clientHeight;
7221             var ct = parseInt(c.scrollTop, 10);
7222             var cl = parseInt(c.scrollLeft, 10);
7223             var cb = ct + ch;
7224             var cr = cl + c.clientWidth;
7225
7226             if(t < ct){
7227                 c.scrollTop = t;
7228             }else if(b > cb){
7229                 c.scrollTop = b-ch;
7230             }
7231
7232             if(hscroll !== false){
7233                 if(l < cl){
7234                     c.scrollLeft = l;
7235                 }else if(r > cr){
7236                     c.scrollLeft = r-c.clientWidth;
7237                 }
7238             }
7239             return this;
7240         },
7241
7242         // private
7243         scrollChildIntoView : function(child, hscroll){
7244             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7245         },
7246
7247         /**
7248          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7249          * the new height may not be available immediately.
7250          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7251          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7252          * @param {Function} onComplete (optional) Function to call when animation completes
7253          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7254          * @return {Roo.Element} this
7255          */
7256         autoHeight : function(animate, duration, onComplete, easing){
7257             var oldHeight = this.getHeight();
7258             this.clip();
7259             this.setHeight(1); // force clipping
7260             setTimeout(function(){
7261                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7262                 if(!animate){
7263                     this.setHeight(height);
7264                     this.unclip();
7265                     if(typeof onComplete == "function"){
7266                         onComplete();
7267                     }
7268                 }else{
7269                     this.setHeight(oldHeight); // restore original height
7270                     this.setHeight(height, animate, duration, function(){
7271                         this.unclip();
7272                         if(typeof onComplete == "function") onComplete();
7273                     }.createDelegate(this), easing);
7274                 }
7275             }.createDelegate(this), 0);
7276             return this;
7277         },
7278
7279         /**
7280          * Returns true if this element is an ancestor of the passed element
7281          * @param {HTMLElement/String} el The element to check
7282          * @return {Boolean} True if this element is an ancestor of el, else false
7283          */
7284         contains : function(el){
7285             if(!el){return false;}
7286             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7287         },
7288
7289         /**
7290          * Checks whether the element is currently visible using both visibility and display properties.
7291          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7292          * @return {Boolean} True if the element is currently visible, else false
7293          */
7294         isVisible : function(deep) {
7295             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7296             if(deep !== true || !vis){
7297                 return vis;
7298             }
7299             var p = this.dom.parentNode;
7300             while(p && p.tagName.toLowerCase() != "body"){
7301                 if(!Roo.fly(p, '_isVisible').isVisible()){
7302                     return false;
7303                 }
7304                 p = p.parentNode;
7305             }
7306             return true;
7307         },
7308
7309         /**
7310          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7311          * @param {String} selector The CSS selector
7312          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7313          * @return {CompositeElement/CompositeElementLite} The composite element
7314          */
7315         select : function(selector, unique){
7316             return El.select(selector, unique, this.dom);
7317         },
7318
7319         /**
7320          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7321          * @param {String} selector The CSS selector
7322          * @return {Array} An array of the matched nodes
7323          */
7324         query : function(selector, unique){
7325             return Roo.DomQuery.select(selector, this.dom);
7326         },
7327
7328         /**
7329          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7330          * @param {String} selector The CSS selector
7331          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7332          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7333          */
7334         child : function(selector, returnDom){
7335             var n = Roo.DomQuery.selectNode(selector, this.dom);
7336             return returnDom ? n : Roo.get(n);
7337         },
7338
7339         /**
7340          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7341          * @param {String} selector The CSS selector
7342          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7343          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7344          */
7345         down : function(selector, returnDom){
7346             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7347             return returnDom ? n : Roo.get(n);
7348         },
7349
7350         /**
7351          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7352          * @param {String} group The group the DD object is member of
7353          * @param {Object} config The DD config object
7354          * @param {Object} overrides An object containing methods to override/implement on the DD object
7355          * @return {Roo.dd.DD} The DD object
7356          */
7357         initDD : function(group, config, overrides){
7358             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7359             return Roo.apply(dd, overrides);
7360         },
7361
7362         /**
7363          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7364          * @param {String} group The group the DDProxy object is member of
7365          * @param {Object} config The DDProxy config object
7366          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7367          * @return {Roo.dd.DDProxy} The DDProxy object
7368          */
7369         initDDProxy : function(group, config, overrides){
7370             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7371             return Roo.apply(dd, overrides);
7372         },
7373
7374         /**
7375          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7376          * @param {String} group The group the DDTarget object is member of
7377          * @param {Object} config The DDTarget config object
7378          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7379          * @return {Roo.dd.DDTarget} The DDTarget object
7380          */
7381         initDDTarget : function(group, config, overrides){
7382             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7383             return Roo.apply(dd, overrides);
7384         },
7385
7386         /**
7387          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7388          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7389          * @param {Boolean} visible Whether the element is visible
7390          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7391          * @return {Roo.Element} this
7392          */
7393          setVisible : function(visible, animate){
7394             if(!animate || !A){
7395                 if(this.visibilityMode == El.DISPLAY){
7396                     this.setDisplayed(visible);
7397                 }else{
7398                     this.fixDisplay();
7399                     this.dom.style.visibility = visible ? "visible" : "hidden";
7400                 }
7401             }else{
7402                 // closure for composites
7403                 var dom = this.dom;
7404                 var visMode = this.visibilityMode;
7405                 if(visible){
7406                     this.setOpacity(.01);
7407                     this.setVisible(true);
7408                 }
7409                 this.anim({opacity: { to: (visible?1:0) }},
7410                       this.preanim(arguments, 1),
7411                       null, .35, 'easeIn', function(){
7412                          if(!visible){
7413                              if(visMode == El.DISPLAY){
7414                                  dom.style.display = "none";
7415                              }else{
7416                                  dom.style.visibility = "hidden";
7417                              }
7418                              Roo.get(dom).setOpacity(1);
7419                          }
7420                      });
7421             }
7422             return this;
7423         },
7424
7425         /**
7426          * Returns true if display is not "none"
7427          * @return {Boolean}
7428          */
7429         isDisplayed : function() {
7430             return this.getStyle("display") != "none";
7431         },
7432
7433         /**
7434          * Toggles the element's visibility or display, depending on visibility mode.
7435          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7436          * @return {Roo.Element} this
7437          */
7438         toggle : function(animate){
7439             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7440             return this;
7441         },
7442
7443         /**
7444          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7445          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7446          * @return {Roo.Element} this
7447          */
7448         setDisplayed : function(value) {
7449             if(typeof value == "boolean"){
7450                value = value ? this.originalDisplay : "none";
7451             }
7452             this.setStyle("display", value);
7453             return this;
7454         },
7455
7456         /**
7457          * Tries to focus the element. Any exceptions are caught and ignored.
7458          * @return {Roo.Element} this
7459          */
7460         focus : function() {
7461             try{
7462                 this.dom.focus();
7463             }catch(e){}
7464             return this;
7465         },
7466
7467         /**
7468          * Tries to blur the element. Any exceptions are caught and ignored.
7469          * @return {Roo.Element} this
7470          */
7471         blur : function() {
7472             try{
7473                 this.dom.blur();
7474             }catch(e){}
7475             return this;
7476         },
7477
7478         /**
7479          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7480          * @param {String/Array} className The CSS class to add, or an array of classes
7481          * @return {Roo.Element} this
7482          */
7483         addClass : function(className){
7484             if(className instanceof Array){
7485                 for(var i = 0, len = className.length; i < len; i++) {
7486                     this.addClass(className[i]);
7487                 }
7488             }else{
7489                 if(className && !this.hasClass(className)){
7490                     this.dom.className = this.dom.className + " " + className;
7491                 }
7492             }
7493             return this;
7494         },
7495
7496         /**
7497          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7498          * @param {String/Array} className The CSS class to add, or an array of classes
7499          * @return {Roo.Element} this
7500          */
7501         radioClass : function(className){
7502             var siblings = this.dom.parentNode.childNodes;
7503             for(var i = 0; i < siblings.length; i++) {
7504                 var s = siblings[i];
7505                 if(s.nodeType == 1){
7506                     Roo.get(s).removeClass(className);
7507                 }
7508             }
7509             this.addClass(className);
7510             return this;
7511         },
7512
7513         /**
7514          * Removes one or more CSS classes from the element.
7515          * @param {String/Array} className The CSS class to remove, or an array of classes
7516          * @return {Roo.Element} this
7517          */
7518         removeClass : function(className){
7519             if(!className || !this.dom.className){
7520                 return this;
7521             }
7522             if(className instanceof Array){
7523                 for(var i = 0, len = className.length; i < len; i++) {
7524                     this.removeClass(className[i]);
7525                 }
7526             }else{
7527                 if(this.hasClass(className)){
7528                     var re = this.classReCache[className];
7529                     if (!re) {
7530                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7531                        this.classReCache[className] = re;
7532                     }
7533                     this.dom.className =
7534                         this.dom.className.replace(re, " ");
7535                 }
7536             }
7537             return this;
7538         },
7539
7540         // private
7541         classReCache: {},
7542
7543         /**
7544          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7545          * @param {String} className The CSS class to toggle
7546          * @return {Roo.Element} this
7547          */
7548         toggleClass : function(className){
7549             if(this.hasClass(className)){
7550                 this.removeClass(className);
7551             }else{
7552                 this.addClass(className);
7553             }
7554             return this;
7555         },
7556
7557         /**
7558          * Checks if the specified CSS class exists on this element's DOM node.
7559          * @param {String} className The CSS class to check for
7560          * @return {Boolean} True if the class exists, else false
7561          */
7562         hasClass : function(className){
7563             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7564         },
7565
7566         /**
7567          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7568          * @param {String} oldClassName The CSS class to replace
7569          * @param {String} newClassName The replacement CSS class
7570          * @return {Roo.Element} this
7571          */
7572         replaceClass : function(oldClassName, newClassName){
7573             this.removeClass(oldClassName);
7574             this.addClass(newClassName);
7575             return this;
7576         },
7577
7578         /**
7579          * Returns an object with properties matching the styles requested.
7580          * For example, el.getStyles('color', 'font-size', 'width') might return
7581          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7582          * @param {String} style1 A style name
7583          * @param {String} style2 A style name
7584          * @param {String} etc.
7585          * @return {Object} The style object
7586          */
7587         getStyles : function(){
7588             var a = arguments, len = a.length, r = {};
7589             for(var i = 0; i < len; i++){
7590                 r[a[i]] = this.getStyle(a[i]);
7591             }
7592             return r;
7593         },
7594
7595         /**
7596          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7597          * @param {String} property The style property whose value is returned.
7598          * @return {String} The current value of the style property for this element.
7599          */
7600         getStyle : function(){
7601             return view && view.getComputedStyle ?
7602                 function(prop){
7603                     var el = this.dom, v, cs, camel;
7604                     if(prop == 'float'){
7605                         prop = "cssFloat";
7606                     }
7607                     if(el.style && (v = el.style[prop])){
7608                         return v;
7609                     }
7610                     if(cs = view.getComputedStyle(el, "")){
7611                         if(!(camel = propCache[prop])){
7612                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7613                         }
7614                         return cs[camel];
7615                     }
7616                     return null;
7617                 } :
7618                 function(prop){
7619                     var el = this.dom, v, cs, camel;
7620                     if(prop == 'opacity'){
7621                         if(typeof el.style.filter == 'string'){
7622                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7623                             if(m){
7624                                 var fv = parseFloat(m[1]);
7625                                 if(!isNaN(fv)){
7626                                     return fv ? fv / 100 : 0;
7627                                 }
7628                             }
7629                         }
7630                         return 1;
7631                     }else if(prop == 'float'){
7632                         prop = "styleFloat";
7633                     }
7634                     if(!(camel = propCache[prop])){
7635                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7636                     }
7637                     if(v = el.style[camel]){
7638                         return v;
7639                     }
7640                     if(cs = el.currentStyle){
7641                         return cs[camel];
7642                     }
7643                     return null;
7644                 };
7645         }(),
7646
7647         /**
7648          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7649          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7650          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7651          * @return {Roo.Element} this
7652          */
7653         setStyle : function(prop, value){
7654             if(typeof prop == "string"){
7655                 
7656                 if (prop == 'float') {
7657                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7658                     return this;
7659                 }
7660                 
7661                 var camel;
7662                 if(!(camel = propCache[prop])){
7663                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7664                 }
7665                 
7666                 if(camel == 'opacity') {
7667                     this.setOpacity(value);
7668                 }else{
7669                     this.dom.style[camel] = value;
7670                 }
7671             }else{
7672                 for(var style in prop){
7673                     if(typeof prop[style] != "function"){
7674                        this.setStyle(style, prop[style]);
7675                     }
7676                 }
7677             }
7678             return this;
7679         },
7680
7681         /**
7682          * More flexible version of {@link #setStyle} for setting style properties.
7683          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7684          * a function which returns such a specification.
7685          * @return {Roo.Element} this
7686          */
7687         applyStyles : function(style){
7688             Roo.DomHelper.applyStyles(this.dom, style);
7689             return this;
7690         },
7691
7692         /**
7693           * 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).
7694           * @return {Number} The X position of the element
7695           */
7696         getX : function(){
7697             return D.getX(this.dom);
7698         },
7699
7700         /**
7701           * 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).
7702           * @return {Number} The Y position of the element
7703           */
7704         getY : function(){
7705             return D.getY(this.dom);
7706         },
7707
7708         /**
7709           * 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).
7710           * @return {Array} The XY position of the element
7711           */
7712         getXY : function(){
7713             return D.getXY(this.dom);
7714         },
7715
7716         /**
7717          * 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).
7718          * @param {Number} The X position of the element
7719          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7720          * @return {Roo.Element} this
7721          */
7722         setX : function(x, animate){
7723             if(!animate || !A){
7724                 D.setX(this.dom, x);
7725             }else{
7726                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7727             }
7728             return this;
7729         },
7730
7731         /**
7732          * 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).
7733          * @param {Number} The Y position of the element
7734          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7735          * @return {Roo.Element} this
7736          */
7737         setY : function(y, animate){
7738             if(!animate || !A){
7739                 D.setY(this.dom, y);
7740             }else{
7741                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7742             }
7743             return this;
7744         },
7745
7746         /**
7747          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7748          * @param {String} left The left CSS property value
7749          * @return {Roo.Element} this
7750          */
7751         setLeft : function(left){
7752             this.setStyle("left", this.addUnits(left));
7753             return this;
7754         },
7755
7756         /**
7757          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7758          * @param {String} top The top CSS property value
7759          * @return {Roo.Element} this
7760          */
7761         setTop : function(top){
7762             this.setStyle("top", this.addUnits(top));
7763             return this;
7764         },
7765
7766         /**
7767          * Sets the element's CSS right style.
7768          * @param {String} right The right CSS property value
7769          * @return {Roo.Element} this
7770          */
7771         setRight : function(right){
7772             this.setStyle("right", this.addUnits(right));
7773             return this;
7774         },
7775
7776         /**
7777          * Sets the element's CSS bottom style.
7778          * @param {String} bottom The bottom CSS property value
7779          * @return {Roo.Element} this
7780          */
7781         setBottom : function(bottom){
7782             this.setStyle("bottom", this.addUnits(bottom));
7783             return this;
7784         },
7785
7786         /**
7787          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7788          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7789          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7790          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7791          * @return {Roo.Element} this
7792          */
7793         setXY : function(pos, animate){
7794             if(!animate || !A){
7795                 D.setXY(this.dom, pos);
7796             }else{
7797                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7798             }
7799             return this;
7800         },
7801
7802         /**
7803          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7804          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7805          * @param {Number} x X value for new position (coordinates are page-based)
7806          * @param {Number} y Y value for new position (coordinates are page-based)
7807          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7808          * @return {Roo.Element} this
7809          */
7810         setLocation : function(x, y, animate){
7811             this.setXY([x, y], this.preanim(arguments, 2));
7812             return this;
7813         },
7814
7815         /**
7816          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7817          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7818          * @param {Number} x X value for new position (coordinates are page-based)
7819          * @param {Number} y Y value for new position (coordinates are page-based)
7820          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7821          * @return {Roo.Element} this
7822          */
7823         moveTo : function(x, y, animate){
7824             this.setXY([x, y], this.preanim(arguments, 2));
7825             return this;
7826         },
7827
7828         /**
7829          * Returns the region of the given element.
7830          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7831          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7832          */
7833         getRegion : function(){
7834             return D.getRegion(this.dom);
7835         },
7836
7837         /**
7838          * Returns the offset height of the element
7839          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7840          * @return {Number} The element's height
7841          */
7842         getHeight : function(contentHeight){
7843             var h = this.dom.offsetHeight || 0;
7844             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7845         },
7846
7847         /**
7848          * Returns the offset width of the element
7849          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7850          * @return {Number} The element's width
7851          */
7852         getWidth : function(contentWidth){
7853             var w = this.dom.offsetWidth || 0;
7854             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7855         },
7856
7857         /**
7858          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7859          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7860          * if a height has not been set using CSS.
7861          * @return {Number}
7862          */
7863         getComputedHeight : function(){
7864             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7865             if(!h){
7866                 h = parseInt(this.getStyle('height'), 10) || 0;
7867                 if(!this.isBorderBox()){
7868                     h += this.getFrameWidth('tb');
7869                 }
7870             }
7871             return h;
7872         },
7873
7874         /**
7875          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7876          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7877          * if a width has not been set using CSS.
7878          * @return {Number}
7879          */
7880         getComputedWidth : function(){
7881             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7882             if(!w){
7883                 w = parseInt(this.getStyle('width'), 10) || 0;
7884                 if(!this.isBorderBox()){
7885                     w += this.getFrameWidth('lr');
7886                 }
7887             }
7888             return w;
7889         },
7890
7891         /**
7892          * Returns the size of the element.
7893          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7894          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7895          */
7896         getSize : function(contentSize){
7897             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7898         },
7899
7900         /**
7901          * Returns the width and height of the viewport.
7902          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7903          */
7904         getViewSize : function(){
7905             var d = this.dom, doc = document, aw = 0, ah = 0;
7906             if(d == doc || d == doc.body){
7907                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7908             }else{
7909                 return {
7910                     width : d.clientWidth,
7911                     height: d.clientHeight
7912                 };
7913             }
7914         },
7915
7916         /**
7917          * Returns the value of the "value" attribute
7918          * @param {Boolean} asNumber true to parse the value as a number
7919          * @return {String/Number}
7920          */
7921         getValue : function(asNumber){
7922             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7923         },
7924
7925         // private
7926         adjustWidth : function(width){
7927             if(typeof width == "number"){
7928                 if(this.autoBoxAdjust && !this.isBorderBox()){
7929                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7930                 }
7931                 if(width < 0){
7932                     width = 0;
7933                 }
7934             }
7935             return width;
7936         },
7937
7938         // private
7939         adjustHeight : function(height){
7940             if(typeof height == "number"){
7941                if(this.autoBoxAdjust && !this.isBorderBox()){
7942                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7943                }
7944                if(height < 0){
7945                    height = 0;
7946                }
7947             }
7948             return height;
7949         },
7950
7951         /**
7952          * Set the width of the element
7953          * @param {Number} width The new width
7954          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7955          * @return {Roo.Element} this
7956          */
7957         setWidth : function(width, animate){
7958             width = this.adjustWidth(width);
7959             if(!animate || !A){
7960                 this.dom.style.width = this.addUnits(width);
7961             }else{
7962                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7963             }
7964             return this;
7965         },
7966
7967         /**
7968          * Set the height of the element
7969          * @param {Number} height The new height
7970          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7971          * @return {Roo.Element} this
7972          */
7973          setHeight : function(height, animate){
7974             height = this.adjustHeight(height);
7975             if(!animate || !A){
7976                 this.dom.style.height = this.addUnits(height);
7977             }else{
7978                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7979             }
7980             return this;
7981         },
7982
7983         /**
7984          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7985          * @param {Number} width The new width
7986          * @param {Number} height The new height
7987          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7988          * @return {Roo.Element} this
7989          */
7990          setSize : function(width, height, animate){
7991             if(typeof width == "object"){ // in case of object from getSize()
7992                 height = width.height; width = width.width;
7993             }
7994             width = this.adjustWidth(width); height = this.adjustHeight(height);
7995             if(!animate || !A){
7996                 this.dom.style.width = this.addUnits(width);
7997                 this.dom.style.height = this.addUnits(height);
7998             }else{
7999                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8000             }
8001             return this;
8002         },
8003
8004         /**
8005          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8006          * @param {Number} x X value for new position (coordinates are page-based)
8007          * @param {Number} y Y value for new position (coordinates are page-based)
8008          * @param {Number} width The new width
8009          * @param {Number} height The new height
8010          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8011          * @return {Roo.Element} this
8012          */
8013         setBounds : function(x, y, width, height, animate){
8014             if(!animate || !A){
8015                 this.setSize(width, height);
8016                 this.setLocation(x, y);
8017             }else{
8018                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8019                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8020                               this.preanim(arguments, 4), 'motion');
8021             }
8022             return this;
8023         },
8024
8025         /**
8026          * 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.
8027          * @param {Roo.lib.Region} region The region to fill
8028          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8029          * @return {Roo.Element} this
8030          */
8031         setRegion : function(region, animate){
8032             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8033             return this;
8034         },
8035
8036         /**
8037          * Appends an event handler
8038          *
8039          * @param {String}   eventName     The type of event to append
8040          * @param {Function} fn        The method the event invokes
8041          * @param {Object} scope       (optional) The scope (this object) of the fn
8042          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8043          */
8044         addListener : function(eventName, fn, scope, options){
8045             if (this.dom) {
8046                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8047             }
8048         },
8049
8050         /**
8051          * Removes an event handler from this element
8052          * @param {String} eventName the type of event to remove
8053          * @param {Function} fn the method the event invokes
8054          * @return {Roo.Element} this
8055          */
8056         removeListener : function(eventName, fn){
8057             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8058             return this;
8059         },
8060
8061         /**
8062          * Removes all previous added listeners from this element
8063          * @return {Roo.Element} this
8064          */
8065         removeAllListeners : function(){
8066             E.purgeElement(this.dom);
8067             return this;
8068         },
8069
8070         relayEvent : function(eventName, observable){
8071             this.on(eventName, function(e){
8072                 observable.fireEvent(eventName, e);
8073             });
8074         },
8075
8076         /**
8077          * Set the opacity of the element
8078          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8079          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8080          * @return {Roo.Element} this
8081          */
8082          setOpacity : function(opacity, animate){
8083             if(!animate || !A){
8084                 var s = this.dom.style;
8085                 if(Roo.isIE){
8086                     s.zoom = 1;
8087                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8088                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8089                 }else{
8090                     s.opacity = opacity;
8091                 }
8092             }else{
8093                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8094             }
8095             return this;
8096         },
8097
8098         /**
8099          * Gets the left X coordinate
8100          * @param {Boolean} local True to get the local css position instead of page coordinate
8101          * @return {Number}
8102          */
8103         getLeft : function(local){
8104             if(!local){
8105                 return this.getX();
8106             }else{
8107                 return parseInt(this.getStyle("left"), 10) || 0;
8108             }
8109         },
8110
8111         /**
8112          * Gets the right X coordinate of the element (element X position + element width)
8113          * @param {Boolean} local True to get the local css position instead of page coordinate
8114          * @return {Number}
8115          */
8116         getRight : function(local){
8117             if(!local){
8118                 return this.getX() + this.getWidth();
8119             }else{
8120                 return (this.getLeft(true) + this.getWidth()) || 0;
8121             }
8122         },
8123
8124         /**
8125          * Gets the top Y coordinate
8126          * @param {Boolean} local True to get the local css position instead of page coordinate
8127          * @return {Number}
8128          */
8129         getTop : function(local) {
8130             if(!local){
8131                 return this.getY();
8132             }else{
8133                 return parseInt(this.getStyle("top"), 10) || 0;
8134             }
8135         },
8136
8137         /**
8138          * Gets the bottom Y coordinate of the element (element Y position + element height)
8139          * @param {Boolean} local True to get the local css position instead of page coordinate
8140          * @return {Number}
8141          */
8142         getBottom : function(local){
8143             if(!local){
8144                 return this.getY() + this.getHeight();
8145             }else{
8146                 return (this.getTop(true) + this.getHeight()) || 0;
8147             }
8148         },
8149
8150         /**
8151         * Initializes positioning on this element. If a desired position is not passed, it will make the
8152         * the element positioned relative IF it is not already positioned.
8153         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8154         * @param {Number} zIndex (optional) The zIndex to apply
8155         * @param {Number} x (optional) Set the page X position
8156         * @param {Number} y (optional) Set the page Y position
8157         */
8158         position : function(pos, zIndex, x, y){
8159             if(!pos){
8160                if(this.getStyle('position') == 'static'){
8161                    this.setStyle('position', 'relative');
8162                }
8163             }else{
8164                 this.setStyle("position", pos);
8165             }
8166             if(zIndex){
8167                 this.setStyle("z-index", zIndex);
8168             }
8169             if(x !== undefined && y !== undefined){
8170                 this.setXY([x, y]);
8171             }else if(x !== undefined){
8172                 this.setX(x);
8173             }else if(y !== undefined){
8174                 this.setY(y);
8175             }
8176         },
8177
8178         /**
8179         * Clear positioning back to the default when the document was loaded
8180         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8181         * @return {Roo.Element} this
8182          */
8183         clearPositioning : function(value){
8184             value = value ||'';
8185             this.setStyle({
8186                 "left": value,
8187                 "right": value,
8188                 "top": value,
8189                 "bottom": value,
8190                 "z-index": "",
8191                 "position" : "static"
8192             });
8193             return this;
8194         },
8195
8196         /**
8197         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8198         * snapshot before performing an update and then restoring the element.
8199         * @return {Object}
8200         */
8201         getPositioning : function(){
8202             var l = this.getStyle("left");
8203             var t = this.getStyle("top");
8204             return {
8205                 "position" : this.getStyle("position"),
8206                 "left" : l,
8207                 "right" : l ? "" : this.getStyle("right"),
8208                 "top" : t,
8209                 "bottom" : t ? "" : this.getStyle("bottom"),
8210                 "z-index" : this.getStyle("z-index")
8211             };
8212         },
8213
8214         /**
8215          * Gets the width of the border(s) for the specified side(s)
8216          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8217          * passing lr would get the border (l)eft width + the border (r)ight width.
8218          * @return {Number} The width of the sides passed added together
8219          */
8220         getBorderWidth : function(side){
8221             return this.addStyles(side, El.borders);
8222         },
8223
8224         /**
8225          * Gets the width of the padding(s) for the specified side(s)
8226          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8227          * passing lr would get the padding (l)eft + the padding (r)ight.
8228          * @return {Number} The padding of the sides passed added together
8229          */
8230         getPadding : function(side){
8231             return this.addStyles(side, El.paddings);
8232         },
8233
8234         /**
8235         * Set positioning with an object returned by getPositioning().
8236         * @param {Object} posCfg
8237         * @return {Roo.Element} this
8238          */
8239         setPositioning : function(pc){
8240             this.applyStyles(pc);
8241             if(pc.right == "auto"){
8242                 this.dom.style.right = "";
8243             }
8244             if(pc.bottom == "auto"){
8245                 this.dom.style.bottom = "";
8246             }
8247             return this;
8248         },
8249
8250         // private
8251         fixDisplay : function(){
8252             if(this.getStyle("display") == "none"){
8253                 this.setStyle("visibility", "hidden");
8254                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8255                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8256                     this.setStyle("display", "block");
8257                 }
8258             }
8259         },
8260
8261         /**
8262          * Quick set left and top adding default units
8263          * @param {String} left The left CSS property value
8264          * @param {String} top The top CSS property value
8265          * @return {Roo.Element} this
8266          */
8267          setLeftTop : function(left, top){
8268             this.dom.style.left = this.addUnits(left);
8269             this.dom.style.top = this.addUnits(top);
8270             return this;
8271         },
8272
8273         /**
8274          * Move this element relative to its current position.
8275          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8276          * @param {Number} distance How far to move the element in pixels
8277          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8278          * @return {Roo.Element} this
8279          */
8280          move : function(direction, distance, animate){
8281             var xy = this.getXY();
8282             direction = direction.toLowerCase();
8283             switch(direction){
8284                 case "l":
8285                 case "left":
8286                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8287                     break;
8288                case "r":
8289                case "right":
8290                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8291                     break;
8292                case "t":
8293                case "top":
8294                case "up":
8295                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8296                     break;
8297                case "b":
8298                case "bottom":
8299                case "down":
8300                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8301                     break;
8302             }
8303             return this;
8304         },
8305
8306         /**
8307          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8308          * @return {Roo.Element} this
8309          */
8310         clip : function(){
8311             if(!this.isClipped){
8312                this.isClipped = true;
8313                this.originalClip = {
8314                    "o": this.getStyle("overflow"),
8315                    "x": this.getStyle("overflow-x"),
8316                    "y": this.getStyle("overflow-y")
8317                };
8318                this.setStyle("overflow", "hidden");
8319                this.setStyle("overflow-x", "hidden");
8320                this.setStyle("overflow-y", "hidden");
8321             }
8322             return this;
8323         },
8324
8325         /**
8326          *  Return clipping (overflow) to original clipping before clip() was called
8327          * @return {Roo.Element} this
8328          */
8329         unclip : function(){
8330             if(this.isClipped){
8331                 this.isClipped = false;
8332                 var o = this.originalClip;
8333                 if(o.o){this.setStyle("overflow", o.o);}
8334                 if(o.x){this.setStyle("overflow-x", o.x);}
8335                 if(o.y){this.setStyle("overflow-y", o.y);}
8336             }
8337             return this;
8338         },
8339
8340
8341         /**
8342          * Gets the x,y coordinates specified by the anchor position on the element.
8343          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8344          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8345          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8346          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8347          * @return {Array} [x, y] An array containing the element's x and y coordinates
8348          */
8349         getAnchorXY : function(anchor, local, s){
8350             //Passing a different size is useful for pre-calculating anchors,
8351             //especially for anchored animations that change the el size.
8352
8353             var w, h, vp = false;
8354             if(!s){
8355                 var d = this.dom;
8356                 if(d == document.body || d == document){
8357                     vp = true;
8358                     w = D.getViewWidth(); h = D.getViewHeight();
8359                 }else{
8360                     w = this.getWidth(); h = this.getHeight();
8361                 }
8362             }else{
8363                 w = s.width;  h = s.height;
8364             }
8365             var x = 0, y = 0, r = Math.round;
8366             switch((anchor || "tl").toLowerCase()){
8367                 case "c":
8368                     x = r(w*.5);
8369                     y = r(h*.5);
8370                 break;
8371                 case "t":
8372                     x = r(w*.5);
8373                     y = 0;
8374                 break;
8375                 case "l":
8376                     x = 0;
8377                     y = r(h*.5);
8378                 break;
8379                 case "r":
8380                     x = w;
8381                     y = r(h*.5);
8382                 break;
8383                 case "b":
8384                     x = r(w*.5);
8385                     y = h;
8386                 break;
8387                 case "tl":
8388                     x = 0;
8389                     y = 0;
8390                 break;
8391                 case "bl":
8392                     x = 0;
8393                     y = h;
8394                 break;
8395                 case "br":
8396                     x = w;
8397                     y = h;
8398                 break;
8399                 case "tr":
8400                     x = w;
8401                     y = 0;
8402                 break;
8403             }
8404             if(local === true){
8405                 return [x, y];
8406             }
8407             if(vp){
8408                 var sc = this.getScroll();
8409                 return [x + sc.left, y + sc.top];
8410             }
8411             //Add the element's offset xy
8412             var o = this.getXY();
8413             return [x+o[0], y+o[1]];
8414         },
8415
8416         /**
8417          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8418          * supported position values.
8419          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8420          * @param {String} position The position to align to.
8421          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8422          * @return {Array} [x, y]
8423          */
8424         getAlignToXY : function(el, p, o){
8425             el = Roo.get(el);
8426             var d = this.dom;
8427             if(!el.dom){
8428                 throw "Element.alignTo with an element that doesn't exist";
8429             }
8430             var c = false; //constrain to viewport
8431             var p1 = "", p2 = "";
8432             o = o || [0,0];
8433
8434             if(!p){
8435                 p = "tl-bl";
8436             }else if(p == "?"){
8437                 p = "tl-bl?";
8438             }else if(p.indexOf("-") == -1){
8439                 p = "tl-" + p;
8440             }
8441             p = p.toLowerCase();
8442             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8443             if(!m){
8444                throw "Element.alignTo with an invalid alignment " + p;
8445             }
8446             p1 = m[1]; p2 = m[2]; c = !!m[3];
8447
8448             //Subtract the aligned el's internal xy from the target's offset xy
8449             //plus custom offset to get the aligned el's new offset xy
8450             var a1 = this.getAnchorXY(p1, true);
8451             var a2 = el.getAnchorXY(p2, false);
8452             var x = a2[0] - a1[0] + o[0];
8453             var y = a2[1] - a1[1] + o[1];
8454             if(c){
8455                 //constrain the aligned el to viewport if necessary
8456                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8457                 // 5px of margin for ie
8458                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8459
8460                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8461                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8462                 //otherwise swap the aligned el to the opposite border of the target.
8463                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8464                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8465                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8466                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8467
8468                var doc = document;
8469                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8470                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8471
8472                if((x+w) > dw + scrollX){
8473                     x = swapX ? r.left-w : dw+scrollX-w;
8474                 }
8475                if(x < scrollX){
8476                    x = swapX ? r.right : scrollX;
8477                }
8478                if((y+h) > dh + scrollY){
8479                     y = swapY ? r.top-h : dh+scrollY-h;
8480                 }
8481                if (y < scrollY){
8482                    y = swapY ? r.bottom : scrollY;
8483                }
8484             }
8485             return [x,y];
8486         },
8487
8488         // private
8489         getConstrainToXY : function(){
8490             var os = {top:0, left:0, bottom:0, right: 0};
8491
8492             return function(el, local, offsets, proposedXY){
8493                 el = Roo.get(el);
8494                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8495
8496                 var vw, vh, vx = 0, vy = 0;
8497                 if(el.dom == document.body || el.dom == document){
8498                     vw = Roo.lib.Dom.getViewWidth();
8499                     vh = Roo.lib.Dom.getViewHeight();
8500                 }else{
8501                     vw = el.dom.clientWidth;
8502                     vh = el.dom.clientHeight;
8503                     if(!local){
8504                         var vxy = el.getXY();
8505                         vx = vxy[0];
8506                         vy = vxy[1];
8507                     }
8508                 }
8509
8510                 var s = el.getScroll();
8511
8512                 vx += offsets.left + s.left;
8513                 vy += offsets.top + s.top;
8514
8515                 vw -= offsets.right;
8516                 vh -= offsets.bottom;
8517
8518                 var vr = vx+vw;
8519                 var vb = vy+vh;
8520
8521                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8522                 var x = xy[0], y = xy[1];
8523                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8524
8525                 // only move it if it needs it
8526                 var moved = false;
8527
8528                 // first validate right/bottom
8529                 if((x + w) > vr){
8530                     x = vr - w;
8531                     moved = true;
8532                 }
8533                 if((y + h) > vb){
8534                     y = vb - h;
8535                     moved = true;
8536                 }
8537                 // then make sure top/left isn't negative
8538                 if(x < vx){
8539                     x = vx;
8540                     moved = true;
8541                 }
8542                 if(y < vy){
8543                     y = vy;
8544                     moved = true;
8545                 }
8546                 return moved ? [x, y] : false;
8547             };
8548         }(),
8549
8550         // private
8551         adjustForConstraints : function(xy, parent, offsets){
8552             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8553         },
8554
8555         /**
8556          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8557          * document it aligns it to the viewport.
8558          * The position parameter is optional, and can be specified in any one of the following formats:
8559          * <ul>
8560          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8561          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8562          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8563          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8564          *   <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
8565          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8566          * </ul>
8567          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8568          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8569          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8570          * that specified in order to enforce the viewport constraints.
8571          * Following are all of the supported anchor positions:
8572     <pre>
8573     Value  Description
8574     -----  -----------------------------
8575     tl     The top left corner (default)
8576     t      The center of the top edge
8577     tr     The top right corner
8578     l      The center of the left edge
8579     c      In the center of the element
8580     r      The center of the right edge
8581     bl     The bottom left corner
8582     b      The center of the bottom edge
8583     br     The bottom right corner
8584     </pre>
8585     Example Usage:
8586     <pre><code>
8587     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8588     el.alignTo("other-el");
8589
8590     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8591     el.alignTo("other-el", "tr?");
8592
8593     // align the bottom right corner of el with the center left edge of other-el
8594     el.alignTo("other-el", "br-l?");
8595
8596     // align the center of el with the bottom left corner of other-el and
8597     // adjust the x position by -6 pixels (and the y position by 0)
8598     el.alignTo("other-el", "c-bl", [-6, 0]);
8599     </code></pre>
8600          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8601          * @param {String} position The position to align to.
8602          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8603          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8604          * @return {Roo.Element} this
8605          */
8606         alignTo : function(element, position, offsets, animate){
8607             var xy = this.getAlignToXY(element, position, offsets);
8608             this.setXY(xy, this.preanim(arguments, 3));
8609             return this;
8610         },
8611
8612         /**
8613          * Anchors an element to another element and realigns it when the window is resized.
8614          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8615          * @param {String} position The position to align to.
8616          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8617          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8618          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8619          * is a number, it is used as the buffer delay (defaults to 50ms).
8620          * @param {Function} callback The function to call after the animation finishes
8621          * @return {Roo.Element} this
8622          */
8623         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8624             var action = function(){
8625                 this.alignTo(el, alignment, offsets, animate);
8626                 Roo.callback(callback, this);
8627             };
8628             Roo.EventManager.onWindowResize(action, this);
8629             var tm = typeof monitorScroll;
8630             if(tm != 'undefined'){
8631                 Roo.EventManager.on(window, 'scroll', action, this,
8632                     {buffer: tm == 'number' ? monitorScroll : 50});
8633             }
8634             action.call(this); // align immediately
8635             return this;
8636         },
8637         /**
8638          * Clears any opacity settings from this element. Required in some cases for IE.
8639          * @return {Roo.Element} this
8640          */
8641         clearOpacity : function(){
8642             if (window.ActiveXObject) {
8643                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8644                     this.dom.style.filter = "";
8645                 }
8646             } else {
8647                 this.dom.style.opacity = "";
8648                 this.dom.style["-moz-opacity"] = "";
8649                 this.dom.style["-khtml-opacity"] = "";
8650             }
8651             return this;
8652         },
8653
8654         /**
8655          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8656          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8657          * @return {Roo.Element} this
8658          */
8659         hide : function(animate){
8660             this.setVisible(false, this.preanim(arguments, 0));
8661             return this;
8662         },
8663
8664         /**
8665         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8666         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8667          * @return {Roo.Element} this
8668          */
8669         show : function(animate){
8670             this.setVisible(true, this.preanim(arguments, 0));
8671             return this;
8672         },
8673
8674         /**
8675          * @private Test if size has a unit, otherwise appends the default
8676          */
8677         addUnits : function(size){
8678             return Roo.Element.addUnits(size, this.defaultUnit);
8679         },
8680
8681         /**
8682          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8683          * @return {Roo.Element} this
8684          */
8685         beginMeasure : function(){
8686             var el = this.dom;
8687             if(el.offsetWidth || el.offsetHeight){
8688                 return this; // offsets work already
8689             }
8690             var changed = [];
8691             var p = this.dom, b = document.body; // start with this element
8692             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8693                 var pe = Roo.get(p);
8694                 if(pe.getStyle('display') == 'none'){
8695                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8696                     p.style.visibility = "hidden";
8697                     p.style.display = "block";
8698                 }
8699                 p = p.parentNode;
8700             }
8701             this._measureChanged = changed;
8702             return this;
8703
8704         },
8705
8706         /**
8707          * Restores displays to before beginMeasure was called
8708          * @return {Roo.Element} this
8709          */
8710         endMeasure : function(){
8711             var changed = this._measureChanged;
8712             if(changed){
8713                 for(var i = 0, len = changed.length; i < len; i++) {
8714                     var r = changed[i];
8715                     r.el.style.visibility = r.visibility;
8716                     r.el.style.display = "none";
8717                 }
8718                 this._measureChanged = null;
8719             }
8720             return this;
8721         },
8722
8723         /**
8724         * Update the innerHTML of this element, optionally searching for and processing scripts
8725         * @param {String} html The new HTML
8726         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8727         * @param {Function} callback For async script loading you can be noticed when the update completes
8728         * @return {Roo.Element} this
8729          */
8730         update : function(html, loadScripts, callback){
8731             if(typeof html == "undefined"){
8732                 html = "";
8733             }
8734             if(loadScripts !== true){
8735                 this.dom.innerHTML = html;
8736                 if(typeof callback == "function"){
8737                     callback();
8738                 }
8739                 return this;
8740             }
8741             var id = Roo.id();
8742             var dom = this.dom;
8743
8744             html += '<span id="' + id + '"></span>';
8745
8746             E.onAvailable(id, function(){
8747                 var hd = document.getElementsByTagName("head")[0];
8748                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8749                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8750                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8751
8752                 var match;
8753                 while(match = re.exec(html)){
8754                     var attrs = match[1];
8755                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8756                     if(srcMatch && srcMatch[2]){
8757                        var s = document.createElement("script");
8758                        s.src = srcMatch[2];
8759                        var typeMatch = attrs.match(typeRe);
8760                        if(typeMatch && typeMatch[2]){
8761                            s.type = typeMatch[2];
8762                        }
8763                        hd.appendChild(s);
8764                     }else if(match[2] && match[2].length > 0){
8765                         if(window.execScript) {
8766                            window.execScript(match[2]);
8767                         } else {
8768                             /**
8769                              * eval:var:id
8770                              * eval:var:dom
8771                              * eval:var:html
8772                              * 
8773                              */
8774                            window.eval(match[2]);
8775                         }
8776                     }
8777                 }
8778                 var el = document.getElementById(id);
8779                 if(el){el.parentNode.removeChild(el);}
8780                 if(typeof callback == "function"){
8781                     callback();
8782                 }
8783             });
8784             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8785             return this;
8786         },
8787
8788         /**
8789          * Direct access to the UpdateManager update() method (takes the same parameters).
8790          * @param {String/Function} url The url for this request or a function to call to get the url
8791          * @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}
8792          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8793          * @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.
8794          * @return {Roo.Element} this
8795          */
8796         load : function(){
8797             var um = this.getUpdateManager();
8798             um.update.apply(um, arguments);
8799             return this;
8800         },
8801
8802         /**
8803         * Gets this element's UpdateManager
8804         * @return {Roo.UpdateManager} The UpdateManager
8805         */
8806         getUpdateManager : function(){
8807             if(!this.updateManager){
8808                 this.updateManager = new Roo.UpdateManager(this);
8809             }
8810             return this.updateManager;
8811         },
8812
8813         /**
8814          * Disables text selection for this element (normalized across browsers)
8815          * @return {Roo.Element} this
8816          */
8817         unselectable : function(){
8818             this.dom.unselectable = "on";
8819             this.swallowEvent("selectstart", true);
8820             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8821             this.addClass("x-unselectable");
8822             return this;
8823         },
8824
8825         /**
8826         * Calculates the x, y to center this element on the screen
8827         * @return {Array} The x, y values [x, y]
8828         */
8829         getCenterXY : function(){
8830             return this.getAlignToXY(document, 'c-c');
8831         },
8832
8833         /**
8834         * Centers the Element in either the viewport, or another Element.
8835         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8836         */
8837         center : function(centerIn){
8838             this.alignTo(centerIn || document, 'c-c');
8839             return this;
8840         },
8841
8842         /**
8843          * Tests various css rules/browsers to determine if this element uses a border box
8844          * @return {Boolean}
8845          */
8846         isBorderBox : function(){
8847             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8848         },
8849
8850         /**
8851          * Return a box {x, y, width, height} that can be used to set another elements
8852          * size/location to match this element.
8853          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8854          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8855          * @return {Object} box An object in the format {x, y, width, height}
8856          */
8857         getBox : function(contentBox, local){
8858             var xy;
8859             if(!local){
8860                 xy = this.getXY();
8861             }else{
8862                 var left = parseInt(this.getStyle("left"), 10) || 0;
8863                 var top = parseInt(this.getStyle("top"), 10) || 0;
8864                 xy = [left, top];
8865             }
8866             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8867             if(!contentBox){
8868                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8869             }else{
8870                 var l = this.getBorderWidth("l")+this.getPadding("l");
8871                 var r = this.getBorderWidth("r")+this.getPadding("r");
8872                 var t = this.getBorderWidth("t")+this.getPadding("t");
8873                 var b = this.getBorderWidth("b")+this.getPadding("b");
8874                 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)};
8875             }
8876             bx.right = bx.x + bx.width;
8877             bx.bottom = bx.y + bx.height;
8878             return bx;
8879         },
8880
8881         /**
8882          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8883          for more information about the sides.
8884          * @param {String} sides
8885          * @return {Number}
8886          */
8887         getFrameWidth : function(sides, onlyContentBox){
8888             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8889         },
8890
8891         /**
8892          * 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.
8893          * @param {Object} box The box to fill {x, y, width, height}
8894          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8895          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8896          * @return {Roo.Element} this
8897          */
8898         setBox : function(box, adjust, animate){
8899             var w = box.width, h = box.height;
8900             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8901                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8902                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8903             }
8904             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8905             return this;
8906         },
8907
8908         /**
8909          * Forces the browser to repaint this element
8910          * @return {Roo.Element} this
8911          */
8912          repaint : function(){
8913             var dom = this.dom;
8914             this.addClass("x-repaint");
8915             setTimeout(function(){
8916                 Roo.get(dom).removeClass("x-repaint");
8917             }, 1);
8918             return this;
8919         },
8920
8921         /**
8922          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8923          * then it returns the calculated width of the sides (see getPadding)
8924          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8925          * @return {Object/Number}
8926          */
8927         getMargins : function(side){
8928             if(!side){
8929                 return {
8930                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8931                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8932                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8933                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8934                 };
8935             }else{
8936                 return this.addStyles(side, El.margins);
8937              }
8938         },
8939
8940         // private
8941         addStyles : function(sides, styles){
8942             var val = 0, v, w;
8943             for(var i = 0, len = sides.length; i < len; i++){
8944                 v = this.getStyle(styles[sides.charAt(i)]);
8945                 if(v){
8946                      w = parseInt(v, 10);
8947                      if(w){ val += w; }
8948                 }
8949             }
8950             return val;
8951         },
8952
8953         /**
8954          * Creates a proxy element of this element
8955          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8956          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8957          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8958          * @return {Roo.Element} The new proxy element
8959          */
8960         createProxy : function(config, renderTo, matchBox){
8961             if(renderTo){
8962                 renderTo = Roo.getDom(renderTo);
8963             }else{
8964                 renderTo = document.body;
8965             }
8966             config = typeof config == "object" ?
8967                 config : {tag : "div", cls: config};
8968             var proxy = Roo.DomHelper.append(renderTo, config, true);
8969             if(matchBox){
8970                proxy.setBox(this.getBox());
8971             }
8972             return proxy;
8973         },
8974
8975         /**
8976          * Puts a mask over this element to disable user interaction. Requires core.css.
8977          * This method can only be applied to elements which accept child nodes.
8978          * @param {String} msg (optional) A message to display in the mask
8979          * @param {String} msgCls (optional) A css class to apply to the msg element
8980          * @return {Element} The mask  element
8981          */
8982         mask : function(msg, msgCls)
8983         {
8984             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8985                 this.setStyle("position", "relative");
8986             }
8987             if(!this._mask){
8988                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8989             }
8990             this.addClass("x-masked");
8991             this._mask.setDisplayed(true);
8992             
8993             // we wander
8994             var z = 0;
8995             var dom = this.dom
8996             while (dom && dom.style) {
8997                 if (!isNaN(parseInt(dom.style.zIndex))) {
8998                     z = Math.max(z, parseInt(dom.style.zIndex));
8999                 }
9000                 dom = dom.parentNode;
9001             }
9002             // if we are masking the body - then it hides everything..
9003             if (this.dom == document.body) {
9004                 z = 1000000;
9005                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9006                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9007             }
9008            
9009             if(typeof msg == 'string'){
9010                 if(!this._maskMsg){
9011                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9012                 }
9013                 var mm = this._maskMsg;
9014                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9015                 if (mm.dom.firstChild) { // weird IE issue?
9016                     mm.dom.firstChild.innerHTML = msg;
9017                 }
9018                 mm.setDisplayed(true);
9019                 mm.center(this);
9020                 mm.setStyle('z-index', z + 102);
9021             }
9022             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9023                 this._mask.setHeight(this.getHeight());
9024             }
9025             this._mask.setStyle('z-index', z + 100);
9026             
9027             return this._mask;
9028         },
9029
9030         /**
9031          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9032          * it is cached for reuse.
9033          */
9034         unmask : function(removeEl){
9035             if(this._mask){
9036                 if(removeEl === true){
9037                     this._mask.remove();
9038                     delete this._mask;
9039                     if(this._maskMsg){
9040                         this._maskMsg.remove();
9041                         delete this._maskMsg;
9042                     }
9043                 }else{
9044                     this._mask.setDisplayed(false);
9045                     if(this._maskMsg){
9046                         this._maskMsg.setDisplayed(false);
9047                     }
9048                 }
9049             }
9050             this.removeClass("x-masked");
9051         },
9052
9053         /**
9054          * Returns true if this element is masked
9055          * @return {Boolean}
9056          */
9057         isMasked : function(){
9058             return this._mask && this._mask.isVisible();
9059         },
9060
9061         /**
9062          * Creates an iframe shim for this element to keep selects and other windowed objects from
9063          * showing through.
9064          * @return {Roo.Element} The new shim element
9065          */
9066         createShim : function(){
9067             var el = document.createElement('iframe');
9068             el.frameBorder = 'no';
9069             el.className = 'roo-shim';
9070             if(Roo.isIE && Roo.isSecure){
9071                 el.src = Roo.SSL_SECURE_URL;
9072             }
9073             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9074             shim.autoBoxAdjust = false;
9075             return shim;
9076         },
9077
9078         /**
9079          * Removes this element from the DOM and deletes it from the cache
9080          */
9081         remove : function(){
9082             if(this.dom.parentNode){
9083                 this.dom.parentNode.removeChild(this.dom);
9084             }
9085             delete El.cache[this.dom.id];
9086         },
9087
9088         /**
9089          * Sets up event handlers to add and remove a css class when the mouse is over this element
9090          * @param {String} className
9091          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9092          * mouseout events for children elements
9093          * @return {Roo.Element} this
9094          */
9095         addClassOnOver : function(className, preventFlicker){
9096             this.on("mouseover", function(){
9097                 Roo.fly(this, '_internal').addClass(className);
9098             }, this.dom);
9099             var removeFn = function(e){
9100                 if(preventFlicker !== true || !e.within(this, true)){
9101                     Roo.fly(this, '_internal').removeClass(className);
9102                 }
9103             };
9104             this.on("mouseout", removeFn, this.dom);
9105             return this;
9106         },
9107
9108         /**
9109          * Sets up event handlers to add and remove a css class when this element has the focus
9110          * @param {String} className
9111          * @return {Roo.Element} this
9112          */
9113         addClassOnFocus : function(className){
9114             this.on("focus", function(){
9115                 Roo.fly(this, '_internal').addClass(className);
9116             }, this.dom);
9117             this.on("blur", function(){
9118                 Roo.fly(this, '_internal').removeClass(className);
9119             }, this.dom);
9120             return this;
9121         },
9122         /**
9123          * 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)
9124          * @param {String} className
9125          * @return {Roo.Element} this
9126          */
9127         addClassOnClick : function(className){
9128             var dom = this.dom;
9129             this.on("mousedown", function(){
9130                 Roo.fly(dom, '_internal').addClass(className);
9131                 var d = Roo.get(document);
9132                 var fn = function(){
9133                     Roo.fly(dom, '_internal').removeClass(className);
9134                     d.removeListener("mouseup", fn);
9135                 };
9136                 d.on("mouseup", fn);
9137             });
9138             return this;
9139         },
9140
9141         /**
9142          * Stops the specified event from bubbling and optionally prevents the default action
9143          * @param {String} eventName
9144          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9145          * @return {Roo.Element} this
9146          */
9147         swallowEvent : function(eventName, preventDefault){
9148             var fn = function(e){
9149                 e.stopPropagation();
9150                 if(preventDefault){
9151                     e.preventDefault();
9152                 }
9153             };
9154             if(eventName instanceof Array){
9155                 for(var i = 0, len = eventName.length; i < len; i++){
9156                      this.on(eventName[i], fn);
9157                 }
9158                 return this;
9159             }
9160             this.on(eventName, fn);
9161             return this;
9162         },
9163
9164         /**
9165          * @private
9166          */
9167       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9168
9169         /**
9170          * Sizes this element to its parent element's dimensions performing
9171          * neccessary box adjustments.
9172          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9173          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9174          * @return {Roo.Element} this
9175          */
9176         fitToParent : function(monitorResize, targetParent) {
9177           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9178           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9179           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9180             return;
9181           }
9182           var p = Roo.get(targetParent || this.dom.parentNode);
9183           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9184           if (monitorResize === true) {
9185             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9186             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9187           }
9188           return this;
9189         },
9190
9191         /**
9192          * Gets the next sibling, skipping text nodes
9193          * @return {HTMLElement} The next sibling or null
9194          */
9195         getNextSibling : function(){
9196             var n = this.dom.nextSibling;
9197             while(n && n.nodeType != 1){
9198                 n = n.nextSibling;
9199             }
9200             return n;
9201         },
9202
9203         /**
9204          * Gets the previous sibling, skipping text nodes
9205          * @return {HTMLElement} The previous sibling or null
9206          */
9207         getPrevSibling : function(){
9208             var n = this.dom.previousSibling;
9209             while(n && n.nodeType != 1){
9210                 n = n.previousSibling;
9211             }
9212             return n;
9213         },
9214
9215
9216         /**
9217          * Appends the passed element(s) to this element
9218          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9219          * @return {Roo.Element} this
9220          */
9221         appendChild: function(el){
9222             el = Roo.get(el);
9223             el.appendTo(this);
9224             return this;
9225         },
9226
9227         /**
9228          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9229          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9230          * automatically generated with the specified attributes.
9231          * @param {HTMLElement} insertBefore (optional) a child element of this element
9232          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9233          * @return {Roo.Element} The new child element
9234          */
9235         createChild: function(config, insertBefore, returnDom){
9236             config = config || {tag:'div'};
9237             if(insertBefore){
9238                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9239             }
9240             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9241         },
9242
9243         /**
9244          * Appends this element to the passed element
9245          * @param {String/HTMLElement/Element} el The new parent element
9246          * @return {Roo.Element} this
9247          */
9248         appendTo: function(el){
9249             el = Roo.getDom(el);
9250             el.appendChild(this.dom);
9251             return this;
9252         },
9253
9254         /**
9255          * Inserts this element before the passed element in the DOM
9256          * @param {String/HTMLElement/Element} el The element to insert before
9257          * @return {Roo.Element} this
9258          */
9259         insertBefore: function(el){
9260             el = Roo.getDom(el);
9261             el.parentNode.insertBefore(this.dom, el);
9262             return this;
9263         },
9264
9265         /**
9266          * Inserts this element after the passed element in the DOM
9267          * @param {String/HTMLElement/Element} el The element to insert after
9268          * @return {Roo.Element} this
9269          */
9270         insertAfter: function(el){
9271             el = Roo.getDom(el);
9272             el.parentNode.insertBefore(this.dom, el.nextSibling);
9273             return this;
9274         },
9275
9276         /**
9277          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9278          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9279          * @return {Roo.Element} The new child
9280          */
9281         insertFirst: function(el, returnDom){
9282             el = el || {};
9283             if(typeof el == 'object' && !el.nodeType){ // dh config
9284                 return this.createChild(el, this.dom.firstChild, returnDom);
9285             }else{
9286                 el = Roo.getDom(el);
9287                 this.dom.insertBefore(el, this.dom.firstChild);
9288                 return !returnDom ? Roo.get(el) : el;
9289             }
9290         },
9291
9292         /**
9293          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9294          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9295          * @param {String} where (optional) 'before' or 'after' defaults to before
9296          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9297          * @return {Roo.Element} the inserted Element
9298          */
9299         insertSibling: function(el, where, returnDom){
9300             where = where ? where.toLowerCase() : 'before';
9301             el = el || {};
9302             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9303
9304             if(typeof el == 'object' && !el.nodeType){ // dh config
9305                 if(where == 'after' && !this.dom.nextSibling){
9306                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9307                 }else{
9308                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9309                 }
9310
9311             }else{
9312                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9313                             where == 'before' ? this.dom : this.dom.nextSibling);
9314                 if(!returnDom){
9315                     rt = Roo.get(rt);
9316                 }
9317             }
9318             return rt;
9319         },
9320
9321         /**
9322          * Creates and wraps this element with another element
9323          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9324          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9325          * @return {HTMLElement/Element} The newly created wrapper element
9326          */
9327         wrap: function(config, returnDom){
9328             if(!config){
9329                 config = {tag: "div"};
9330             }
9331             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9332             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9333             return newEl;
9334         },
9335
9336         /**
9337          * Replaces the passed element with this element
9338          * @param {String/HTMLElement/Element} el The element to replace
9339          * @return {Roo.Element} this
9340          */
9341         replace: function(el){
9342             el = Roo.get(el);
9343             this.insertBefore(el);
9344             el.remove();
9345             return this;
9346         },
9347
9348         /**
9349          * Inserts an html fragment into this element
9350          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9351          * @param {String} html The HTML fragment
9352          * @param {Boolean} returnEl True to return an Roo.Element
9353          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9354          */
9355         insertHtml : function(where, html, returnEl){
9356             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9357             return returnEl ? Roo.get(el) : el;
9358         },
9359
9360         /**
9361          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9362          * @param {Object} o The object with the attributes
9363          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9364          * @return {Roo.Element} this
9365          */
9366         set : function(o, useSet){
9367             var el = this.dom;
9368             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9369             for(var attr in o){
9370                 if(attr == "style" || typeof o[attr] == "function") continue;
9371                 if(attr=="cls"){
9372                     el.className = o["cls"];
9373                 }else{
9374                     if(useSet) el.setAttribute(attr, o[attr]);
9375                     else el[attr] = o[attr];
9376                 }
9377             }
9378             if(o.style){
9379                 Roo.DomHelper.applyStyles(el, o.style);
9380             }
9381             return this;
9382         },
9383
9384         /**
9385          * Convenience method for constructing a KeyMap
9386          * @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:
9387          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9388          * @param {Function} fn The function to call
9389          * @param {Object} scope (optional) The scope of the function
9390          * @return {Roo.KeyMap} The KeyMap created
9391          */
9392         addKeyListener : function(key, fn, scope){
9393             var config;
9394             if(typeof key != "object" || key instanceof Array){
9395                 config = {
9396                     key: key,
9397                     fn: fn,
9398                     scope: scope
9399                 };
9400             }else{
9401                 config = {
9402                     key : key.key,
9403                     shift : key.shift,
9404                     ctrl : key.ctrl,
9405                     alt : key.alt,
9406                     fn: fn,
9407                     scope: scope
9408                 };
9409             }
9410             return new Roo.KeyMap(this, config);
9411         },
9412
9413         /**
9414          * Creates a KeyMap for this element
9415          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9416          * @return {Roo.KeyMap} The KeyMap created
9417          */
9418         addKeyMap : function(config){
9419             return new Roo.KeyMap(this, config);
9420         },
9421
9422         /**
9423          * Returns true if this element is scrollable.
9424          * @return {Boolean}
9425          */
9426          isScrollable : function(){
9427             var dom = this.dom;
9428             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9429         },
9430
9431         /**
9432          * 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().
9433          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9434          * @param {Number} value The new scroll value
9435          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9436          * @return {Element} this
9437          */
9438
9439         scrollTo : function(side, value, animate){
9440             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9441             if(!animate || !A){
9442                 this.dom[prop] = value;
9443             }else{
9444                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9445                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9446             }
9447             return this;
9448         },
9449
9450         /**
9451          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9452          * within this element's scrollable range.
9453          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9454          * @param {Number} distance How far to scroll the element in pixels
9455          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9456          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9457          * was scrolled as far as it could go.
9458          */
9459          scroll : function(direction, distance, animate){
9460              if(!this.isScrollable()){
9461                  return;
9462              }
9463              var el = this.dom;
9464              var l = el.scrollLeft, t = el.scrollTop;
9465              var w = el.scrollWidth, h = el.scrollHeight;
9466              var cw = el.clientWidth, ch = el.clientHeight;
9467              direction = direction.toLowerCase();
9468              var scrolled = false;
9469              var a = this.preanim(arguments, 2);
9470              switch(direction){
9471                  case "l":
9472                  case "left":
9473                      if(w - l > cw){
9474                          var v = Math.min(l + distance, w-cw);
9475                          this.scrollTo("left", v, a);
9476                          scrolled = true;
9477                      }
9478                      break;
9479                 case "r":
9480                 case "right":
9481                      if(l > 0){
9482                          var v = Math.max(l - distance, 0);
9483                          this.scrollTo("left", v, a);
9484                          scrolled = true;
9485                      }
9486                      break;
9487                 case "t":
9488                 case "top":
9489                 case "up":
9490                      if(t > 0){
9491                          var v = Math.max(t - distance, 0);
9492                          this.scrollTo("top", v, a);
9493                          scrolled = true;
9494                      }
9495                      break;
9496                 case "b":
9497                 case "bottom":
9498                 case "down":
9499                      if(h - t > ch){
9500                          var v = Math.min(t + distance, h-ch);
9501                          this.scrollTo("top", v, a);
9502                          scrolled = true;
9503                      }
9504                      break;
9505              }
9506              return scrolled;
9507         },
9508
9509         /**
9510          * Translates the passed page coordinates into left/top css values for this element
9511          * @param {Number/Array} x The page x or an array containing [x, y]
9512          * @param {Number} y The page y
9513          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9514          */
9515         translatePoints : function(x, y){
9516             if(typeof x == 'object' || x instanceof Array){
9517                 y = x[1]; x = x[0];
9518             }
9519             var p = this.getStyle('position');
9520             var o = this.getXY();
9521
9522             var l = parseInt(this.getStyle('left'), 10);
9523             var t = parseInt(this.getStyle('top'), 10);
9524
9525             if(isNaN(l)){
9526                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9527             }
9528             if(isNaN(t)){
9529                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9530             }
9531
9532             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9533         },
9534
9535         /**
9536          * Returns the current scroll position of the element.
9537          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9538          */
9539         getScroll : function(){
9540             var d = this.dom, doc = document;
9541             if(d == doc || d == doc.body){
9542                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9543                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9544                 return {left: l, top: t};
9545             }else{
9546                 return {left: d.scrollLeft, top: d.scrollTop};
9547             }
9548         },
9549
9550         /**
9551          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9552          * are convert to standard 6 digit hex color.
9553          * @param {String} attr The css attribute
9554          * @param {String} defaultValue The default value to use when a valid color isn't found
9555          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9556          * YUI color anims.
9557          */
9558         getColor : function(attr, defaultValue, prefix){
9559             var v = this.getStyle(attr);
9560             if(!v || v == "transparent" || v == "inherit") {
9561                 return defaultValue;
9562             }
9563             var color = typeof prefix == "undefined" ? "#" : prefix;
9564             if(v.substr(0, 4) == "rgb("){
9565                 var rvs = v.slice(4, v.length -1).split(",");
9566                 for(var i = 0; i < 3; i++){
9567                     var h = parseInt(rvs[i]).toString(16);
9568                     if(h < 16){
9569                         h = "0" + h;
9570                     }
9571                     color += h;
9572                 }
9573             } else {
9574                 if(v.substr(0, 1) == "#"){
9575                     if(v.length == 4) {
9576                         for(var i = 1; i < 4; i++){
9577                             var c = v.charAt(i);
9578                             color +=  c + c;
9579                         }
9580                     }else if(v.length == 7){
9581                         color += v.substr(1);
9582                     }
9583                 }
9584             }
9585             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9586         },
9587
9588         /**
9589          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9590          * gradient background, rounded corners and a 4-way shadow.
9591          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9592          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9593          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9594          * @return {Roo.Element} this
9595          */
9596         boxWrap : function(cls){
9597             cls = cls || 'x-box';
9598             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9599             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9600             return el;
9601         },
9602
9603         /**
9604          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9605          * @param {String} namespace The namespace in which to look for the attribute
9606          * @param {String} name The attribute name
9607          * @return {String} The attribute value
9608          */
9609         getAttributeNS : Roo.isIE ? function(ns, name){
9610             var d = this.dom;
9611             var type = typeof d[ns+":"+name];
9612             if(type != 'undefined' && type != 'unknown'){
9613                 return d[ns+":"+name];
9614             }
9615             return d[name];
9616         } : function(ns, name){
9617             var d = this.dom;
9618             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9619         },
9620         
9621         
9622         /**
9623          * Sets or Returns the value the dom attribute value
9624          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9625          * @param {String} value (optional) The value to set the attribute to
9626          * @return {String} The attribute value
9627          */
9628         attr : function(name){
9629             if (arguments.length > 1) {
9630                 this.dom.setAttribute(name, arguments[1]);
9631                 return arguments[1];
9632             }
9633             if (typeof(name) == 'object') {
9634                 for(var i in name) {
9635                     this.attr(i, name[i]);
9636                 }
9637                 return name;
9638             }
9639             
9640             
9641             if (!this.dom.hasAttribute(name)) {
9642                 return undefined;
9643             }
9644             return this.dom.getAttribute(name);
9645         }
9646         
9647         
9648         
9649     };
9650
9651     var ep = El.prototype;
9652
9653     /**
9654      * Appends an event handler (Shorthand for addListener)
9655      * @param {String}   eventName     The type of event to append
9656      * @param {Function} fn        The method the event invokes
9657      * @param {Object} scope       (optional) The scope (this object) of the fn
9658      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9659      * @method
9660      */
9661     ep.on = ep.addListener;
9662         // backwards compat
9663     ep.mon = ep.addListener;
9664
9665     /**
9666      * Removes an event handler from this element (shorthand for removeListener)
9667      * @param {String} eventName the type of event to remove
9668      * @param {Function} fn the method the event invokes
9669      * @return {Roo.Element} this
9670      * @method
9671      */
9672     ep.un = ep.removeListener;
9673
9674     /**
9675      * true to automatically adjust width and height settings for box-model issues (default to true)
9676      */
9677     ep.autoBoxAdjust = true;
9678
9679     // private
9680     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9681
9682     // private
9683     El.addUnits = function(v, defaultUnit){
9684         if(v === "" || v == "auto"){
9685             return v;
9686         }
9687         if(v === undefined){
9688             return '';
9689         }
9690         if(typeof v == "number" || !El.unitPattern.test(v)){
9691             return v + (defaultUnit || 'px');
9692         }
9693         return v;
9694     };
9695
9696     // special markup used throughout Roo when box wrapping elements
9697     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>';
9698     /**
9699      * Visibility mode constant - Use visibility to hide element
9700      * @static
9701      * @type Number
9702      */
9703     El.VISIBILITY = 1;
9704     /**
9705      * Visibility mode constant - Use display to hide element
9706      * @static
9707      * @type Number
9708      */
9709     El.DISPLAY = 2;
9710
9711     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9712     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9713     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9714
9715
9716
9717     /**
9718      * @private
9719      */
9720     El.cache = {};
9721
9722     var docEl;
9723
9724     /**
9725      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9726      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9727      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9728      * @return {Element} The Element object
9729      * @static
9730      */
9731     El.get = function(el){
9732         var ex, elm, id;
9733         if(!el){ return null; }
9734         if(typeof el == "string"){ // element id
9735             if(!(elm = document.getElementById(el))){
9736                 return null;
9737             }
9738             if(ex = El.cache[el]){
9739                 ex.dom = elm;
9740             }else{
9741                 ex = El.cache[el] = new El(elm);
9742             }
9743             return ex;
9744         }else if(el.tagName){ // dom element
9745             if(!(id = el.id)){
9746                 id = Roo.id(el);
9747             }
9748             if(ex = El.cache[id]){
9749                 ex.dom = el;
9750             }else{
9751                 ex = El.cache[id] = new El(el);
9752             }
9753             return ex;
9754         }else if(el instanceof El){
9755             if(el != docEl){
9756                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9757                                                               // catch case where it hasn't been appended
9758                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9759             }
9760             return el;
9761         }else if(el.isComposite){
9762             return el;
9763         }else if(el instanceof Array){
9764             return El.select(el);
9765         }else if(el == document){
9766             // create a bogus element object representing the document object
9767             if(!docEl){
9768                 var f = function(){};
9769                 f.prototype = El.prototype;
9770                 docEl = new f();
9771                 docEl.dom = document;
9772             }
9773             return docEl;
9774         }
9775         return null;
9776     };
9777
9778     // private
9779     El.uncache = function(el){
9780         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9781             if(a[i]){
9782                 delete El.cache[a[i].id || a[i]];
9783             }
9784         }
9785     };
9786
9787     // private
9788     // Garbage collection - uncache elements/purge listeners on orphaned elements
9789     // so we don't hold a reference and cause the browser to retain them
9790     El.garbageCollect = function(){
9791         if(!Roo.enableGarbageCollector){
9792             clearInterval(El.collectorThread);
9793             return;
9794         }
9795         for(var eid in El.cache){
9796             var el = El.cache[eid], d = el.dom;
9797             // -------------------------------------------------------
9798             // Determining what is garbage:
9799             // -------------------------------------------------------
9800             // !d
9801             // dom node is null, definitely garbage
9802             // -------------------------------------------------------
9803             // !d.parentNode
9804             // no parentNode == direct orphan, definitely garbage
9805             // -------------------------------------------------------
9806             // !d.offsetParent && !document.getElementById(eid)
9807             // display none elements have no offsetParent so we will
9808             // also try to look it up by it's id. However, check
9809             // offsetParent first so we don't do unneeded lookups.
9810             // This enables collection of elements that are not orphans
9811             // directly, but somewhere up the line they have an orphan
9812             // parent.
9813             // -------------------------------------------------------
9814             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9815                 delete El.cache[eid];
9816                 if(d && Roo.enableListenerCollection){
9817                     E.purgeElement(d);
9818                 }
9819             }
9820         }
9821     }
9822     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9823
9824
9825     // dom is optional
9826     El.Flyweight = function(dom){
9827         this.dom = dom;
9828     };
9829     El.Flyweight.prototype = El.prototype;
9830
9831     El._flyweights = {};
9832     /**
9833      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9834      * the dom node can be overwritten by other code.
9835      * @param {String/HTMLElement} el The dom node or id
9836      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9837      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9838      * @static
9839      * @return {Element} The shared Element object
9840      */
9841     El.fly = function(el, named){
9842         named = named || '_global';
9843         el = Roo.getDom(el);
9844         if(!el){
9845             return null;
9846         }
9847         if(!El._flyweights[named]){
9848             El._flyweights[named] = new El.Flyweight();
9849         }
9850         El._flyweights[named].dom = el;
9851         return El._flyweights[named];
9852     };
9853
9854     /**
9855      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9856      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9857      * Shorthand of {@link Roo.Element#get}
9858      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9859      * @return {Element} The Element object
9860      * @member Roo
9861      * @method get
9862      */
9863     Roo.get = El.get;
9864     /**
9865      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9866      * the dom node can be overwritten by other code.
9867      * Shorthand of {@link Roo.Element#fly}
9868      * @param {String/HTMLElement} el The dom node or id
9869      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9870      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9871      * @static
9872      * @return {Element} The shared Element object
9873      * @member Roo
9874      * @method fly
9875      */
9876     Roo.fly = El.fly;
9877
9878     // speedy lookup for elements never to box adjust
9879     var noBoxAdjust = Roo.isStrict ? {
9880         select:1
9881     } : {
9882         input:1, select:1, textarea:1
9883     };
9884     if(Roo.isIE || Roo.isGecko){
9885         noBoxAdjust['button'] = 1;
9886     }
9887
9888
9889     Roo.EventManager.on(window, 'unload', function(){
9890         delete El.cache;
9891         delete El._flyweights;
9892     });
9893 })();
9894
9895
9896
9897
9898 if(Roo.DomQuery){
9899     Roo.Element.selectorFunction = Roo.DomQuery.select;
9900 }
9901
9902 Roo.Element.select = function(selector, unique, root){
9903     var els;
9904     if(typeof selector == "string"){
9905         els = Roo.Element.selectorFunction(selector, root);
9906     }else if(selector.length !== undefined){
9907         els = selector;
9908     }else{
9909         throw "Invalid selector";
9910     }
9911     if(unique === true){
9912         return new Roo.CompositeElement(els);
9913     }else{
9914         return new Roo.CompositeElementLite(els);
9915     }
9916 };
9917 /**
9918  * Selects elements based on the passed CSS selector to enable working on them as 1.
9919  * @param {String/Array} selector The CSS selector or an array of elements
9920  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9921  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9922  * @return {CompositeElementLite/CompositeElement}
9923  * @member Roo
9924  * @method select
9925  */
9926 Roo.select = Roo.Element.select;
9927
9928
9929
9930
9931
9932
9933
9934
9935
9936
9937
9938
9939
9940
9941 /*
9942  * Based on:
9943  * Ext JS Library 1.1.1
9944  * Copyright(c) 2006-2007, Ext JS, LLC.
9945  *
9946  * Originally Released Under LGPL - original licence link has changed is not relivant.
9947  *
9948  * Fork - LGPL
9949  * <script type="text/javascript">
9950  */
9951
9952
9953
9954 //Notifies Element that fx methods are available
9955 Roo.enableFx = true;
9956
9957 /**
9958  * @class Roo.Fx
9959  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9960  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9961  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9962  * Element effects to work.</p><br/>
9963  *
9964  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9965  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9966  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9967  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9968  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9969  * expected results and should be done with care.</p><br/>
9970  *
9971  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9972  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9973 <pre>
9974 Value  Description
9975 -----  -----------------------------
9976 tl     The top left corner
9977 t      The center of the top edge
9978 tr     The top right corner
9979 l      The center of the left edge
9980 r      The center of the right edge
9981 bl     The bottom left corner
9982 b      The center of the bottom edge
9983 br     The bottom right corner
9984 </pre>
9985  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9986  * below are common options that can be passed to any Fx method.</b>
9987  * @cfg {Function} callback A function called when the effect is finished
9988  * @cfg {Object} scope The scope of the effect function
9989  * @cfg {String} easing A valid Easing value for the effect
9990  * @cfg {String} afterCls A css class to apply after the effect
9991  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9992  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9993  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9994  * effects that end with the element being visually hidden, ignored otherwise)
9995  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9996  * a function which returns such a specification that will be applied to the Element after the effect finishes
9997  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9998  * @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
9999  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10000  */
10001 Roo.Fx = {
10002         /**
10003          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10004          * origin for the slide effect.  This function automatically handles wrapping the element with
10005          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10006          * Usage:
10007          *<pre><code>
10008 // default: slide the element in from the top
10009 el.slideIn();
10010
10011 // custom: slide the element in from the right with a 2-second duration
10012 el.slideIn('r', { duration: 2 });
10013
10014 // common config options shown with default values
10015 el.slideIn('t', {
10016     easing: 'easeOut',
10017     duration: .5
10018 });
10019 </code></pre>
10020          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10021          * @param {Object} options (optional) Object literal with any of the Fx config options
10022          * @return {Roo.Element} The Element
10023          */
10024     slideIn : function(anchor, o){
10025         var el = this.getFxEl();
10026         o = o || {};
10027
10028         el.queueFx(o, function(){
10029
10030             anchor = anchor || "t";
10031
10032             // fix display to visibility
10033             this.fixDisplay();
10034
10035             // restore values after effect
10036             var r = this.getFxRestore();
10037             var b = this.getBox();
10038             // fixed size for slide
10039             this.setSize(b);
10040
10041             // wrap if needed
10042             var wrap = this.fxWrap(r.pos, o, "hidden");
10043
10044             var st = this.dom.style;
10045             st.visibility = "visible";
10046             st.position = "absolute";
10047
10048             // clear out temp styles after slide and unwrap
10049             var after = function(){
10050                 el.fxUnwrap(wrap, r.pos, o);
10051                 st.width = r.width;
10052                 st.height = r.height;
10053                 el.afterFx(o);
10054             };
10055             // time to calc the positions
10056             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10057
10058             switch(anchor.toLowerCase()){
10059                 case "t":
10060                     wrap.setSize(b.width, 0);
10061                     st.left = st.bottom = "0";
10062                     a = {height: bh};
10063                 break;
10064                 case "l":
10065                     wrap.setSize(0, b.height);
10066                     st.right = st.top = "0";
10067                     a = {width: bw};
10068                 break;
10069                 case "r":
10070                     wrap.setSize(0, b.height);
10071                     wrap.setX(b.right);
10072                     st.left = st.top = "0";
10073                     a = {width: bw, points: pt};
10074                 break;
10075                 case "b":
10076                     wrap.setSize(b.width, 0);
10077                     wrap.setY(b.bottom);
10078                     st.left = st.top = "0";
10079                     a = {height: bh, points: pt};
10080                 break;
10081                 case "tl":
10082                     wrap.setSize(0, 0);
10083                     st.right = st.bottom = "0";
10084                     a = {width: bw, height: bh};
10085                 break;
10086                 case "bl":
10087                     wrap.setSize(0, 0);
10088                     wrap.setY(b.y+b.height);
10089                     st.right = st.top = "0";
10090                     a = {width: bw, height: bh, points: pt};
10091                 break;
10092                 case "br":
10093                     wrap.setSize(0, 0);
10094                     wrap.setXY([b.right, b.bottom]);
10095                     st.left = st.top = "0";
10096                     a = {width: bw, height: bh, points: pt};
10097                 break;
10098                 case "tr":
10099                     wrap.setSize(0, 0);
10100                     wrap.setX(b.x+b.width);
10101                     st.left = st.bottom = "0";
10102                     a = {width: bw, height: bh, points: pt};
10103                 break;
10104             }
10105             this.dom.style.visibility = "visible";
10106             wrap.show();
10107
10108             arguments.callee.anim = wrap.fxanim(a,
10109                 o,
10110                 'motion',
10111                 .5,
10112                 'easeOut', after);
10113         });
10114         return this;
10115     },
10116     
10117         /**
10118          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10119          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10120          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10121          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10122          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10123          * Usage:
10124          *<pre><code>
10125 // default: slide the element out to the top
10126 el.slideOut();
10127
10128 // custom: slide the element out to the right with a 2-second duration
10129 el.slideOut('r', { duration: 2 });
10130
10131 // common config options shown with default values
10132 el.slideOut('t', {
10133     easing: 'easeOut',
10134     duration: .5,
10135     remove: false,
10136     useDisplay: false
10137 });
10138 </code></pre>
10139          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10140          * @param {Object} options (optional) Object literal with any of the Fx config options
10141          * @return {Roo.Element} The Element
10142          */
10143     slideOut : function(anchor, o){
10144         var el = this.getFxEl();
10145         o = o || {};
10146
10147         el.queueFx(o, function(){
10148
10149             anchor = anchor || "t";
10150
10151             // restore values after effect
10152             var r = this.getFxRestore();
10153             
10154             var b = this.getBox();
10155             // fixed size for slide
10156             this.setSize(b);
10157
10158             // wrap if needed
10159             var wrap = this.fxWrap(r.pos, o, "visible");
10160
10161             var st = this.dom.style;
10162             st.visibility = "visible";
10163             st.position = "absolute";
10164
10165             wrap.setSize(b);
10166
10167             var after = function(){
10168                 if(o.useDisplay){
10169                     el.setDisplayed(false);
10170                 }else{
10171                     el.hide();
10172                 }
10173
10174                 el.fxUnwrap(wrap, r.pos, o);
10175
10176                 st.width = r.width;
10177                 st.height = r.height;
10178
10179                 el.afterFx(o);
10180             };
10181
10182             var a, zero = {to: 0};
10183             switch(anchor.toLowerCase()){
10184                 case "t":
10185                     st.left = st.bottom = "0";
10186                     a = {height: zero};
10187                 break;
10188                 case "l":
10189                     st.right = st.top = "0";
10190                     a = {width: zero};
10191                 break;
10192                 case "r":
10193                     st.left = st.top = "0";
10194                     a = {width: zero, points: {to:[b.right, b.y]}};
10195                 break;
10196                 case "b":
10197                     st.left = st.top = "0";
10198                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10199                 break;
10200                 case "tl":
10201                     st.right = st.bottom = "0";
10202                     a = {width: zero, height: zero};
10203                 break;
10204                 case "bl":
10205                     st.right = st.top = "0";
10206                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10207                 break;
10208                 case "br":
10209                     st.left = st.top = "0";
10210                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10211                 break;
10212                 case "tr":
10213                     st.left = st.bottom = "0";
10214                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10215                 break;
10216             }
10217
10218             arguments.callee.anim = wrap.fxanim(a,
10219                 o,
10220                 'motion',
10221                 .5,
10222                 "easeOut", after);
10223         });
10224         return this;
10225     },
10226
10227         /**
10228          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10229          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10230          * The element must be removed from the DOM using the 'remove' config option if desired.
10231          * Usage:
10232          *<pre><code>
10233 // default
10234 el.puff();
10235
10236 // common config options shown with default values
10237 el.puff({
10238     easing: 'easeOut',
10239     duration: .5,
10240     remove: false,
10241     useDisplay: false
10242 });
10243 </code></pre>
10244          * @param {Object} options (optional) Object literal with any of the Fx config options
10245          * @return {Roo.Element} The Element
10246          */
10247     puff : function(o){
10248         var el = this.getFxEl();
10249         o = o || {};
10250
10251         el.queueFx(o, function(){
10252             this.clearOpacity();
10253             this.show();
10254
10255             // restore values after effect
10256             var r = this.getFxRestore();
10257             var st = this.dom.style;
10258
10259             var after = function(){
10260                 if(o.useDisplay){
10261                     el.setDisplayed(false);
10262                 }else{
10263                     el.hide();
10264                 }
10265
10266                 el.clearOpacity();
10267
10268                 el.setPositioning(r.pos);
10269                 st.width = r.width;
10270                 st.height = r.height;
10271                 st.fontSize = '';
10272                 el.afterFx(o);
10273             };
10274
10275             var width = this.getWidth();
10276             var height = this.getHeight();
10277
10278             arguments.callee.anim = this.fxanim({
10279                     width : {to: this.adjustWidth(width * 2)},
10280                     height : {to: this.adjustHeight(height * 2)},
10281                     points : {by: [-(width * .5), -(height * .5)]},
10282                     opacity : {to: 0},
10283                     fontSize: {to:200, unit: "%"}
10284                 },
10285                 o,
10286                 'motion',
10287                 .5,
10288                 "easeOut", after);
10289         });
10290         return this;
10291     },
10292
10293         /**
10294          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10295          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10296          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10297          * Usage:
10298          *<pre><code>
10299 // default
10300 el.switchOff();
10301
10302 // all config options shown with default values
10303 el.switchOff({
10304     easing: 'easeIn',
10305     duration: .3,
10306     remove: false,
10307     useDisplay: false
10308 });
10309 </code></pre>
10310          * @param {Object} options (optional) Object literal with any of the Fx config options
10311          * @return {Roo.Element} The Element
10312          */
10313     switchOff : function(o){
10314         var el = this.getFxEl();
10315         o = o || {};
10316
10317         el.queueFx(o, function(){
10318             this.clearOpacity();
10319             this.clip();
10320
10321             // restore values after effect
10322             var r = this.getFxRestore();
10323             var st = this.dom.style;
10324
10325             var after = function(){
10326                 if(o.useDisplay){
10327                     el.setDisplayed(false);
10328                 }else{
10329                     el.hide();
10330                 }
10331
10332                 el.clearOpacity();
10333                 el.setPositioning(r.pos);
10334                 st.width = r.width;
10335                 st.height = r.height;
10336
10337                 el.afterFx(o);
10338             };
10339
10340             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10341                 this.clearOpacity();
10342                 (function(){
10343                     this.fxanim({
10344                         height:{to:1},
10345                         points:{by:[0, this.getHeight() * .5]}
10346                     }, o, 'motion', 0.3, 'easeIn', after);
10347                 }).defer(100, this);
10348             });
10349         });
10350         return this;
10351     },
10352
10353     /**
10354      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10355      * changed using the "attr" config option) and then fading back to the original color. If no original
10356      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10357      * Usage:
10358 <pre><code>
10359 // default: highlight background to yellow
10360 el.highlight();
10361
10362 // custom: highlight foreground text to blue for 2 seconds
10363 el.highlight("0000ff", { attr: 'color', duration: 2 });
10364
10365 // common config options shown with default values
10366 el.highlight("ffff9c", {
10367     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10368     endColor: (current color) or "ffffff",
10369     easing: 'easeIn',
10370     duration: 1
10371 });
10372 </code></pre>
10373      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10374      * @param {Object} options (optional) Object literal with any of the Fx config options
10375      * @return {Roo.Element} The Element
10376      */ 
10377     highlight : function(color, o){
10378         var el = this.getFxEl();
10379         o = o || {};
10380
10381         el.queueFx(o, function(){
10382             color = color || "ffff9c";
10383             attr = o.attr || "backgroundColor";
10384
10385             this.clearOpacity();
10386             this.show();
10387
10388             var origColor = this.getColor(attr);
10389             var restoreColor = this.dom.style[attr];
10390             endColor = (o.endColor || origColor) || "ffffff";
10391
10392             var after = function(){
10393                 el.dom.style[attr] = restoreColor;
10394                 el.afterFx(o);
10395             };
10396
10397             var a = {};
10398             a[attr] = {from: color, to: endColor};
10399             arguments.callee.anim = this.fxanim(a,
10400                 o,
10401                 'color',
10402                 1,
10403                 'easeIn', after);
10404         });
10405         return this;
10406     },
10407
10408    /**
10409     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10410     * Usage:
10411 <pre><code>
10412 // default: a single light blue ripple
10413 el.frame();
10414
10415 // custom: 3 red ripples lasting 3 seconds total
10416 el.frame("ff0000", 3, { duration: 3 });
10417
10418 // common config options shown with default values
10419 el.frame("C3DAF9", 1, {
10420     duration: 1 //duration of entire animation (not each individual ripple)
10421     // Note: Easing is not configurable and will be ignored if included
10422 });
10423 </code></pre>
10424     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10425     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10426     * @param {Object} options (optional) Object literal with any of the Fx config options
10427     * @return {Roo.Element} The Element
10428     */
10429     frame : function(color, count, o){
10430         var el = this.getFxEl();
10431         o = o || {};
10432
10433         el.queueFx(o, function(){
10434             color = color || "#C3DAF9";
10435             if(color.length == 6){
10436                 color = "#" + color;
10437             }
10438             count = count || 1;
10439             duration = o.duration || 1;
10440             this.show();
10441
10442             var b = this.getBox();
10443             var animFn = function(){
10444                 var proxy = this.createProxy({
10445
10446                      style:{
10447                         visbility:"hidden",
10448                         position:"absolute",
10449                         "z-index":"35000", // yee haw
10450                         border:"0px solid " + color
10451                      }
10452                   });
10453                 var scale = Roo.isBorderBox ? 2 : 1;
10454                 proxy.animate({
10455                     top:{from:b.y, to:b.y - 20},
10456                     left:{from:b.x, to:b.x - 20},
10457                     borderWidth:{from:0, to:10},
10458                     opacity:{from:1, to:0},
10459                     height:{from:b.height, to:(b.height + (20*scale))},
10460                     width:{from:b.width, to:(b.width + (20*scale))}
10461                 }, duration, function(){
10462                     proxy.remove();
10463                 });
10464                 if(--count > 0){
10465                      animFn.defer((duration/2)*1000, this);
10466                 }else{
10467                     el.afterFx(o);
10468                 }
10469             };
10470             animFn.call(this);
10471         });
10472         return this;
10473     },
10474
10475    /**
10476     * Creates a pause before any subsequent queued effects begin.  If there are
10477     * no effects queued after the pause it will have no effect.
10478     * Usage:
10479 <pre><code>
10480 el.pause(1);
10481 </code></pre>
10482     * @param {Number} seconds The length of time to pause (in seconds)
10483     * @return {Roo.Element} The Element
10484     */
10485     pause : function(seconds){
10486         var el = this.getFxEl();
10487         var o = {};
10488
10489         el.queueFx(o, function(){
10490             setTimeout(function(){
10491                 el.afterFx(o);
10492             }, seconds * 1000);
10493         });
10494         return this;
10495     },
10496
10497    /**
10498     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10499     * using the "endOpacity" config option.
10500     * Usage:
10501 <pre><code>
10502 // default: fade in from opacity 0 to 100%
10503 el.fadeIn();
10504
10505 // custom: fade in from opacity 0 to 75% over 2 seconds
10506 el.fadeIn({ endOpacity: .75, duration: 2});
10507
10508 // common config options shown with default values
10509 el.fadeIn({
10510     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10511     easing: 'easeOut',
10512     duration: .5
10513 });
10514 </code></pre>
10515     * @param {Object} options (optional) Object literal with any of the Fx config options
10516     * @return {Roo.Element} The Element
10517     */
10518     fadeIn : function(o){
10519         var el = this.getFxEl();
10520         o = o || {};
10521         el.queueFx(o, function(){
10522             this.setOpacity(0);
10523             this.fixDisplay();
10524             this.dom.style.visibility = 'visible';
10525             var to = o.endOpacity || 1;
10526             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10527                 o, null, .5, "easeOut", function(){
10528                 if(to == 1){
10529                     this.clearOpacity();
10530                 }
10531                 el.afterFx(o);
10532             });
10533         });
10534         return this;
10535     },
10536
10537    /**
10538     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10539     * using the "endOpacity" config option.
10540     * Usage:
10541 <pre><code>
10542 // default: fade out from the element's current opacity to 0
10543 el.fadeOut();
10544
10545 // custom: fade out from the element's current opacity to 25% over 2 seconds
10546 el.fadeOut({ endOpacity: .25, duration: 2});
10547
10548 // common config options shown with default values
10549 el.fadeOut({
10550     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10551     easing: 'easeOut',
10552     duration: .5
10553     remove: false,
10554     useDisplay: false
10555 });
10556 </code></pre>
10557     * @param {Object} options (optional) Object literal with any of the Fx config options
10558     * @return {Roo.Element} The Element
10559     */
10560     fadeOut : function(o){
10561         var el = this.getFxEl();
10562         o = o || {};
10563         el.queueFx(o, function(){
10564             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10565                 o, null, .5, "easeOut", function(){
10566                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10567                      this.dom.style.display = "none";
10568                 }else{
10569                      this.dom.style.visibility = "hidden";
10570                 }
10571                 this.clearOpacity();
10572                 el.afterFx(o);
10573             });
10574         });
10575         return this;
10576     },
10577
10578    /**
10579     * Animates the transition of an element's dimensions from a starting height/width
10580     * to an ending height/width.
10581     * Usage:
10582 <pre><code>
10583 // change height and width to 100x100 pixels
10584 el.scale(100, 100);
10585
10586 // common config options shown with default values.  The height and width will default to
10587 // the element's existing values if passed as null.
10588 el.scale(
10589     [element's width],
10590     [element's height], {
10591     easing: 'easeOut',
10592     duration: .35
10593 });
10594 </code></pre>
10595     * @param {Number} width  The new width (pass undefined to keep the original width)
10596     * @param {Number} height  The new height (pass undefined to keep the original height)
10597     * @param {Object} options (optional) Object literal with any of the Fx config options
10598     * @return {Roo.Element} The Element
10599     */
10600     scale : function(w, h, o){
10601         this.shift(Roo.apply({}, o, {
10602             width: w,
10603             height: h
10604         }));
10605         return this;
10606     },
10607
10608    /**
10609     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10610     * Any of these properties not specified in the config object will not be changed.  This effect 
10611     * requires that at least one new dimension, position or opacity setting must be passed in on
10612     * the config object in order for the function to have any effect.
10613     * Usage:
10614 <pre><code>
10615 // slide the element horizontally to x position 200 while changing the height and opacity
10616 el.shift({ x: 200, height: 50, opacity: .8 });
10617
10618 // common config options shown with default values.
10619 el.shift({
10620     width: [element's width],
10621     height: [element's height],
10622     x: [element's x position],
10623     y: [element's y position],
10624     opacity: [element's opacity],
10625     easing: 'easeOut',
10626     duration: .35
10627 });
10628 </code></pre>
10629     * @param {Object} options  Object literal with any of the Fx config options
10630     * @return {Roo.Element} The Element
10631     */
10632     shift : function(o){
10633         var el = this.getFxEl();
10634         o = o || {};
10635         el.queueFx(o, function(){
10636             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10637             if(w !== undefined){
10638                 a.width = {to: this.adjustWidth(w)};
10639             }
10640             if(h !== undefined){
10641                 a.height = {to: this.adjustHeight(h)};
10642             }
10643             if(x !== undefined || y !== undefined){
10644                 a.points = {to: [
10645                     x !== undefined ? x : this.getX(),
10646                     y !== undefined ? y : this.getY()
10647                 ]};
10648             }
10649             if(op !== undefined){
10650                 a.opacity = {to: op};
10651             }
10652             if(o.xy !== undefined){
10653                 a.points = {to: o.xy};
10654             }
10655             arguments.callee.anim = this.fxanim(a,
10656                 o, 'motion', .35, "easeOut", function(){
10657                 el.afterFx(o);
10658             });
10659         });
10660         return this;
10661     },
10662
10663         /**
10664          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10665          * ending point of the effect.
10666          * Usage:
10667          *<pre><code>
10668 // default: slide the element downward while fading out
10669 el.ghost();
10670
10671 // custom: slide the element out to the right with a 2-second duration
10672 el.ghost('r', { duration: 2 });
10673
10674 // common config options shown with default values
10675 el.ghost('b', {
10676     easing: 'easeOut',
10677     duration: .5
10678     remove: false,
10679     useDisplay: false
10680 });
10681 </code></pre>
10682          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10683          * @param {Object} options (optional) Object literal with any of the Fx config options
10684          * @return {Roo.Element} The Element
10685          */
10686     ghost : function(anchor, o){
10687         var el = this.getFxEl();
10688         o = o || {};
10689
10690         el.queueFx(o, function(){
10691             anchor = anchor || "b";
10692
10693             // restore values after effect
10694             var r = this.getFxRestore();
10695             var w = this.getWidth(),
10696                 h = this.getHeight();
10697
10698             var st = this.dom.style;
10699
10700             var after = function(){
10701                 if(o.useDisplay){
10702                     el.setDisplayed(false);
10703                 }else{
10704                     el.hide();
10705                 }
10706
10707                 el.clearOpacity();
10708                 el.setPositioning(r.pos);
10709                 st.width = r.width;
10710                 st.height = r.height;
10711
10712                 el.afterFx(o);
10713             };
10714
10715             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10716             switch(anchor.toLowerCase()){
10717                 case "t":
10718                     pt.by = [0, -h];
10719                 break;
10720                 case "l":
10721                     pt.by = [-w, 0];
10722                 break;
10723                 case "r":
10724                     pt.by = [w, 0];
10725                 break;
10726                 case "b":
10727                     pt.by = [0, h];
10728                 break;
10729                 case "tl":
10730                     pt.by = [-w, -h];
10731                 break;
10732                 case "bl":
10733                     pt.by = [-w, h];
10734                 break;
10735                 case "br":
10736                     pt.by = [w, h];
10737                 break;
10738                 case "tr":
10739                     pt.by = [w, -h];
10740                 break;
10741             }
10742
10743             arguments.callee.anim = this.fxanim(a,
10744                 o,
10745                 'motion',
10746                 .5,
10747                 "easeOut", after);
10748         });
10749         return this;
10750     },
10751
10752         /**
10753          * Ensures that all effects queued after syncFx is called on the element are
10754          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10755          * @return {Roo.Element} The Element
10756          */
10757     syncFx : function(){
10758         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10759             block : false,
10760             concurrent : true,
10761             stopFx : false
10762         });
10763         return this;
10764     },
10765
10766         /**
10767          * Ensures that all effects queued after sequenceFx is called on the element are
10768          * run in sequence.  This is the opposite of {@link #syncFx}.
10769          * @return {Roo.Element} The Element
10770          */
10771     sequenceFx : function(){
10772         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10773             block : false,
10774             concurrent : false,
10775             stopFx : false
10776         });
10777         return this;
10778     },
10779
10780         /* @private */
10781     nextFx : function(){
10782         var ef = this.fxQueue[0];
10783         if(ef){
10784             ef.call(this);
10785         }
10786     },
10787
10788         /**
10789          * Returns true if the element has any effects actively running or queued, else returns false.
10790          * @return {Boolean} True if element has active effects, else false
10791          */
10792     hasActiveFx : function(){
10793         return this.fxQueue && this.fxQueue[0];
10794     },
10795
10796         /**
10797          * Stops any running effects and clears the element's internal effects queue if it contains
10798          * any additional effects that haven't started yet.
10799          * @return {Roo.Element} The Element
10800          */
10801     stopFx : function(){
10802         if(this.hasActiveFx()){
10803             var cur = this.fxQueue[0];
10804             if(cur && cur.anim && cur.anim.isAnimated()){
10805                 this.fxQueue = [cur]; // clear out others
10806                 cur.anim.stop(true);
10807             }
10808         }
10809         return this;
10810     },
10811
10812         /* @private */
10813     beforeFx : function(o){
10814         if(this.hasActiveFx() && !o.concurrent){
10815            if(o.stopFx){
10816                this.stopFx();
10817                return true;
10818            }
10819            return false;
10820         }
10821         return true;
10822     },
10823
10824         /**
10825          * Returns true if the element is currently blocking so that no other effect can be queued
10826          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10827          * used to ensure that an effect initiated by a user action runs to completion prior to the
10828          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10829          * @return {Boolean} True if blocking, else false
10830          */
10831     hasFxBlock : function(){
10832         var q = this.fxQueue;
10833         return q && q[0] && q[0].block;
10834     },
10835
10836         /* @private */
10837     queueFx : function(o, fn){
10838         if(!this.fxQueue){
10839             this.fxQueue = [];
10840         }
10841         if(!this.hasFxBlock()){
10842             Roo.applyIf(o, this.fxDefaults);
10843             if(!o.concurrent){
10844                 var run = this.beforeFx(o);
10845                 fn.block = o.block;
10846                 this.fxQueue.push(fn);
10847                 if(run){
10848                     this.nextFx();
10849                 }
10850             }else{
10851                 fn.call(this);
10852             }
10853         }
10854         return this;
10855     },
10856
10857         /* @private */
10858     fxWrap : function(pos, o, vis){
10859         var wrap;
10860         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10861             var wrapXY;
10862             if(o.fixPosition){
10863                 wrapXY = this.getXY();
10864             }
10865             var div = document.createElement("div");
10866             div.style.visibility = vis;
10867             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10868             wrap.setPositioning(pos);
10869             if(wrap.getStyle("position") == "static"){
10870                 wrap.position("relative");
10871             }
10872             this.clearPositioning('auto');
10873             wrap.clip();
10874             wrap.dom.appendChild(this.dom);
10875             if(wrapXY){
10876                 wrap.setXY(wrapXY);
10877             }
10878         }
10879         return wrap;
10880     },
10881
10882         /* @private */
10883     fxUnwrap : function(wrap, pos, o){
10884         this.clearPositioning();
10885         this.setPositioning(pos);
10886         if(!o.wrap){
10887             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10888             wrap.remove();
10889         }
10890     },
10891
10892         /* @private */
10893     getFxRestore : function(){
10894         var st = this.dom.style;
10895         return {pos: this.getPositioning(), width: st.width, height : st.height};
10896     },
10897
10898         /* @private */
10899     afterFx : function(o){
10900         if(o.afterStyle){
10901             this.applyStyles(o.afterStyle);
10902         }
10903         if(o.afterCls){
10904             this.addClass(o.afterCls);
10905         }
10906         if(o.remove === true){
10907             this.remove();
10908         }
10909         Roo.callback(o.callback, o.scope, [this]);
10910         if(!o.concurrent){
10911             this.fxQueue.shift();
10912             this.nextFx();
10913         }
10914     },
10915
10916         /* @private */
10917     getFxEl : function(){ // support for composite element fx
10918         return Roo.get(this.dom);
10919     },
10920
10921         /* @private */
10922     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10923         animType = animType || 'run';
10924         opt = opt || {};
10925         var anim = Roo.lib.Anim[animType](
10926             this.dom, args,
10927             (opt.duration || defaultDur) || .35,
10928             (opt.easing || defaultEase) || 'easeOut',
10929             function(){
10930                 Roo.callback(cb, this);
10931             },
10932             this
10933         );
10934         opt.anim = anim;
10935         return anim;
10936     }
10937 };
10938
10939 // backwords compat
10940 Roo.Fx.resize = Roo.Fx.scale;
10941
10942 //When included, Roo.Fx is automatically applied to Element so that all basic
10943 //effects are available directly via the Element API
10944 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10945  * Based on:
10946  * Ext JS Library 1.1.1
10947  * Copyright(c) 2006-2007, Ext JS, LLC.
10948  *
10949  * Originally Released Under LGPL - original licence link has changed is not relivant.
10950  *
10951  * Fork - LGPL
10952  * <script type="text/javascript">
10953  */
10954
10955
10956 /**
10957  * @class Roo.CompositeElement
10958  * Standard composite class. Creates a Roo.Element for every element in the collection.
10959  * <br><br>
10960  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10961  * actions will be performed on all the elements in this collection.</b>
10962  * <br><br>
10963  * All methods return <i>this</i> and can be chained.
10964  <pre><code>
10965  var els = Roo.select("#some-el div.some-class", true);
10966  // or select directly from an existing element
10967  var el = Roo.get('some-el');
10968  el.select('div.some-class', true);
10969
10970  els.setWidth(100); // all elements become 100 width
10971  els.hide(true); // all elements fade out and hide
10972  // or
10973  els.setWidth(100).hide(true);
10974  </code></pre>
10975  */
10976 Roo.CompositeElement = function(els){
10977     this.elements = [];
10978     this.addElements(els);
10979 };
10980 Roo.CompositeElement.prototype = {
10981     isComposite: true,
10982     addElements : function(els){
10983         if(!els) return this;
10984         if(typeof els == "string"){
10985             els = Roo.Element.selectorFunction(els);
10986         }
10987         var yels = this.elements;
10988         var index = yels.length-1;
10989         for(var i = 0, len = els.length; i < len; i++) {
10990                 yels[++index] = Roo.get(els[i]);
10991         }
10992         return this;
10993     },
10994
10995     /**
10996     * Clears this composite and adds the elements returned by the passed selector.
10997     * @param {String/Array} els A string CSS selector, an array of elements or an element
10998     * @return {CompositeElement} this
10999     */
11000     fill : function(els){
11001         this.elements = [];
11002         this.add(els);
11003         return this;
11004     },
11005
11006     /**
11007     * Filters this composite to only elements that match the passed selector.
11008     * @param {String} selector A string CSS selector
11009     * @param {Boolean} inverse return inverse filter (not matches)
11010     * @return {CompositeElement} this
11011     */
11012     filter : function(selector, inverse){
11013         var els = [];
11014         inverse = inverse || false;
11015         this.each(function(el){
11016             var match = inverse ? !el.is(selector) : el.is(selector);
11017             if(match){
11018                 els[els.length] = el.dom;
11019             }
11020         });
11021         this.fill(els);
11022         return this;
11023     },
11024
11025     invoke : function(fn, args){
11026         var els = this.elements;
11027         for(var i = 0, len = els.length; i < len; i++) {
11028                 Roo.Element.prototype[fn].apply(els[i], args);
11029         }
11030         return this;
11031     },
11032     /**
11033     * Adds elements to this composite.
11034     * @param {String/Array} els A string CSS selector, an array of elements or an element
11035     * @return {CompositeElement} this
11036     */
11037     add : function(els){
11038         if(typeof els == "string"){
11039             this.addElements(Roo.Element.selectorFunction(els));
11040         }else if(els.length !== undefined){
11041             this.addElements(els);
11042         }else{
11043             this.addElements([els]);
11044         }
11045         return this;
11046     },
11047     /**
11048     * Calls the passed function passing (el, this, index) for each element in this composite.
11049     * @param {Function} fn The function to call
11050     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11051     * @return {CompositeElement} this
11052     */
11053     each : function(fn, scope){
11054         var els = this.elements;
11055         for(var i = 0, len = els.length; i < len; i++){
11056             if(fn.call(scope || els[i], els[i], this, i) === false) {
11057                 break;
11058             }
11059         }
11060         return this;
11061     },
11062
11063     /**
11064      * Returns the Element object at the specified index
11065      * @param {Number} index
11066      * @return {Roo.Element}
11067      */
11068     item : function(index){
11069         return this.elements[index] || null;
11070     },
11071
11072     /**
11073      * Returns the first Element
11074      * @return {Roo.Element}
11075      */
11076     first : function(){
11077         return this.item(0);
11078     },
11079
11080     /**
11081      * Returns the last Element
11082      * @return {Roo.Element}
11083      */
11084     last : function(){
11085         return this.item(this.elements.length-1);
11086     },
11087
11088     /**
11089      * Returns the number of elements in this composite
11090      * @return Number
11091      */
11092     getCount : function(){
11093         return this.elements.length;
11094     },
11095
11096     /**
11097      * Returns true if this composite contains the passed element
11098      * @return Boolean
11099      */
11100     contains : function(el){
11101         return this.indexOf(el) !== -1;
11102     },
11103
11104     /**
11105      * Returns true if this composite contains the passed element
11106      * @return Boolean
11107      */
11108     indexOf : function(el){
11109         return this.elements.indexOf(Roo.get(el));
11110     },
11111
11112
11113     /**
11114     * Removes the specified element(s).
11115     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11116     * or an array of any of those.
11117     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11118     * @return {CompositeElement} this
11119     */
11120     removeElement : function(el, removeDom){
11121         if(el instanceof Array){
11122             for(var i = 0, len = el.length; i < len; i++){
11123                 this.removeElement(el[i]);
11124             }
11125             return this;
11126         }
11127         var index = typeof el == 'number' ? el : this.indexOf(el);
11128         if(index !== -1){
11129             if(removeDom){
11130                 var d = this.elements[index];
11131                 if(d.dom){
11132                     d.remove();
11133                 }else{
11134                     d.parentNode.removeChild(d);
11135                 }
11136             }
11137             this.elements.splice(index, 1);
11138         }
11139         return this;
11140     },
11141
11142     /**
11143     * Replaces the specified element with the passed element.
11144     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11145     * to replace.
11146     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11147     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11148     * @return {CompositeElement} this
11149     */
11150     replaceElement : function(el, replacement, domReplace){
11151         var index = typeof el == 'number' ? el : this.indexOf(el);
11152         if(index !== -1){
11153             if(domReplace){
11154                 this.elements[index].replaceWith(replacement);
11155             }else{
11156                 this.elements.splice(index, 1, Roo.get(replacement))
11157             }
11158         }
11159         return this;
11160     },
11161
11162     /**
11163      * Removes all elements.
11164      */
11165     clear : function(){
11166         this.elements = [];
11167     }
11168 };
11169 (function(){
11170     Roo.CompositeElement.createCall = function(proto, fnName){
11171         if(!proto[fnName]){
11172             proto[fnName] = function(){
11173                 return this.invoke(fnName, arguments);
11174             };
11175         }
11176     };
11177     for(var fnName in Roo.Element.prototype){
11178         if(typeof Roo.Element.prototype[fnName] == "function"){
11179             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11180         }
11181     };
11182 })();
11183 /*
11184  * Based on:
11185  * Ext JS Library 1.1.1
11186  * Copyright(c) 2006-2007, Ext JS, LLC.
11187  *
11188  * Originally Released Under LGPL - original licence link has changed is not relivant.
11189  *
11190  * Fork - LGPL
11191  * <script type="text/javascript">
11192  */
11193
11194 /**
11195  * @class Roo.CompositeElementLite
11196  * @extends Roo.CompositeElement
11197  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11198  <pre><code>
11199  var els = Roo.select("#some-el div.some-class");
11200  // or select directly from an existing element
11201  var el = Roo.get('some-el');
11202  el.select('div.some-class');
11203
11204  els.setWidth(100); // all elements become 100 width
11205  els.hide(true); // all elements fade out and hide
11206  // or
11207  els.setWidth(100).hide(true);
11208  </code></pre><br><br>
11209  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11210  * actions will be performed on all the elements in this collection.</b>
11211  */
11212 Roo.CompositeElementLite = function(els){
11213     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11214     this.el = new Roo.Element.Flyweight();
11215 };
11216 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11217     addElements : function(els){
11218         if(els){
11219             if(els instanceof Array){
11220                 this.elements = this.elements.concat(els);
11221             }else{
11222                 var yels = this.elements;
11223                 var index = yels.length-1;
11224                 for(var i = 0, len = els.length; i < len; i++) {
11225                     yels[++index] = els[i];
11226                 }
11227             }
11228         }
11229         return this;
11230     },
11231     invoke : function(fn, args){
11232         var els = this.elements;
11233         var el = this.el;
11234         for(var i = 0, len = els.length; i < len; i++) {
11235             el.dom = els[i];
11236                 Roo.Element.prototype[fn].apply(el, args);
11237         }
11238         return this;
11239     },
11240     /**
11241      * Returns a flyweight Element of the dom element object at the specified index
11242      * @param {Number} index
11243      * @return {Roo.Element}
11244      */
11245     item : function(index){
11246         if(!this.elements[index]){
11247             return null;
11248         }
11249         this.el.dom = this.elements[index];
11250         return this.el;
11251     },
11252
11253     // fixes scope with flyweight
11254     addListener : function(eventName, handler, scope, opt){
11255         var els = this.elements;
11256         for(var i = 0, len = els.length; i < len; i++) {
11257             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11258         }
11259         return this;
11260     },
11261
11262     /**
11263     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11264     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11265     * a reference to the dom node, use el.dom.</b>
11266     * @param {Function} fn The function to call
11267     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11268     * @return {CompositeElement} this
11269     */
11270     each : function(fn, scope){
11271         var els = this.elements;
11272         var el = this.el;
11273         for(var i = 0, len = els.length; i < len; i++){
11274             el.dom = els[i];
11275                 if(fn.call(scope || el, el, this, i) === false){
11276                 break;
11277             }
11278         }
11279         return this;
11280     },
11281
11282     indexOf : function(el){
11283         return this.elements.indexOf(Roo.getDom(el));
11284     },
11285
11286     replaceElement : function(el, replacement, domReplace){
11287         var index = typeof el == 'number' ? el : this.indexOf(el);
11288         if(index !== -1){
11289             replacement = Roo.getDom(replacement);
11290             if(domReplace){
11291                 var d = this.elements[index];
11292                 d.parentNode.insertBefore(replacement, d);
11293                 d.parentNode.removeChild(d);
11294             }
11295             this.elements.splice(index, 1, replacement);
11296         }
11297         return this;
11298     }
11299 });
11300 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11301
11302 /*
11303  * Based on:
11304  * Ext JS Library 1.1.1
11305  * Copyright(c) 2006-2007, Ext JS, LLC.
11306  *
11307  * Originally Released Under LGPL - original licence link has changed is not relivant.
11308  *
11309  * Fork - LGPL
11310  * <script type="text/javascript">
11311  */
11312
11313  
11314
11315 /**
11316  * @class Roo.data.Connection
11317  * @extends Roo.util.Observable
11318  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11319  * either to a configured URL, or to a URL specified at request time.<br><br>
11320  * <p>
11321  * Requests made by this class are asynchronous, and will return immediately. No data from
11322  * the server will be available to the statement immediately following the {@link #request} call.
11323  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11324  * <p>
11325  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11326  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11327  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11328  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11329  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11330  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11331  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11332  * standard DOM methods.
11333  * @constructor
11334  * @param {Object} config a configuration object.
11335  */
11336 Roo.data.Connection = function(config){
11337     Roo.apply(this, config);
11338     this.addEvents({
11339         /**
11340          * @event beforerequest
11341          * Fires before a network request is made to retrieve a data object.
11342          * @param {Connection} conn This Connection object.
11343          * @param {Object} options The options config object passed to the {@link #request} method.
11344          */
11345         "beforerequest" : true,
11346         /**
11347          * @event requestcomplete
11348          * Fires if the request was successfully completed.
11349          * @param {Connection} conn This Connection object.
11350          * @param {Object} response The XHR object containing the response data.
11351          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11352          * @param {Object} options The options config object passed to the {@link #request} method.
11353          */
11354         "requestcomplete" : true,
11355         /**
11356          * @event requestexception
11357          * Fires if an error HTTP status was returned from the server.
11358          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11359          * @param {Connection} conn This Connection object.
11360          * @param {Object} response The XHR object containing the response data.
11361          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11362          * @param {Object} options The options config object passed to the {@link #request} method.
11363          */
11364         "requestexception" : true
11365     });
11366     Roo.data.Connection.superclass.constructor.call(this);
11367 };
11368
11369 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11370     /**
11371      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11372      */
11373     /**
11374      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11375      * extra parameters to each request made by this object. (defaults to undefined)
11376      */
11377     /**
11378      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11379      *  to each request made by this object. (defaults to undefined)
11380      */
11381     /**
11382      * @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)
11383      */
11384     /**
11385      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11386      */
11387     timeout : 30000,
11388     /**
11389      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11390      * @type Boolean
11391      */
11392     autoAbort:false,
11393
11394     /**
11395      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11396      * @type Boolean
11397      */
11398     disableCaching: true,
11399
11400     /**
11401      * Sends an HTTP request to a remote server.
11402      * @param {Object} options An object which may contain the following properties:<ul>
11403      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11404      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11405      * request, a url encoded string or a function to call to get either.</li>
11406      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11407      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11408      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11409      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11410      * <li>options {Object} The parameter to the request call.</li>
11411      * <li>success {Boolean} True if the request succeeded.</li>
11412      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11413      * </ul></li>
11414      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11415      * The callback is passed the following parameters:<ul>
11416      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11417      * <li>options {Object} The parameter to the request call.</li>
11418      * </ul></li>
11419      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11420      * The callback is passed the following parameters:<ul>
11421      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11422      * <li>options {Object} The parameter to the request call.</li>
11423      * </ul></li>
11424      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11425      * for the callback function. Defaults to the browser window.</li>
11426      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11427      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11428      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11429      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11430      * params for the post data. Any params will be appended to the URL.</li>
11431      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11432      * </ul>
11433      * @return {Number} transactionId
11434      */
11435     request : function(o){
11436         if(this.fireEvent("beforerequest", this, o) !== false){
11437             var p = o.params;
11438
11439             if(typeof p == "function"){
11440                 p = p.call(o.scope||window, o);
11441             }
11442             if(typeof p == "object"){
11443                 p = Roo.urlEncode(o.params);
11444             }
11445             if(this.extraParams){
11446                 var extras = Roo.urlEncode(this.extraParams);
11447                 p = p ? (p + '&' + extras) : extras;
11448             }
11449
11450             var url = o.url || this.url;
11451             if(typeof url == 'function'){
11452                 url = url.call(o.scope||window, o);
11453             }
11454
11455             if(o.form){
11456                 var form = Roo.getDom(o.form);
11457                 url = url || form.action;
11458
11459                 var enctype = form.getAttribute("enctype");
11460                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11461                     return this.doFormUpload(o, p, url);
11462                 }
11463                 var f = Roo.lib.Ajax.serializeForm(form);
11464                 p = p ? (p + '&' + f) : f;
11465             }
11466
11467             var hs = o.headers;
11468             if(this.defaultHeaders){
11469                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11470                 if(!o.headers){
11471                     o.headers = hs;
11472                 }
11473             }
11474
11475             var cb = {
11476                 success: this.handleResponse,
11477                 failure: this.handleFailure,
11478                 scope: this,
11479                 argument: {options: o},
11480                 timeout : o.timeout || this.timeout
11481             };
11482
11483             var method = o.method||this.method||(p ? "POST" : "GET");
11484
11485             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11486                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11487             }
11488
11489             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11490                 if(o.autoAbort){
11491                     this.abort();
11492                 }
11493             }else if(this.autoAbort !== false){
11494                 this.abort();
11495             }
11496
11497             if((method == 'GET' && p) || o.xmlData){
11498                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11499                 p = '';
11500             }
11501             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11502             return this.transId;
11503         }else{
11504             Roo.callback(o.callback, o.scope, [o, null, null]);
11505             return null;
11506         }
11507     },
11508
11509     /**
11510      * Determine whether this object has a request outstanding.
11511      * @param {Number} transactionId (Optional) defaults to the last transaction
11512      * @return {Boolean} True if there is an outstanding request.
11513      */
11514     isLoading : function(transId){
11515         if(transId){
11516             return Roo.lib.Ajax.isCallInProgress(transId);
11517         }else{
11518             return this.transId ? true : false;
11519         }
11520     },
11521
11522     /**
11523      * Aborts any outstanding request.
11524      * @param {Number} transactionId (Optional) defaults to the last transaction
11525      */
11526     abort : function(transId){
11527         if(transId || this.isLoading()){
11528             Roo.lib.Ajax.abort(transId || this.transId);
11529         }
11530     },
11531
11532     // private
11533     handleResponse : function(response){
11534         this.transId = false;
11535         var options = response.argument.options;
11536         response.argument = options ? options.argument : null;
11537         this.fireEvent("requestcomplete", this, response, options);
11538         Roo.callback(options.success, options.scope, [response, options]);
11539         Roo.callback(options.callback, options.scope, [options, true, response]);
11540     },
11541
11542     // private
11543     handleFailure : function(response, e){
11544         this.transId = false;
11545         var options = response.argument.options;
11546         response.argument = options ? options.argument : null;
11547         this.fireEvent("requestexception", this, response, options, e);
11548         Roo.callback(options.failure, options.scope, [response, options]);
11549         Roo.callback(options.callback, options.scope, [options, false, response]);
11550     },
11551
11552     // private
11553     doFormUpload : function(o, ps, url){
11554         var id = Roo.id();
11555         var frame = document.createElement('iframe');
11556         frame.id = id;
11557         frame.name = id;
11558         frame.className = 'x-hidden';
11559         if(Roo.isIE){
11560             frame.src = Roo.SSL_SECURE_URL;
11561         }
11562         document.body.appendChild(frame);
11563
11564         if(Roo.isIE){
11565            document.frames[id].name = id;
11566         }
11567
11568         var form = Roo.getDom(o.form);
11569         form.target = id;
11570         form.method = 'POST';
11571         form.enctype = form.encoding = 'multipart/form-data';
11572         if(url){
11573             form.action = url;
11574         }
11575
11576         var hiddens, hd;
11577         if(ps){ // add dynamic params
11578             hiddens = [];
11579             ps = Roo.urlDecode(ps, false);
11580             for(var k in ps){
11581                 if(ps.hasOwnProperty(k)){
11582                     hd = document.createElement('input');
11583                     hd.type = 'hidden';
11584                     hd.name = k;
11585                     hd.value = ps[k];
11586                     form.appendChild(hd);
11587                     hiddens.push(hd);
11588                 }
11589             }
11590         }
11591
11592         function cb(){
11593             var r = {  // bogus response object
11594                 responseText : '',
11595                 responseXML : null
11596             };
11597
11598             r.argument = o ? o.argument : null;
11599
11600             try { //
11601                 var doc;
11602                 if(Roo.isIE){
11603                     doc = frame.contentWindow.document;
11604                 }else {
11605                     doc = (frame.contentDocument || window.frames[id].document);
11606                 }
11607                 if(doc && doc.body){
11608                     r.responseText = doc.body.innerHTML;
11609                 }
11610                 if(doc && doc.XMLDocument){
11611                     r.responseXML = doc.XMLDocument;
11612                 }else {
11613                     r.responseXML = doc;
11614                 }
11615             }
11616             catch(e) {
11617                 // ignore
11618             }
11619
11620             Roo.EventManager.removeListener(frame, 'load', cb, this);
11621
11622             this.fireEvent("requestcomplete", this, r, o);
11623             Roo.callback(o.success, o.scope, [r, o]);
11624             Roo.callback(o.callback, o.scope, [o, true, r]);
11625
11626             setTimeout(function(){document.body.removeChild(frame);}, 100);
11627         }
11628
11629         Roo.EventManager.on(frame, 'load', cb, this);
11630         form.submit();
11631
11632         if(hiddens){ // remove dynamic params
11633             for(var i = 0, len = hiddens.length; i < len; i++){
11634                 form.removeChild(hiddens[i]);
11635             }
11636         }
11637     }
11638 });
11639 /*
11640  * Based on:
11641  * Ext JS Library 1.1.1
11642  * Copyright(c) 2006-2007, Ext JS, LLC.
11643  *
11644  * Originally Released Under LGPL - original licence link has changed is not relivant.
11645  *
11646  * Fork - LGPL
11647  * <script type="text/javascript">
11648  */
11649  
11650 /**
11651  * Global Ajax request class.
11652  * 
11653  * @class Roo.Ajax
11654  * @extends Roo.data.Connection
11655  * @static
11656  * 
11657  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11658  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11659  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11660  * @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)
11661  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11662  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11663  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11664  */
11665 Roo.Ajax = new Roo.data.Connection({
11666     // fix up the docs
11667     /**
11668      * @scope Roo.Ajax
11669      * @type {Boolear} 
11670      */
11671     autoAbort : false,
11672
11673     /**
11674      * Serialize the passed form into a url encoded string
11675      * @scope Roo.Ajax
11676      * @param {String/HTMLElement} form
11677      * @return {String}
11678      */
11679     serializeForm : function(form){
11680         return Roo.lib.Ajax.serializeForm(form);
11681     }
11682 });/*
11683  * Based on:
11684  * Ext JS Library 1.1.1
11685  * Copyright(c) 2006-2007, Ext JS, LLC.
11686  *
11687  * Originally Released Under LGPL - original licence link has changed is not relivant.
11688  *
11689  * Fork - LGPL
11690  * <script type="text/javascript">
11691  */
11692
11693  
11694 /**
11695  * @class Roo.UpdateManager
11696  * @extends Roo.util.Observable
11697  * Provides AJAX-style update for Element object.<br><br>
11698  * Usage:<br>
11699  * <pre><code>
11700  * // Get it from a Roo.Element object
11701  * var el = Roo.get("foo");
11702  * var mgr = el.getUpdateManager();
11703  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11704  * ...
11705  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11706  * <br>
11707  * // or directly (returns the same UpdateManager instance)
11708  * var mgr = new Roo.UpdateManager("myElementId");
11709  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11710  * mgr.on("update", myFcnNeedsToKnow);
11711  * <br>
11712    // short handed call directly from the element object
11713    Roo.get("foo").load({
11714         url: "bar.php",
11715         scripts:true,
11716         params: "for=bar",
11717         text: "Loading Foo..."
11718    });
11719  * </code></pre>
11720  * @constructor
11721  * Create new UpdateManager directly.
11722  * @param {String/HTMLElement/Roo.Element} el The element to update
11723  * @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).
11724  */
11725 Roo.UpdateManager = function(el, forceNew){
11726     el = Roo.get(el);
11727     if(!forceNew && el.updateManager){
11728         return el.updateManager;
11729     }
11730     /**
11731      * The Element object
11732      * @type Roo.Element
11733      */
11734     this.el = el;
11735     /**
11736      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11737      * @type String
11738      */
11739     this.defaultUrl = null;
11740
11741     this.addEvents({
11742         /**
11743          * @event beforeupdate
11744          * Fired before an update is made, return false from your handler and the update is cancelled.
11745          * @param {Roo.Element} el
11746          * @param {String/Object/Function} url
11747          * @param {String/Object} params
11748          */
11749         "beforeupdate": true,
11750         /**
11751          * @event update
11752          * Fired after successful update is made.
11753          * @param {Roo.Element} el
11754          * @param {Object} oResponseObject The response Object
11755          */
11756         "update": true,
11757         /**
11758          * @event failure
11759          * Fired on update failure.
11760          * @param {Roo.Element} el
11761          * @param {Object} oResponseObject The response Object
11762          */
11763         "failure": true
11764     });
11765     var d = Roo.UpdateManager.defaults;
11766     /**
11767      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11768      * @type String
11769      */
11770     this.sslBlankUrl = d.sslBlankUrl;
11771     /**
11772      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11773      * @type Boolean
11774      */
11775     this.disableCaching = d.disableCaching;
11776     /**
11777      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11778      * @type String
11779      */
11780     this.indicatorText = d.indicatorText;
11781     /**
11782      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11783      * @type String
11784      */
11785     this.showLoadIndicator = d.showLoadIndicator;
11786     /**
11787      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11788      * @type Number
11789      */
11790     this.timeout = d.timeout;
11791
11792     /**
11793      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11794      * @type Boolean
11795      */
11796     this.loadScripts = d.loadScripts;
11797
11798     /**
11799      * Transaction object of current executing transaction
11800      */
11801     this.transaction = null;
11802
11803     /**
11804      * @private
11805      */
11806     this.autoRefreshProcId = null;
11807     /**
11808      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11809      * @type Function
11810      */
11811     this.refreshDelegate = this.refresh.createDelegate(this);
11812     /**
11813      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11814      * @type Function
11815      */
11816     this.updateDelegate = this.update.createDelegate(this);
11817     /**
11818      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11819      * @type Function
11820      */
11821     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11822     /**
11823      * @private
11824      */
11825     this.successDelegate = this.processSuccess.createDelegate(this);
11826     /**
11827      * @private
11828      */
11829     this.failureDelegate = this.processFailure.createDelegate(this);
11830
11831     if(!this.renderer){
11832      /**
11833       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11834       */
11835     this.renderer = new Roo.UpdateManager.BasicRenderer();
11836     }
11837     
11838     Roo.UpdateManager.superclass.constructor.call(this);
11839 };
11840
11841 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11842     /**
11843      * Get the Element this UpdateManager is bound to
11844      * @return {Roo.Element} The element
11845      */
11846     getEl : function(){
11847         return this.el;
11848     },
11849     /**
11850      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11851      * @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:
11852 <pre><code>
11853 um.update({<br/>
11854     url: "your-url.php",<br/>
11855     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11856     callback: yourFunction,<br/>
11857     scope: yourObject, //(optional scope)  <br/>
11858     discardUrl: false, <br/>
11859     nocache: false,<br/>
11860     text: "Loading...",<br/>
11861     timeout: 30,<br/>
11862     scripts: false<br/>
11863 });
11864 </code></pre>
11865      * The only required property is url. The optional properties nocache, text and scripts
11866      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11867      * @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}
11868      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11869      * @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.
11870      */
11871     update : function(url, params, callback, discardUrl){
11872         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11873             var method = this.method,
11874                 cfg;
11875             if(typeof url == "object"){ // must be config object
11876                 cfg = url;
11877                 url = cfg.url;
11878                 params = params || cfg.params;
11879                 callback = callback || cfg.callback;
11880                 discardUrl = discardUrl || cfg.discardUrl;
11881                 if(callback && cfg.scope){
11882                     callback = callback.createDelegate(cfg.scope);
11883                 }
11884                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11885                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11886                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11887                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11888                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11889             }
11890             this.showLoading();
11891             if(!discardUrl){
11892                 this.defaultUrl = url;
11893             }
11894             if(typeof url == "function"){
11895                 url = url.call(this);
11896             }
11897
11898             method = method || (params ? "POST" : "GET");
11899             if(method == "GET"){
11900                 url = this.prepareUrl(url);
11901             }
11902
11903             var o = Roo.apply(cfg ||{}, {
11904                 url : url,
11905                 params: params,
11906                 success: this.successDelegate,
11907                 failure: this.failureDelegate,
11908                 callback: undefined,
11909                 timeout: (this.timeout*1000),
11910                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11911             });
11912             Roo.log("updated manager called with timeout of " + o.timeout);
11913             this.transaction = Roo.Ajax.request(o);
11914         }
11915     },
11916
11917     /**
11918      * 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.
11919      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11920      * @param {String/HTMLElement} form The form Id or form element
11921      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11922      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11923      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11924      */
11925     formUpdate : function(form, url, reset, callback){
11926         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11927             if(typeof url == "function"){
11928                 url = url.call(this);
11929             }
11930             form = Roo.getDom(form);
11931             this.transaction = Roo.Ajax.request({
11932                 form: form,
11933                 url:url,
11934                 success: this.successDelegate,
11935                 failure: this.failureDelegate,
11936                 timeout: (this.timeout*1000),
11937                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11938             });
11939             this.showLoading.defer(1, this);
11940         }
11941     },
11942
11943     /**
11944      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11945      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11946      */
11947     refresh : function(callback){
11948         if(this.defaultUrl == null){
11949             return;
11950         }
11951         this.update(this.defaultUrl, null, callback, true);
11952     },
11953
11954     /**
11955      * Set this element to auto refresh.
11956      * @param {Number} interval How often to update (in seconds).
11957      * @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)
11958      * @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}
11959      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11960      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11961      */
11962     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11963         if(refreshNow){
11964             this.update(url || this.defaultUrl, params, callback, true);
11965         }
11966         if(this.autoRefreshProcId){
11967             clearInterval(this.autoRefreshProcId);
11968         }
11969         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11970     },
11971
11972     /**
11973      * Stop auto refresh on this element.
11974      */
11975      stopAutoRefresh : function(){
11976         if(this.autoRefreshProcId){
11977             clearInterval(this.autoRefreshProcId);
11978             delete this.autoRefreshProcId;
11979         }
11980     },
11981
11982     isAutoRefreshing : function(){
11983        return this.autoRefreshProcId ? true : false;
11984     },
11985     /**
11986      * Called to update the element to "Loading" state. Override to perform custom action.
11987      */
11988     showLoading : function(){
11989         if(this.showLoadIndicator){
11990             this.el.update(this.indicatorText);
11991         }
11992     },
11993
11994     /**
11995      * Adds unique parameter to query string if disableCaching = true
11996      * @private
11997      */
11998     prepareUrl : function(url){
11999         if(this.disableCaching){
12000             var append = "_dc=" + (new Date().getTime());
12001             if(url.indexOf("?") !== -1){
12002                 url += "&" + append;
12003             }else{
12004                 url += "?" + append;
12005             }
12006         }
12007         return url;
12008     },
12009
12010     /**
12011      * @private
12012      */
12013     processSuccess : function(response){
12014         this.transaction = null;
12015         if(response.argument.form && response.argument.reset){
12016             try{ // put in try/catch since some older FF releases had problems with this
12017                 response.argument.form.reset();
12018             }catch(e){}
12019         }
12020         if(this.loadScripts){
12021             this.renderer.render(this.el, response, this,
12022                 this.updateComplete.createDelegate(this, [response]));
12023         }else{
12024             this.renderer.render(this.el, response, this);
12025             this.updateComplete(response);
12026         }
12027     },
12028
12029     updateComplete : function(response){
12030         this.fireEvent("update", this.el, response);
12031         if(typeof response.argument.callback == "function"){
12032             response.argument.callback(this.el, true, response);
12033         }
12034     },
12035
12036     /**
12037      * @private
12038      */
12039     processFailure : function(response){
12040         this.transaction = null;
12041         this.fireEvent("failure", this.el, response);
12042         if(typeof response.argument.callback == "function"){
12043             response.argument.callback(this.el, false, response);
12044         }
12045     },
12046
12047     /**
12048      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12049      * @param {Object} renderer The object implementing the render() method
12050      */
12051     setRenderer : function(renderer){
12052         this.renderer = renderer;
12053     },
12054
12055     getRenderer : function(){
12056        return this.renderer;
12057     },
12058
12059     /**
12060      * Set the defaultUrl used for updates
12061      * @param {String/Function} defaultUrl The url or a function to call to get the url
12062      */
12063     setDefaultUrl : function(defaultUrl){
12064         this.defaultUrl = defaultUrl;
12065     },
12066
12067     /**
12068      * Aborts the executing transaction
12069      */
12070     abort : function(){
12071         if(this.transaction){
12072             Roo.Ajax.abort(this.transaction);
12073         }
12074     },
12075
12076     /**
12077      * Returns true if an update is in progress
12078      * @return {Boolean}
12079      */
12080     isUpdating : function(){
12081         if(this.transaction){
12082             return Roo.Ajax.isLoading(this.transaction);
12083         }
12084         return false;
12085     }
12086 });
12087
12088 /**
12089  * @class Roo.UpdateManager.defaults
12090  * @static (not really - but it helps the doc tool)
12091  * The defaults collection enables customizing the default properties of UpdateManager
12092  */
12093    Roo.UpdateManager.defaults = {
12094        /**
12095          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12096          * @type Number
12097          */
12098          timeout : 30,
12099
12100          /**
12101          * True to process scripts by default (Defaults to false).
12102          * @type Boolean
12103          */
12104         loadScripts : false,
12105
12106         /**
12107         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12108         * @type String
12109         */
12110         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12111         /**
12112          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12113          * @type Boolean
12114          */
12115         disableCaching : false,
12116         /**
12117          * Whether to show indicatorText when loading (Defaults to true).
12118          * @type Boolean
12119          */
12120         showLoadIndicator : true,
12121         /**
12122          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12123          * @type String
12124          */
12125         indicatorText : '<div class="loading-indicator">Loading...</div>'
12126    };
12127
12128 /**
12129  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12130  *Usage:
12131  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12132  * @param {String/HTMLElement/Roo.Element} el The element to update
12133  * @param {String} url The url
12134  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12135  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12136  * @static
12137  * @deprecated
12138  * @member Roo.UpdateManager
12139  */
12140 Roo.UpdateManager.updateElement = function(el, url, params, options){
12141     var um = Roo.get(el, true).getUpdateManager();
12142     Roo.apply(um, options);
12143     um.update(url, params, options ? options.callback : null);
12144 };
12145 // alias for backwards compat
12146 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12147 /**
12148  * @class Roo.UpdateManager.BasicRenderer
12149  * Default Content renderer. Updates the elements innerHTML with the responseText.
12150  */
12151 Roo.UpdateManager.BasicRenderer = function(){};
12152
12153 Roo.UpdateManager.BasicRenderer.prototype = {
12154     /**
12155      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12156      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12157      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12158      * @param {Roo.Element} el The element being rendered
12159      * @param {Object} response The YUI Connect response object
12160      * @param {UpdateManager} updateManager The calling update manager
12161      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12162      */
12163      render : function(el, response, updateManager, callback){
12164         el.update(response.responseText, updateManager.loadScripts, callback);
12165     }
12166 };
12167 /*
12168  * Based on:
12169  * Roo JS
12170  * (c)) Alan Knowles
12171  * Licence : LGPL
12172  */
12173
12174
12175 /**
12176  * @class Roo.DomTemplate
12177  * @extends Roo.Template
12178  * An effort at a dom based template engine..
12179  *
12180  * Similar to XTemplate, except it uses dom parsing to create the template..
12181  *
12182  * Supported features:
12183  *
12184  *  Tags:
12185
12186 <pre><code>
12187       {a_variable} - output encoded.
12188       {a_variable.format:("Y-m-d")} - call a method on the variable
12189       {a_variable:raw} - unencoded output
12190       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12191       {a_variable:this.method_on_template(...)} - call a method on the template object.
12192  
12193 </code></pre>
12194  *  The tpl tag:
12195 <pre><code>
12196         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12197         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12198         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12199         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12200   
12201 </code></pre>
12202  *      
12203  */
12204 Roo.DomTemplate = function()
12205 {
12206      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12207      if (this.html) {
12208         this.compile();
12209      }
12210 };
12211
12212
12213 Roo.extend(Roo.DomTemplate, Roo.Template, {
12214     /**
12215      * id counter for sub templates.
12216      */
12217     id : 0,
12218     /**
12219      * flag to indicate if dom parser is inside a pre,
12220      * it will strip whitespace if not.
12221      */
12222     inPre : false,
12223     
12224     /**
12225      * The various sub templates
12226      */
12227     tpls : false,
12228     
12229     
12230     
12231     /**
12232      *
12233      * basic tag replacing syntax
12234      * WORD:WORD()
12235      *
12236      * // you can fake an object call by doing this
12237      *  x.t:(test,tesT) 
12238      * 
12239      */
12240     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12241     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12242     
12243     iterChild : function (node, method) {
12244         
12245         var oldPre = this.inPre;
12246         if (node.tagName == 'PRE') {
12247             this.inPre = true;
12248         }
12249         for( var i = 0; i < node.childNodes.length; i++) {
12250             method.call(this, node.childNodes[i]);
12251         }
12252         this.inPre = oldPre;
12253     },
12254     
12255     
12256     
12257     /**
12258      * compile the template
12259      *
12260      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12261      *
12262      */
12263     compile: function()
12264     {
12265         var s = this.html;
12266         
12267         // covert the html into DOM...
12268         var doc = false;
12269         var div =false;
12270         try {
12271             doc = document.implementation.createHTMLDocument("");
12272             doc.documentElement.innerHTML =   this.html  ;
12273             div = doc.documentElement;
12274         } catch (e) {
12275             // old IE... - nasty -- it causes all sorts of issues.. with
12276             // images getting pulled from server..
12277             div = document.createElement('div');
12278             div.innerHTML = this.html;
12279         }
12280         //doc.documentElement.innerHTML = htmlBody
12281          
12282         
12283         
12284         this.tpls = [];
12285         var _t = this;
12286         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12287         
12288         var tpls = this.tpls;
12289         
12290         // create a top level template from the snippet..
12291         
12292         //Roo.log(div.innerHTML);
12293         
12294         var tpl = {
12295             uid : 'master',
12296             id : this.id++,
12297             attr : false,
12298             value : false,
12299             body : div.innerHTML,
12300             
12301             forCall : false,
12302             execCall : false,
12303             dom : div,
12304             isTop : true
12305             
12306         };
12307         tpls.unshift(tpl);
12308         
12309         
12310         // compile them...
12311         this.tpls = [];
12312         Roo.each(tpls, function(tp){
12313             this.compileTpl(tp);
12314             this.tpls[tp.id] = tp;
12315         }, this);
12316         
12317         this.master = tpls[0];
12318         return this;
12319         
12320         
12321     },
12322     
12323     compileNode : function(node, istop) {
12324         // test for
12325         //Roo.log(node);
12326         
12327         
12328         // skip anything not a tag..
12329         if (node.nodeType != 1) {
12330             if (node.nodeType == 3 && !this.inPre) {
12331                 // reduce white space..
12332                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12333                 
12334             }
12335             return;
12336         }
12337         
12338         var tpl = {
12339             uid : false,
12340             id : false,
12341             attr : false,
12342             value : false,
12343             body : '',
12344             
12345             forCall : false,
12346             execCall : false,
12347             dom : false,
12348             isTop : istop
12349             
12350             
12351         };
12352         
12353         
12354         switch(true) {
12355             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12356             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12357             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12358             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12359             // no default..
12360         }
12361         
12362         
12363         if (!tpl.attr) {
12364             // just itterate children..
12365             this.iterChild(node,this.compileNode);
12366             return;
12367         }
12368         tpl.uid = this.id++;
12369         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12370         node.removeAttribute('roo-'+ tpl.attr);
12371         if (tpl.attr != 'name') {
12372             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12373             node.parentNode.replaceChild(placeholder,  node);
12374         } else {
12375             
12376             var placeholder =  document.createElement('span');
12377             placeholder.className = 'roo-tpl-' + tpl.value;
12378             node.parentNode.replaceChild(placeholder,  node);
12379         }
12380         
12381         // parent now sees '{domtplXXXX}
12382         this.iterChild(node,this.compileNode);
12383         
12384         // we should now have node body...
12385         var div = document.createElement('div');
12386         div.appendChild(node);
12387         tpl.dom = node;
12388         // this has the unfortunate side effect of converting tagged attributes
12389         // eg. href="{...}" into %7C...%7D
12390         // this has been fixed by searching for those combo's although it's a bit hacky..
12391         
12392         
12393         tpl.body = div.innerHTML;
12394         
12395         
12396          
12397         tpl.id = tpl.uid;
12398         switch(tpl.attr) {
12399             case 'for' :
12400                 switch (tpl.value) {
12401                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12402                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12403                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12404                 }
12405                 break;
12406             
12407             case 'exec':
12408                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12409                 break;
12410             
12411             case 'if':     
12412                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12413                 break;
12414             
12415             case 'name':
12416                 tpl.id  = tpl.value; // replace non characters???
12417                 break;
12418             
12419         }
12420         
12421         
12422         this.tpls.push(tpl);
12423         
12424         
12425         
12426     },
12427     
12428     
12429     
12430     
12431     /**
12432      * Compile a segment of the template into a 'sub-template'
12433      *
12434      * 
12435      * 
12436      *
12437      */
12438     compileTpl : function(tpl)
12439     {
12440         var fm = Roo.util.Format;
12441         var useF = this.disableFormats !== true;
12442         
12443         var sep = Roo.isGecko ? "+\n" : ",\n";
12444         
12445         var undef = function(str) {
12446             Roo.debug && Roo.log("Property not found :"  + str);
12447             return '';
12448         };
12449           
12450         //Roo.log(tpl.body);
12451         
12452         
12453         
12454         var fn = function(m, lbrace, name, format, args)
12455         {
12456             //Roo.log("ARGS");
12457             //Roo.log(arguments);
12458             args = args ? args.replace(/\\'/g,"'") : args;
12459             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12460             if (typeof(format) == 'undefined') {
12461                 format =  'htmlEncode'; 
12462             }
12463             if (format == 'raw' ) {
12464                 format = false;
12465             }
12466             
12467             if(name.substr(0, 6) == 'domtpl'){
12468                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12469             }
12470             
12471             // build an array of options to determine if value is undefined..
12472             
12473             // basically get 'xxxx.yyyy' then do
12474             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12475             //    (function () { Roo.log("Property not found"); return ''; })() :
12476             //    ......
12477             
12478             var udef_ar = [];
12479             var lookfor = '';
12480             Roo.each(name.split('.'), function(st) {
12481                 lookfor += (lookfor.length ? '.': '') + st;
12482                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12483             });
12484             
12485             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12486             
12487             
12488             if(format && useF){
12489                 
12490                 args = args ? ',' + args : "";
12491                  
12492                 if(format.substr(0, 5) != "this."){
12493                     format = "fm." + format + '(';
12494                 }else{
12495                     format = 'this.call("'+ format.substr(5) + '", ';
12496                     args = ", values";
12497                 }
12498                 
12499                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12500             }
12501              
12502             if (args && args.length) {
12503                 // called with xxyx.yuu:(test,test)
12504                 // change to ()
12505                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12506             }
12507             // raw.. - :raw modifier..
12508             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12509             
12510         };
12511         var body;
12512         // branched to use + in gecko and [].join() in others
12513         if(Roo.isGecko){
12514             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12515                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12516                     "';};};";
12517         }else{
12518             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12519             body.push(tpl.body.replace(/(\r\n|\n)/g,
12520                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12521             body.push("'].join('');};};");
12522             body = body.join('');
12523         }
12524         
12525         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12526        
12527         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12528         eval(body);
12529         
12530         return this;
12531     },
12532      
12533     /**
12534      * same as applyTemplate, except it's done to one of the subTemplates
12535      * when using named templates, you can do:
12536      *
12537      * var str = pl.applySubTemplate('your-name', values);
12538      *
12539      * 
12540      * @param {Number} id of the template
12541      * @param {Object} values to apply to template
12542      * @param {Object} parent (normaly the instance of this object)
12543      */
12544     applySubTemplate : function(id, values, parent)
12545     {
12546         
12547         
12548         var t = this.tpls[id];
12549         
12550         
12551         try { 
12552             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12553                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12554                 return '';
12555             }
12556         } catch(e) {
12557             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12558             Roo.log(values);
12559           
12560             return '';
12561         }
12562         try { 
12563             
12564             if(t.execCall && t.execCall.call(this, values, parent)){
12565                 return '';
12566             }
12567         } catch(e) {
12568             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12569             Roo.log(values);
12570             return '';
12571         }
12572         
12573         try {
12574             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12575             parent = t.target ? values : parent;
12576             if(t.forCall && vs instanceof Array){
12577                 var buf = [];
12578                 for(var i = 0, len = vs.length; i < len; i++){
12579                     try {
12580                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12581                     } catch (e) {
12582                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12583                         Roo.log(e.body);
12584                         //Roo.log(t.compiled);
12585                         Roo.log(vs[i]);
12586                     }   
12587                 }
12588                 return buf.join('');
12589             }
12590         } catch (e) {
12591             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12592             Roo.log(values);
12593             return '';
12594         }
12595         try {
12596             return t.compiled.call(this, vs, parent);
12597         } catch (e) {
12598             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12599             Roo.log(e.body);
12600             //Roo.log(t.compiled);
12601             Roo.log(values);
12602             return '';
12603         }
12604     },
12605
12606    
12607
12608     applyTemplate : function(values){
12609         return this.master.compiled.call(this, values, {});
12610         //var s = this.subs;
12611     },
12612
12613     apply : function(){
12614         return this.applyTemplate.apply(this, arguments);
12615     }
12616
12617  });
12618
12619 Roo.DomTemplate.from = function(el){
12620     el = Roo.getDom(el);
12621     return new Roo.Domtemplate(el.value || el.innerHTML);
12622 };/*
12623  * Based on:
12624  * Ext JS Library 1.1.1
12625  * Copyright(c) 2006-2007, Ext JS, LLC.
12626  *
12627  * Originally Released Under LGPL - original licence link has changed is not relivant.
12628  *
12629  * Fork - LGPL
12630  * <script type="text/javascript">
12631  */
12632
12633 /**
12634  * @class Roo.util.DelayedTask
12635  * Provides a convenient method of performing setTimeout where a new
12636  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12637  * You can use this class to buffer
12638  * the keypress events for a certain number of milliseconds, and perform only if they stop
12639  * for that amount of time.
12640  * @constructor The parameters to this constructor serve as defaults and are not required.
12641  * @param {Function} fn (optional) The default function to timeout
12642  * @param {Object} scope (optional) The default scope of that timeout
12643  * @param {Array} args (optional) The default Array of arguments
12644  */
12645 Roo.util.DelayedTask = function(fn, scope, args){
12646     var id = null, d, t;
12647
12648     var call = function(){
12649         var now = new Date().getTime();
12650         if(now - t >= d){
12651             clearInterval(id);
12652             id = null;
12653             fn.apply(scope, args || []);
12654         }
12655     };
12656     /**
12657      * Cancels any pending timeout and queues a new one
12658      * @param {Number} delay The milliseconds to delay
12659      * @param {Function} newFn (optional) Overrides function passed to constructor
12660      * @param {Object} newScope (optional) Overrides scope passed to constructor
12661      * @param {Array} newArgs (optional) Overrides args passed to constructor
12662      */
12663     this.delay = function(delay, newFn, newScope, newArgs){
12664         if(id && delay != d){
12665             this.cancel();
12666         }
12667         d = delay;
12668         t = new Date().getTime();
12669         fn = newFn || fn;
12670         scope = newScope || scope;
12671         args = newArgs || args;
12672         if(!id){
12673             id = setInterval(call, d);
12674         }
12675     };
12676
12677     /**
12678      * Cancel the last queued timeout
12679      */
12680     this.cancel = function(){
12681         if(id){
12682             clearInterval(id);
12683             id = null;
12684         }
12685     };
12686 };/*
12687  * Based on:
12688  * Ext JS Library 1.1.1
12689  * Copyright(c) 2006-2007, Ext JS, LLC.
12690  *
12691  * Originally Released Under LGPL - original licence link has changed is not relivant.
12692  *
12693  * Fork - LGPL
12694  * <script type="text/javascript">
12695  */
12696  
12697  
12698 Roo.util.TaskRunner = function(interval){
12699     interval = interval || 10;
12700     var tasks = [], removeQueue = [];
12701     var id = 0;
12702     var running = false;
12703
12704     var stopThread = function(){
12705         running = false;
12706         clearInterval(id);
12707         id = 0;
12708     };
12709
12710     var startThread = function(){
12711         if(!running){
12712             running = true;
12713             id = setInterval(runTasks, interval);
12714         }
12715     };
12716
12717     var removeTask = function(task){
12718         removeQueue.push(task);
12719         if(task.onStop){
12720             task.onStop();
12721         }
12722     };
12723
12724     var runTasks = function(){
12725         if(removeQueue.length > 0){
12726             for(var i = 0, len = removeQueue.length; i < len; i++){
12727                 tasks.remove(removeQueue[i]);
12728             }
12729             removeQueue = [];
12730             if(tasks.length < 1){
12731                 stopThread();
12732                 return;
12733             }
12734         }
12735         var now = new Date().getTime();
12736         for(var i = 0, len = tasks.length; i < len; ++i){
12737             var t = tasks[i];
12738             var itime = now - t.taskRunTime;
12739             if(t.interval <= itime){
12740                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12741                 t.taskRunTime = now;
12742                 if(rt === false || t.taskRunCount === t.repeat){
12743                     removeTask(t);
12744                     return;
12745                 }
12746             }
12747             if(t.duration && t.duration <= (now - t.taskStartTime)){
12748                 removeTask(t);
12749             }
12750         }
12751     };
12752
12753     /**
12754      * Queues a new task.
12755      * @param {Object} task
12756      */
12757     this.start = function(task){
12758         tasks.push(task);
12759         task.taskStartTime = new Date().getTime();
12760         task.taskRunTime = 0;
12761         task.taskRunCount = 0;
12762         startThread();
12763         return task;
12764     };
12765
12766     this.stop = function(task){
12767         removeTask(task);
12768         return task;
12769     };
12770
12771     this.stopAll = function(){
12772         stopThread();
12773         for(var i = 0, len = tasks.length; i < len; i++){
12774             if(tasks[i].onStop){
12775                 tasks[i].onStop();
12776             }
12777         }
12778         tasks = [];
12779         removeQueue = [];
12780     };
12781 };
12782
12783 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12784  * Based on:
12785  * Ext JS Library 1.1.1
12786  * Copyright(c) 2006-2007, Ext JS, LLC.
12787  *
12788  * Originally Released Under LGPL - original licence link has changed is not relivant.
12789  *
12790  * Fork - LGPL
12791  * <script type="text/javascript">
12792  */
12793
12794  
12795 /**
12796  * @class Roo.util.MixedCollection
12797  * @extends Roo.util.Observable
12798  * A Collection class that maintains both numeric indexes and keys and exposes events.
12799  * @constructor
12800  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12801  * collection (defaults to false)
12802  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12803  * and return the key value for that item.  This is used when available to look up the key on items that
12804  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12805  * equivalent to providing an implementation for the {@link #getKey} method.
12806  */
12807 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12808     this.items = [];
12809     this.map = {};
12810     this.keys = [];
12811     this.length = 0;
12812     this.addEvents({
12813         /**
12814          * @event clear
12815          * Fires when the collection is cleared.
12816          */
12817         "clear" : true,
12818         /**
12819          * @event add
12820          * Fires when an item is added to the collection.
12821          * @param {Number} index The index at which the item was added.
12822          * @param {Object} o The item added.
12823          * @param {String} key The key associated with the added item.
12824          */
12825         "add" : true,
12826         /**
12827          * @event replace
12828          * Fires when an item is replaced in the collection.
12829          * @param {String} key he key associated with the new added.
12830          * @param {Object} old The item being replaced.
12831          * @param {Object} new The new item.
12832          */
12833         "replace" : true,
12834         /**
12835          * @event remove
12836          * Fires when an item is removed from the collection.
12837          * @param {Object} o The item being removed.
12838          * @param {String} key (optional) The key associated with the removed item.
12839          */
12840         "remove" : true,
12841         "sort" : true
12842     });
12843     this.allowFunctions = allowFunctions === true;
12844     if(keyFn){
12845         this.getKey = keyFn;
12846     }
12847     Roo.util.MixedCollection.superclass.constructor.call(this);
12848 };
12849
12850 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12851     allowFunctions : false,
12852     
12853 /**
12854  * Adds an item to the collection.
12855  * @param {String} key The key to associate with the item
12856  * @param {Object} o The item to add.
12857  * @return {Object} The item added.
12858  */
12859     add : function(key, o){
12860         if(arguments.length == 1){
12861             o = arguments[0];
12862             key = this.getKey(o);
12863         }
12864         if(typeof key == "undefined" || key === null){
12865             this.length++;
12866             this.items.push(o);
12867             this.keys.push(null);
12868         }else{
12869             var old = this.map[key];
12870             if(old){
12871                 return this.replace(key, o);
12872             }
12873             this.length++;
12874             this.items.push(o);
12875             this.map[key] = o;
12876             this.keys.push(key);
12877         }
12878         this.fireEvent("add", this.length-1, o, key);
12879         return o;
12880     },
12881        
12882 /**
12883   * MixedCollection has a generic way to fetch keys if you implement getKey.
12884 <pre><code>
12885 // normal way
12886 var mc = new Roo.util.MixedCollection();
12887 mc.add(someEl.dom.id, someEl);
12888 mc.add(otherEl.dom.id, otherEl);
12889 //and so on
12890
12891 // using getKey
12892 var mc = new Roo.util.MixedCollection();
12893 mc.getKey = function(el){
12894    return el.dom.id;
12895 };
12896 mc.add(someEl);
12897 mc.add(otherEl);
12898
12899 // or via the constructor
12900 var mc = new Roo.util.MixedCollection(false, function(el){
12901    return el.dom.id;
12902 });
12903 mc.add(someEl);
12904 mc.add(otherEl);
12905 </code></pre>
12906  * @param o {Object} The item for which to find the key.
12907  * @return {Object} The key for the passed item.
12908  */
12909     getKey : function(o){
12910          return o.id; 
12911     },
12912    
12913 /**
12914  * Replaces an item in the collection.
12915  * @param {String} key The key associated with the item to replace, or the item to replace.
12916  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12917  * @return {Object}  The new item.
12918  */
12919     replace : function(key, o){
12920         if(arguments.length == 1){
12921             o = arguments[0];
12922             key = this.getKey(o);
12923         }
12924         var old = this.item(key);
12925         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12926              return this.add(key, o);
12927         }
12928         var index = this.indexOfKey(key);
12929         this.items[index] = o;
12930         this.map[key] = o;
12931         this.fireEvent("replace", key, old, o);
12932         return o;
12933     },
12934    
12935 /**
12936  * Adds all elements of an Array or an Object to the collection.
12937  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12938  * an Array of values, each of which are added to the collection.
12939  */
12940     addAll : function(objs){
12941         if(arguments.length > 1 || objs instanceof Array){
12942             var args = arguments.length > 1 ? arguments : objs;
12943             for(var i = 0, len = args.length; i < len; i++){
12944                 this.add(args[i]);
12945             }
12946         }else{
12947             for(var key in objs){
12948                 if(this.allowFunctions || typeof objs[key] != "function"){
12949                     this.add(key, objs[key]);
12950                 }
12951             }
12952         }
12953     },
12954    
12955 /**
12956  * Executes the specified function once for every item in the collection, passing each
12957  * item as the first and only parameter. returning false from the function will stop the iteration.
12958  * @param {Function} fn The function to execute for each item.
12959  * @param {Object} scope (optional) The scope in which to execute the function.
12960  */
12961     each : function(fn, scope){
12962         var items = [].concat(this.items); // each safe for removal
12963         for(var i = 0, len = items.length; i < len; i++){
12964             if(fn.call(scope || items[i], items[i], i, len) === false){
12965                 break;
12966             }
12967         }
12968     },
12969    
12970 /**
12971  * Executes the specified function once for every key in the collection, passing each
12972  * key, and its associated item as the first two parameters.
12973  * @param {Function} fn The function to execute for each item.
12974  * @param {Object} scope (optional) The scope in which to execute the function.
12975  */
12976     eachKey : function(fn, scope){
12977         for(var i = 0, len = this.keys.length; i < len; i++){
12978             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12979         }
12980     },
12981    
12982 /**
12983  * Returns the first item in the collection which elicits a true return value from the
12984  * passed selection function.
12985  * @param {Function} fn The selection function to execute for each item.
12986  * @param {Object} scope (optional) The scope in which to execute the function.
12987  * @return {Object} The first item in the collection which returned true from the selection function.
12988  */
12989     find : function(fn, scope){
12990         for(var i = 0, len = this.items.length; i < len; i++){
12991             if(fn.call(scope || window, this.items[i], this.keys[i])){
12992                 return this.items[i];
12993             }
12994         }
12995         return null;
12996     },
12997    
12998 /**
12999  * Inserts an item at the specified index in the collection.
13000  * @param {Number} index The index to insert the item at.
13001  * @param {String} key The key to associate with the new item, or the item itself.
13002  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13003  * @return {Object} The item inserted.
13004  */
13005     insert : function(index, key, o){
13006         if(arguments.length == 2){
13007             o = arguments[1];
13008             key = this.getKey(o);
13009         }
13010         if(index >= this.length){
13011             return this.add(key, o);
13012         }
13013         this.length++;
13014         this.items.splice(index, 0, o);
13015         if(typeof key != "undefined" && key != null){
13016             this.map[key] = o;
13017         }
13018         this.keys.splice(index, 0, key);
13019         this.fireEvent("add", index, o, key);
13020         return o;
13021     },
13022    
13023 /**
13024  * Removed an item from the collection.
13025  * @param {Object} o The item to remove.
13026  * @return {Object} The item removed.
13027  */
13028     remove : function(o){
13029         return this.removeAt(this.indexOf(o));
13030     },
13031    
13032 /**
13033  * Remove an item from a specified index in the collection.
13034  * @param {Number} index The index within the collection of the item to remove.
13035  */
13036     removeAt : function(index){
13037         if(index < this.length && index >= 0){
13038             this.length--;
13039             var o = this.items[index];
13040             this.items.splice(index, 1);
13041             var key = this.keys[index];
13042             if(typeof key != "undefined"){
13043                 delete this.map[key];
13044             }
13045             this.keys.splice(index, 1);
13046             this.fireEvent("remove", o, key);
13047         }
13048     },
13049    
13050 /**
13051  * Removed an item associated with the passed key fom the collection.
13052  * @param {String} key The key of the item to remove.
13053  */
13054     removeKey : function(key){
13055         return this.removeAt(this.indexOfKey(key));
13056     },
13057    
13058 /**
13059  * Returns the number of items in the collection.
13060  * @return {Number} the number of items in the collection.
13061  */
13062     getCount : function(){
13063         return this.length; 
13064     },
13065    
13066 /**
13067  * Returns index within the collection of the passed Object.
13068  * @param {Object} o The item to find the index of.
13069  * @return {Number} index of the item.
13070  */
13071     indexOf : function(o){
13072         if(!this.items.indexOf){
13073             for(var i = 0, len = this.items.length; i < len; i++){
13074                 if(this.items[i] == o) return i;
13075             }
13076             return -1;
13077         }else{
13078             return this.items.indexOf(o);
13079         }
13080     },
13081    
13082 /**
13083  * Returns index within the collection of the passed key.
13084  * @param {String} key The key to find the index of.
13085  * @return {Number} index of the key.
13086  */
13087     indexOfKey : function(key){
13088         if(!this.keys.indexOf){
13089             for(var i = 0, len = this.keys.length; i < len; i++){
13090                 if(this.keys[i] == key) return i;
13091             }
13092             return -1;
13093         }else{
13094             return this.keys.indexOf(key);
13095         }
13096     },
13097    
13098 /**
13099  * Returns the item associated with the passed key OR index. Key has priority over index.
13100  * @param {String/Number} key The key or index of the item.
13101  * @return {Object} The item associated with the passed key.
13102  */
13103     item : function(key){
13104         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13105         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13106     },
13107     
13108 /**
13109  * Returns the item at the specified index.
13110  * @param {Number} index The index of the item.
13111  * @return {Object}
13112  */
13113     itemAt : function(index){
13114         return this.items[index];
13115     },
13116     
13117 /**
13118  * Returns the item associated with the passed key.
13119  * @param {String/Number} key The key of the item.
13120  * @return {Object} The item associated with the passed key.
13121  */
13122     key : function(key){
13123         return this.map[key];
13124     },
13125    
13126 /**
13127  * Returns true if the collection contains the passed Object as an item.
13128  * @param {Object} o  The Object to look for in the collection.
13129  * @return {Boolean} True if the collection contains the Object as an item.
13130  */
13131     contains : function(o){
13132         return this.indexOf(o) != -1;
13133     },
13134    
13135 /**
13136  * Returns true if the collection contains the passed Object as a key.
13137  * @param {String} key The key to look for in the collection.
13138  * @return {Boolean} True if the collection contains the Object as a key.
13139  */
13140     containsKey : function(key){
13141         return typeof this.map[key] != "undefined";
13142     },
13143    
13144 /**
13145  * Removes all items from the collection.
13146  */
13147     clear : function(){
13148         this.length = 0;
13149         this.items = [];
13150         this.keys = [];
13151         this.map = {};
13152         this.fireEvent("clear");
13153     },
13154    
13155 /**
13156  * Returns the first item in the collection.
13157  * @return {Object} the first item in the collection..
13158  */
13159     first : function(){
13160         return this.items[0]; 
13161     },
13162    
13163 /**
13164  * Returns the last item in the collection.
13165  * @return {Object} the last item in the collection..
13166  */
13167     last : function(){
13168         return this.items[this.length-1];   
13169     },
13170     
13171     _sort : function(property, dir, fn){
13172         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13173         fn = fn || function(a, b){
13174             return a-b;
13175         };
13176         var c = [], k = this.keys, items = this.items;
13177         for(var i = 0, len = items.length; i < len; i++){
13178             c[c.length] = {key: k[i], value: items[i], index: i};
13179         }
13180         c.sort(function(a, b){
13181             var v = fn(a[property], b[property]) * dsc;
13182             if(v == 0){
13183                 v = (a.index < b.index ? -1 : 1);
13184             }
13185             return v;
13186         });
13187         for(var i = 0, len = c.length; i < len; i++){
13188             items[i] = c[i].value;
13189             k[i] = c[i].key;
13190         }
13191         this.fireEvent("sort", this);
13192     },
13193     
13194     /**
13195      * Sorts this collection with the passed comparison function
13196      * @param {String} direction (optional) "ASC" or "DESC"
13197      * @param {Function} fn (optional) comparison function
13198      */
13199     sort : function(dir, fn){
13200         this._sort("value", dir, fn);
13201     },
13202     
13203     /**
13204      * Sorts this collection by keys
13205      * @param {String} direction (optional) "ASC" or "DESC"
13206      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13207      */
13208     keySort : function(dir, fn){
13209         this._sort("key", dir, fn || function(a, b){
13210             return String(a).toUpperCase()-String(b).toUpperCase();
13211         });
13212     },
13213     
13214     /**
13215      * Returns a range of items in this collection
13216      * @param {Number} startIndex (optional) defaults to 0
13217      * @param {Number} endIndex (optional) default to the last item
13218      * @return {Array} An array of items
13219      */
13220     getRange : function(start, end){
13221         var items = this.items;
13222         if(items.length < 1){
13223             return [];
13224         }
13225         start = start || 0;
13226         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13227         var r = [];
13228         if(start <= end){
13229             for(var i = start; i <= end; i++) {
13230                     r[r.length] = items[i];
13231             }
13232         }else{
13233             for(var i = start; i >= end; i--) {
13234                     r[r.length] = items[i];
13235             }
13236         }
13237         return r;
13238     },
13239         
13240     /**
13241      * Filter the <i>objects</i> in this collection by a specific property. 
13242      * Returns a new collection that has been filtered.
13243      * @param {String} property A property on your objects
13244      * @param {String/RegExp} value Either string that the property values 
13245      * should start with or a RegExp to test against the property
13246      * @return {MixedCollection} The new filtered collection
13247      */
13248     filter : function(property, value){
13249         if(!value.exec){ // not a regex
13250             value = String(value);
13251             if(value.length == 0){
13252                 return this.clone();
13253             }
13254             value = new RegExp("^" + Roo.escapeRe(value), "i");
13255         }
13256         return this.filterBy(function(o){
13257             return o && value.test(o[property]);
13258         });
13259         },
13260     
13261     /**
13262      * Filter by a function. * Returns a new collection that has been filtered.
13263      * The passed function will be called with each 
13264      * object in the collection. If the function returns true, the value is included 
13265      * otherwise it is filtered.
13266      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13267      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13268      * @return {MixedCollection} The new filtered collection
13269      */
13270     filterBy : function(fn, scope){
13271         var r = new Roo.util.MixedCollection();
13272         r.getKey = this.getKey;
13273         var k = this.keys, it = this.items;
13274         for(var i = 0, len = it.length; i < len; i++){
13275             if(fn.call(scope||this, it[i], k[i])){
13276                                 r.add(k[i], it[i]);
13277                         }
13278         }
13279         return r;
13280     },
13281     
13282     /**
13283      * Creates a duplicate of this collection
13284      * @return {MixedCollection}
13285      */
13286     clone : function(){
13287         var r = new Roo.util.MixedCollection();
13288         var k = this.keys, it = this.items;
13289         for(var i = 0, len = it.length; i < len; i++){
13290             r.add(k[i], it[i]);
13291         }
13292         r.getKey = this.getKey;
13293         return r;
13294     }
13295 });
13296 /**
13297  * Returns the item associated with the passed key or index.
13298  * @method
13299  * @param {String/Number} key The key or index of the item.
13300  * @return {Object} The item associated with the passed key.
13301  */
13302 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13303  * Based on:
13304  * Ext JS Library 1.1.1
13305  * Copyright(c) 2006-2007, Ext JS, LLC.
13306  *
13307  * Originally Released Under LGPL - original licence link has changed is not relivant.
13308  *
13309  * Fork - LGPL
13310  * <script type="text/javascript">
13311  */
13312 /**
13313  * @class Roo.util.JSON
13314  * Modified version of Douglas Crockford"s json.js that doesn"t
13315  * mess with the Object prototype 
13316  * http://www.json.org/js.html
13317  * @singleton
13318  */
13319 Roo.util.JSON = new (function(){
13320     var useHasOwn = {}.hasOwnProperty ? true : false;
13321     
13322     // crashes Safari in some instances
13323     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13324     
13325     var pad = function(n) {
13326         return n < 10 ? "0" + n : n;
13327     };
13328     
13329     var m = {
13330         "\b": '\\b',
13331         "\t": '\\t',
13332         "\n": '\\n',
13333         "\f": '\\f',
13334         "\r": '\\r',
13335         '"' : '\\"',
13336         "\\": '\\\\'
13337     };
13338
13339     var encodeString = function(s){
13340         if (/["\\\x00-\x1f]/.test(s)) {
13341             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13342                 var c = m[b];
13343                 if(c){
13344                     return c;
13345                 }
13346                 c = b.charCodeAt();
13347                 return "\\u00" +
13348                     Math.floor(c / 16).toString(16) +
13349                     (c % 16).toString(16);
13350             }) + '"';
13351         }
13352         return '"' + s + '"';
13353     };
13354     
13355     var encodeArray = function(o){
13356         var a = ["["], b, i, l = o.length, v;
13357             for (i = 0; i < l; i += 1) {
13358                 v = o[i];
13359                 switch (typeof v) {
13360                     case "undefined":
13361                     case "function":
13362                     case "unknown":
13363                         break;
13364                     default:
13365                         if (b) {
13366                             a.push(',');
13367                         }
13368                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13369                         b = true;
13370                 }
13371             }
13372             a.push("]");
13373             return a.join("");
13374     };
13375     
13376     var encodeDate = function(o){
13377         return '"' + o.getFullYear() + "-" +
13378                 pad(o.getMonth() + 1) + "-" +
13379                 pad(o.getDate()) + "T" +
13380                 pad(o.getHours()) + ":" +
13381                 pad(o.getMinutes()) + ":" +
13382                 pad(o.getSeconds()) + '"';
13383     };
13384     
13385     /**
13386      * Encodes an Object, Array or other value
13387      * @param {Mixed} o The variable to encode
13388      * @return {String} The JSON string
13389      */
13390     this.encode = function(o)
13391     {
13392         // should this be extended to fully wrap stringify..
13393         
13394         if(typeof o == "undefined" || o === null){
13395             return "null";
13396         }else if(o instanceof Array){
13397             return encodeArray(o);
13398         }else if(o instanceof Date){
13399             return encodeDate(o);
13400         }else if(typeof o == "string"){
13401             return encodeString(o);
13402         }else if(typeof o == "number"){
13403             return isFinite(o) ? String(o) : "null";
13404         }else if(typeof o == "boolean"){
13405             return String(o);
13406         }else {
13407             var a = ["{"], b, i, v;
13408             for (i in o) {
13409                 if(!useHasOwn || o.hasOwnProperty(i)) {
13410                     v = o[i];
13411                     switch (typeof v) {
13412                     case "undefined":
13413                     case "function":
13414                     case "unknown":
13415                         break;
13416                     default:
13417                         if(b){
13418                             a.push(',');
13419                         }
13420                         a.push(this.encode(i), ":",
13421                                 v === null ? "null" : this.encode(v));
13422                         b = true;
13423                     }
13424                 }
13425             }
13426             a.push("}");
13427             return a.join("");
13428         }
13429     };
13430     
13431     /**
13432      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13433      * @param {String} json The JSON string
13434      * @return {Object} The resulting object
13435      */
13436     this.decode = function(json){
13437         
13438         return  /** eval:var:json */ eval("(" + json + ')');
13439     };
13440 })();
13441 /** 
13442  * Shorthand for {@link Roo.util.JSON#encode}
13443  * @member Roo encode 
13444  * @method */
13445 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13446 /** 
13447  * Shorthand for {@link Roo.util.JSON#decode}
13448  * @member Roo decode 
13449  * @method */
13450 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13451 /*
13452  * Based on:
13453  * Ext JS Library 1.1.1
13454  * Copyright(c) 2006-2007, Ext JS, LLC.
13455  *
13456  * Originally Released Under LGPL - original licence link has changed is not relivant.
13457  *
13458  * Fork - LGPL
13459  * <script type="text/javascript">
13460  */
13461  
13462 /**
13463  * @class Roo.util.Format
13464  * Reusable data formatting functions
13465  * @singleton
13466  */
13467 Roo.util.Format = function(){
13468     var trimRe = /^\s+|\s+$/g;
13469     return {
13470         /**
13471          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13472          * @param {String} value The string to truncate
13473          * @param {Number} length The maximum length to allow before truncating
13474          * @return {String} The converted text
13475          */
13476         ellipsis : function(value, len){
13477             if(value && value.length > len){
13478                 return value.substr(0, len-3)+"...";
13479             }
13480             return value;
13481         },
13482
13483         /**
13484          * Checks a reference and converts it to empty string if it is undefined
13485          * @param {Mixed} value Reference to check
13486          * @return {Mixed} Empty string if converted, otherwise the original value
13487          */
13488         undef : function(value){
13489             return typeof value != "undefined" ? value : "";
13490         },
13491
13492         /**
13493          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13494          * @param {String} value The string to encode
13495          * @return {String} The encoded text
13496          */
13497         htmlEncode : function(value){
13498             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13499         },
13500
13501         /**
13502          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13503          * @param {String} value The string to decode
13504          * @return {String} The decoded text
13505          */
13506         htmlDecode : function(value){
13507             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13508         },
13509
13510         /**
13511          * Trims any whitespace from either side of a string
13512          * @param {String} value The text to trim
13513          * @return {String} The trimmed text
13514          */
13515         trim : function(value){
13516             return String(value).replace(trimRe, "");
13517         },
13518
13519         /**
13520          * Returns a substring from within an original string
13521          * @param {String} value The original text
13522          * @param {Number} start The start index of the substring
13523          * @param {Number} length The length of the substring
13524          * @return {String} The substring
13525          */
13526         substr : function(value, start, length){
13527             return String(value).substr(start, length);
13528         },
13529
13530         /**
13531          * Converts a string to all lower case letters
13532          * @param {String} value The text to convert
13533          * @return {String} The converted text
13534          */
13535         lowercase : function(value){
13536             return String(value).toLowerCase();
13537         },
13538
13539         /**
13540          * Converts a string to all upper case letters
13541          * @param {String} value The text to convert
13542          * @return {String} The converted text
13543          */
13544         uppercase : function(value){
13545             return String(value).toUpperCase();
13546         },
13547
13548         /**
13549          * Converts the first character only of a string to upper case
13550          * @param {String} value The text to convert
13551          * @return {String} The converted text
13552          */
13553         capitalize : function(value){
13554             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13555         },
13556
13557         // private
13558         call : function(value, fn){
13559             if(arguments.length > 2){
13560                 var args = Array.prototype.slice.call(arguments, 2);
13561                 args.unshift(value);
13562                  
13563                 return /** eval:var:value */  eval(fn).apply(window, args);
13564             }else{
13565                 /** eval:var:value */
13566                 return /** eval:var:value */ eval(fn).call(window, value);
13567             }
13568         },
13569
13570        
13571         /**
13572          * safer version of Math.toFixed..??/
13573          * @param {Number/String} value The numeric value to format
13574          * @param {Number/String} value Decimal places 
13575          * @return {String} The formatted currency string
13576          */
13577         toFixed : function(v, n)
13578         {
13579             // why not use to fixed - precision is buggered???
13580             if (!n) {
13581                 return Math.round(v-0);
13582             }
13583             var fact = Math.pow(10,n+1);
13584             v = (Math.round((v-0)*fact))/fact;
13585             var z = (''+fact).substring(2);
13586             if (v == Math.floor(v)) {
13587                 return Math.floor(v) + '.' + z;
13588             }
13589             
13590             // now just padd decimals..
13591             var ps = String(v).split('.');
13592             var fd = (ps[1] + z);
13593             var r = fd.substring(0,n); 
13594             var rm = fd.substring(n); 
13595             if (rm < 5) {
13596                 return ps[0] + '.' + r;
13597             }
13598             r*=1; // turn it into a number;
13599             r++;
13600             if (String(r).length != n) {
13601                 ps[0]*=1;
13602                 ps[0]++;
13603                 r = String(r).substring(1); // chop the end off.
13604             }
13605             
13606             return ps[0] + '.' + r;
13607              
13608         },
13609         
13610         /**
13611          * Format a number as US currency
13612          * @param {Number/String} value The numeric value to format
13613          * @return {String} The formatted currency string
13614          */
13615         usMoney : function(v){
13616             return '$' + Roo.util.Format.number(v);
13617         },
13618         
13619         /**
13620          * Format a number
13621          * eventually this should probably emulate php's number_format
13622          * @param {Number/String} value The numeric value to format
13623          * @param {Number} decimals number of decimal places
13624          * @return {String} The formatted currency string
13625          */
13626         number : function(v,decimals)
13627         {
13628             // multiply and round.
13629             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13630             var mul = Math.pow(10, decimals);
13631             var zero = String(mul).substring(1);
13632             v = (Math.round((v-0)*mul))/mul;
13633             
13634             // if it's '0' number.. then
13635             
13636             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13637             v = String(v);
13638             var ps = v.split('.');
13639             var whole = ps[0];
13640             
13641             
13642             var r = /(\d+)(\d{3})/;
13643             // add comma's
13644             while (r.test(whole)) {
13645                 whole = whole.replace(r, '$1' + ',' + '$2');
13646             }
13647             
13648             
13649             var sub = ps[1] ?
13650                     // has decimals..
13651                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13652                     // does not have decimals
13653                     (decimals ? ('.' + zero) : '');
13654             
13655             
13656             return whole + sub ;
13657         },
13658         
13659         /**
13660          * Parse a value into a formatted date using the specified format pattern.
13661          * @param {Mixed} value The value to format
13662          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13663          * @return {String} The formatted date string
13664          */
13665         date : function(v, format){
13666             if(!v){
13667                 return "";
13668             }
13669             if(!(v instanceof Date)){
13670                 v = new Date(Date.parse(v));
13671             }
13672             return v.dateFormat(format || Roo.util.Format.defaults.date);
13673         },
13674
13675         /**
13676          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13677          * @param {String} format Any valid date format string
13678          * @return {Function} The date formatting function
13679          */
13680         dateRenderer : function(format){
13681             return function(v){
13682                 return Roo.util.Format.date(v, format);  
13683             };
13684         },
13685
13686         // private
13687         stripTagsRE : /<\/?[^>]+>/gi,
13688         
13689         /**
13690          * Strips all HTML tags
13691          * @param {Mixed} value The text from which to strip tags
13692          * @return {String} The stripped text
13693          */
13694         stripTags : function(v){
13695             return !v ? v : String(v).replace(this.stripTagsRE, "");
13696         }
13697     };
13698 }();
13699 Roo.util.Format.defaults = {
13700     date : 'd/M/Y'
13701 };/*
13702  * Based on:
13703  * Ext JS Library 1.1.1
13704  * Copyright(c) 2006-2007, Ext JS, LLC.
13705  *
13706  * Originally Released Under LGPL - original licence link has changed is not relivant.
13707  *
13708  * Fork - LGPL
13709  * <script type="text/javascript">
13710  */
13711
13712
13713  
13714
13715 /**
13716  * @class Roo.MasterTemplate
13717  * @extends Roo.Template
13718  * Provides a template that can have child templates. The syntax is:
13719 <pre><code>
13720 var t = new Roo.MasterTemplate(
13721         '&lt;select name="{name}"&gt;',
13722                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13723         '&lt;/select&gt;'
13724 );
13725 t.add('options', {value: 'foo', text: 'bar'});
13726 // or you can add multiple child elements in one shot
13727 t.addAll('options', [
13728     {value: 'foo', text: 'bar'},
13729     {value: 'foo2', text: 'bar2'},
13730     {value: 'foo3', text: 'bar3'}
13731 ]);
13732 // then append, applying the master template values
13733 t.append('my-form', {name: 'my-select'});
13734 </code></pre>
13735 * A name attribute for the child template is not required if you have only one child
13736 * template or you want to refer to them by index.
13737  */
13738 Roo.MasterTemplate = function(){
13739     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13740     this.originalHtml = this.html;
13741     var st = {};
13742     var m, re = this.subTemplateRe;
13743     re.lastIndex = 0;
13744     var subIndex = 0;
13745     while(m = re.exec(this.html)){
13746         var name = m[1], content = m[2];
13747         st[subIndex] = {
13748             name: name,
13749             index: subIndex,
13750             buffer: [],
13751             tpl : new Roo.Template(content)
13752         };
13753         if(name){
13754             st[name] = st[subIndex];
13755         }
13756         st[subIndex].tpl.compile();
13757         st[subIndex].tpl.call = this.call.createDelegate(this);
13758         subIndex++;
13759     }
13760     this.subCount = subIndex;
13761     this.subs = st;
13762 };
13763 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13764     /**
13765     * The regular expression used to match sub templates
13766     * @type RegExp
13767     * @property
13768     */
13769     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13770
13771     /**
13772      * Applies the passed values to a child template.
13773      * @param {String/Number} name (optional) The name or index of the child template
13774      * @param {Array/Object} values The values to be applied to the template
13775      * @return {MasterTemplate} this
13776      */
13777      add : function(name, values){
13778         if(arguments.length == 1){
13779             values = arguments[0];
13780             name = 0;
13781         }
13782         var s = this.subs[name];
13783         s.buffer[s.buffer.length] = s.tpl.apply(values);
13784         return this;
13785     },
13786
13787     /**
13788      * Applies all the passed values to a child template.
13789      * @param {String/Number} name (optional) The name or index of the child template
13790      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13791      * @param {Boolean} reset (optional) True to reset the template first
13792      * @return {MasterTemplate} this
13793      */
13794     fill : function(name, values, reset){
13795         var a = arguments;
13796         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13797             values = a[0];
13798             name = 0;
13799             reset = a[1];
13800         }
13801         if(reset){
13802             this.reset();
13803         }
13804         for(var i = 0, len = values.length; i < len; i++){
13805             this.add(name, values[i]);
13806         }
13807         return this;
13808     },
13809
13810     /**
13811      * Resets the template for reuse
13812      * @return {MasterTemplate} this
13813      */
13814      reset : function(){
13815         var s = this.subs;
13816         for(var i = 0; i < this.subCount; i++){
13817             s[i].buffer = [];
13818         }
13819         return this;
13820     },
13821
13822     applyTemplate : function(values){
13823         var s = this.subs;
13824         var replaceIndex = -1;
13825         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13826             return s[++replaceIndex].buffer.join("");
13827         });
13828         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13829     },
13830
13831     apply : function(){
13832         return this.applyTemplate.apply(this, arguments);
13833     },
13834
13835     compile : function(){return this;}
13836 });
13837
13838 /**
13839  * Alias for fill().
13840  * @method
13841  */
13842 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13843  /**
13844  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13845  * var tpl = Roo.MasterTemplate.from('element-id');
13846  * @param {String/HTMLElement} el
13847  * @param {Object} config
13848  * @static
13849  */
13850 Roo.MasterTemplate.from = function(el, config){
13851     el = Roo.getDom(el);
13852     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13853 };/*
13854  * Based on:
13855  * Ext JS Library 1.1.1
13856  * Copyright(c) 2006-2007, Ext JS, LLC.
13857  *
13858  * Originally Released Under LGPL - original licence link has changed is not relivant.
13859  *
13860  * Fork - LGPL
13861  * <script type="text/javascript">
13862  */
13863
13864  
13865 /**
13866  * @class Roo.util.CSS
13867  * Utility class for manipulating CSS rules
13868  * @singleton
13869  */
13870 Roo.util.CSS = function(){
13871         var rules = null;
13872         var doc = document;
13873
13874     var camelRe = /(-[a-z])/gi;
13875     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13876
13877    return {
13878    /**
13879     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13880     * tag and appended to the HEAD of the document.
13881     * @param {String|Object} cssText The text containing the css rules
13882     * @param {String} id An id to add to the stylesheet for later removal
13883     * @return {StyleSheet}
13884     */
13885     createStyleSheet : function(cssText, id){
13886         var ss;
13887         var head = doc.getElementsByTagName("head")[0];
13888         var nrules = doc.createElement("style");
13889         nrules.setAttribute("type", "text/css");
13890         if(id){
13891             nrules.setAttribute("id", id);
13892         }
13893         if (typeof(cssText) != 'string') {
13894             // support object maps..
13895             // not sure if this a good idea.. 
13896             // perhaps it should be merged with the general css handling
13897             // and handle js style props.
13898             var cssTextNew = [];
13899             for(var n in cssText) {
13900                 var citems = [];
13901                 for(var k in cssText[n]) {
13902                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13903                 }
13904                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13905                 
13906             }
13907             cssText = cssTextNew.join("\n");
13908             
13909         }
13910        
13911        
13912        if(Roo.isIE){
13913            head.appendChild(nrules);
13914            ss = nrules.styleSheet;
13915            ss.cssText = cssText;
13916        }else{
13917            try{
13918                 nrules.appendChild(doc.createTextNode(cssText));
13919            }catch(e){
13920                nrules.cssText = cssText; 
13921            }
13922            head.appendChild(nrules);
13923            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13924        }
13925        this.cacheStyleSheet(ss);
13926        return ss;
13927    },
13928
13929    /**
13930     * Removes a style or link tag by id
13931     * @param {String} id The id of the tag
13932     */
13933    removeStyleSheet : function(id){
13934        var existing = doc.getElementById(id);
13935        if(existing){
13936            existing.parentNode.removeChild(existing);
13937        }
13938    },
13939
13940    /**
13941     * Dynamically swaps an existing stylesheet reference for a new one
13942     * @param {String} id The id of an existing link tag to remove
13943     * @param {String} url The href of the new stylesheet to include
13944     */
13945    swapStyleSheet : function(id, url){
13946        this.removeStyleSheet(id);
13947        var ss = doc.createElement("link");
13948        ss.setAttribute("rel", "stylesheet");
13949        ss.setAttribute("type", "text/css");
13950        ss.setAttribute("id", id);
13951        ss.setAttribute("href", url);
13952        doc.getElementsByTagName("head")[0].appendChild(ss);
13953    },
13954    
13955    /**
13956     * Refresh the rule cache if you have dynamically added stylesheets
13957     * @return {Object} An object (hash) of rules indexed by selector
13958     */
13959    refreshCache : function(){
13960        return this.getRules(true);
13961    },
13962
13963    // private
13964    cacheStyleSheet : function(stylesheet){
13965        if(!rules){
13966            rules = {};
13967        }
13968        try{// try catch for cross domain access issue
13969            var ssRules = stylesheet.cssRules || stylesheet.rules;
13970            for(var j = ssRules.length-1; j >= 0; --j){
13971                rules[ssRules[j].selectorText] = ssRules[j];
13972            }
13973        }catch(e){}
13974    },
13975    
13976    /**
13977     * Gets all css rules for the document
13978     * @param {Boolean} refreshCache true to refresh the internal cache
13979     * @return {Object} An object (hash) of rules indexed by selector
13980     */
13981    getRules : function(refreshCache){
13982                 if(rules == null || refreshCache){
13983                         rules = {};
13984                         var ds = doc.styleSheets;
13985                         for(var i =0, len = ds.length; i < len; i++){
13986                             try{
13987                         this.cacheStyleSheet(ds[i]);
13988                     }catch(e){} 
13989                 }
13990                 }
13991                 return rules;
13992         },
13993         
13994         /**
13995     * Gets an an individual CSS rule by selector(s)
13996     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13997     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13998     * @return {CSSRule} The CSS rule or null if one is not found
13999     */
14000    getRule : function(selector, refreshCache){
14001                 var rs = this.getRules(refreshCache);
14002                 if(!(selector instanceof Array)){
14003                     return rs[selector];
14004                 }
14005                 for(var i = 0; i < selector.length; i++){
14006                         if(rs[selector[i]]){
14007                                 return rs[selector[i]];
14008                         }
14009                 }
14010                 return null;
14011         },
14012         
14013         
14014         /**
14015     * Updates a rule property
14016     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14017     * @param {String} property The css property
14018     * @param {String} value The new value for the property
14019     * @return {Boolean} true If a rule was found and updated
14020     */
14021    updateRule : function(selector, property, value){
14022                 if(!(selector instanceof Array)){
14023                         var rule = this.getRule(selector);
14024                         if(rule){
14025                                 rule.style[property.replace(camelRe, camelFn)] = value;
14026                                 return true;
14027                         }
14028                 }else{
14029                         for(var i = 0; i < selector.length; i++){
14030                                 if(this.updateRule(selector[i], property, value)){
14031                                         return true;
14032                                 }
14033                         }
14034                 }
14035                 return false;
14036         }
14037    };   
14038 }();/*
14039  * Based on:
14040  * Ext JS Library 1.1.1
14041  * Copyright(c) 2006-2007, Ext JS, LLC.
14042  *
14043  * Originally Released Under LGPL - original licence link has changed is not relivant.
14044  *
14045  * Fork - LGPL
14046  * <script type="text/javascript">
14047  */
14048
14049  
14050
14051 /**
14052  * @class Roo.util.ClickRepeater
14053  * @extends Roo.util.Observable
14054  * 
14055  * A wrapper class which can be applied to any element. Fires a "click" event while the
14056  * mouse is pressed. The interval between firings may be specified in the config but
14057  * defaults to 10 milliseconds.
14058  * 
14059  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14060  * 
14061  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14062  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14063  * Similar to an autorepeat key delay.
14064  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14065  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14066  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14067  *           "interval" and "delay" are ignored. "immediate" is honored.
14068  * @cfg {Boolean} preventDefault True to prevent the default click event
14069  * @cfg {Boolean} stopDefault True to stop the default click event
14070  * 
14071  * @history
14072  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14073  *     2007-02-02 jvs Renamed to ClickRepeater
14074  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14075  *
14076  *  @constructor
14077  * @param {String/HTMLElement/Element} el The element to listen on
14078  * @param {Object} config
14079  **/
14080 Roo.util.ClickRepeater = function(el, config)
14081 {
14082     this.el = Roo.get(el);
14083     this.el.unselectable();
14084
14085     Roo.apply(this, config);
14086
14087     this.addEvents({
14088     /**
14089      * @event mousedown
14090      * Fires when the mouse button is depressed.
14091      * @param {Roo.util.ClickRepeater} this
14092      */
14093         "mousedown" : true,
14094     /**
14095      * @event click
14096      * Fires on a specified interval during the time the element is pressed.
14097      * @param {Roo.util.ClickRepeater} this
14098      */
14099         "click" : true,
14100     /**
14101      * @event mouseup
14102      * Fires when the mouse key is released.
14103      * @param {Roo.util.ClickRepeater} this
14104      */
14105         "mouseup" : true
14106     });
14107
14108     this.el.on("mousedown", this.handleMouseDown, this);
14109     if(this.preventDefault || this.stopDefault){
14110         this.el.on("click", function(e){
14111             if(this.preventDefault){
14112                 e.preventDefault();
14113             }
14114             if(this.stopDefault){
14115                 e.stopEvent();
14116             }
14117         }, this);
14118     }
14119
14120     // allow inline handler
14121     if(this.handler){
14122         this.on("click", this.handler,  this.scope || this);
14123     }
14124
14125     Roo.util.ClickRepeater.superclass.constructor.call(this);
14126 };
14127
14128 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14129     interval : 20,
14130     delay: 250,
14131     preventDefault : true,
14132     stopDefault : false,
14133     timer : 0,
14134
14135     // private
14136     handleMouseDown : function(){
14137         clearTimeout(this.timer);
14138         this.el.blur();
14139         if(this.pressClass){
14140             this.el.addClass(this.pressClass);
14141         }
14142         this.mousedownTime = new Date();
14143
14144         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14145         this.el.on("mouseout", this.handleMouseOut, this);
14146
14147         this.fireEvent("mousedown", this);
14148         this.fireEvent("click", this);
14149         
14150         this.timer = this.click.defer(this.delay || this.interval, this);
14151     },
14152
14153     // private
14154     click : function(){
14155         this.fireEvent("click", this);
14156         this.timer = this.click.defer(this.getInterval(), this);
14157     },
14158
14159     // private
14160     getInterval: function(){
14161         if(!this.accelerate){
14162             return this.interval;
14163         }
14164         var pressTime = this.mousedownTime.getElapsed();
14165         if(pressTime < 500){
14166             return 400;
14167         }else if(pressTime < 1700){
14168             return 320;
14169         }else if(pressTime < 2600){
14170             return 250;
14171         }else if(pressTime < 3500){
14172             return 180;
14173         }else if(pressTime < 4400){
14174             return 140;
14175         }else if(pressTime < 5300){
14176             return 80;
14177         }else if(pressTime < 6200){
14178             return 50;
14179         }else{
14180             return 10;
14181         }
14182     },
14183
14184     // private
14185     handleMouseOut : function(){
14186         clearTimeout(this.timer);
14187         if(this.pressClass){
14188             this.el.removeClass(this.pressClass);
14189         }
14190         this.el.on("mouseover", this.handleMouseReturn, this);
14191     },
14192
14193     // private
14194     handleMouseReturn : function(){
14195         this.el.un("mouseover", this.handleMouseReturn);
14196         if(this.pressClass){
14197             this.el.addClass(this.pressClass);
14198         }
14199         this.click();
14200     },
14201
14202     // private
14203     handleMouseUp : function(){
14204         clearTimeout(this.timer);
14205         this.el.un("mouseover", this.handleMouseReturn);
14206         this.el.un("mouseout", this.handleMouseOut);
14207         Roo.get(document).un("mouseup", this.handleMouseUp);
14208         this.el.removeClass(this.pressClass);
14209         this.fireEvent("mouseup", this);
14210     }
14211 });/*
14212  * Based on:
14213  * Ext JS Library 1.1.1
14214  * Copyright(c) 2006-2007, Ext JS, LLC.
14215  *
14216  * Originally Released Under LGPL - original licence link has changed is not relivant.
14217  *
14218  * Fork - LGPL
14219  * <script type="text/javascript">
14220  */
14221
14222  
14223 /**
14224  * @class Roo.KeyNav
14225  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14226  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14227  * way to implement custom navigation schemes for any UI component.</p>
14228  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14229  * pageUp, pageDown, del, home, end.  Usage:</p>
14230  <pre><code>
14231 var nav = new Roo.KeyNav("my-element", {
14232     "left" : function(e){
14233         this.moveLeft(e.ctrlKey);
14234     },
14235     "right" : function(e){
14236         this.moveRight(e.ctrlKey);
14237     },
14238     "enter" : function(e){
14239         this.save();
14240     },
14241     scope : this
14242 });
14243 </code></pre>
14244  * @constructor
14245  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14246  * @param {Object} config The config
14247  */
14248 Roo.KeyNav = function(el, config){
14249     this.el = Roo.get(el);
14250     Roo.apply(this, config);
14251     if(!this.disabled){
14252         this.disabled = true;
14253         this.enable();
14254     }
14255 };
14256
14257 Roo.KeyNav.prototype = {
14258     /**
14259      * @cfg {Boolean} disabled
14260      * True to disable this KeyNav instance (defaults to false)
14261      */
14262     disabled : false,
14263     /**
14264      * @cfg {String} defaultEventAction
14265      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14266      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14267      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14268      */
14269     defaultEventAction: "stopEvent",
14270     /**
14271      * @cfg {Boolean} forceKeyDown
14272      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14273      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14274      * handle keydown instead of keypress.
14275      */
14276     forceKeyDown : false,
14277
14278     // private
14279     prepareEvent : function(e){
14280         var k = e.getKey();
14281         var h = this.keyToHandler[k];
14282         //if(h && this[h]){
14283         //    e.stopPropagation();
14284         //}
14285         if(Roo.isSafari && h && k >= 37 && k <= 40){
14286             e.stopEvent();
14287         }
14288     },
14289
14290     // private
14291     relay : function(e){
14292         var k = e.getKey();
14293         var h = this.keyToHandler[k];
14294         if(h && this[h]){
14295             if(this.doRelay(e, this[h], h) !== true){
14296                 e[this.defaultEventAction]();
14297             }
14298         }
14299     },
14300
14301     // private
14302     doRelay : function(e, h, hname){
14303         return h.call(this.scope || this, e);
14304     },
14305
14306     // possible handlers
14307     enter : false,
14308     left : false,
14309     right : false,
14310     up : false,
14311     down : false,
14312     tab : false,
14313     esc : false,
14314     pageUp : false,
14315     pageDown : false,
14316     del : false,
14317     home : false,
14318     end : false,
14319
14320     // quick lookup hash
14321     keyToHandler : {
14322         37 : "left",
14323         39 : "right",
14324         38 : "up",
14325         40 : "down",
14326         33 : "pageUp",
14327         34 : "pageDown",
14328         46 : "del",
14329         36 : "home",
14330         35 : "end",
14331         13 : "enter",
14332         27 : "esc",
14333         9  : "tab"
14334     },
14335
14336         /**
14337          * Enable this KeyNav
14338          */
14339         enable: function(){
14340                 if(this.disabled){
14341             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14342             // the EventObject will normalize Safari automatically
14343             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14344                 this.el.on("keydown", this.relay,  this);
14345             }else{
14346                 this.el.on("keydown", this.prepareEvent,  this);
14347                 this.el.on("keypress", this.relay,  this);
14348             }
14349                     this.disabled = false;
14350                 }
14351         },
14352
14353         /**
14354          * Disable this KeyNav
14355          */
14356         disable: function(){
14357                 if(!this.disabled){
14358                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14359                 this.el.un("keydown", this.relay);
14360             }else{
14361                 this.el.un("keydown", this.prepareEvent);
14362                 this.el.un("keypress", this.relay);
14363             }
14364                     this.disabled = true;
14365                 }
14366         }
14367 };/*
14368  * Based on:
14369  * Ext JS Library 1.1.1
14370  * Copyright(c) 2006-2007, Ext JS, LLC.
14371  *
14372  * Originally Released Under LGPL - original licence link has changed is not relivant.
14373  *
14374  * Fork - LGPL
14375  * <script type="text/javascript">
14376  */
14377
14378  
14379 /**
14380  * @class Roo.KeyMap
14381  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14382  * The constructor accepts the same config object as defined by {@link #addBinding}.
14383  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14384  * combination it will call the function with this signature (if the match is a multi-key
14385  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14386  * A KeyMap can also handle a string representation of keys.<br />
14387  * Usage:
14388  <pre><code>
14389 // map one key by key code
14390 var map = new Roo.KeyMap("my-element", {
14391     key: 13, // or Roo.EventObject.ENTER
14392     fn: myHandler,
14393     scope: myObject
14394 });
14395
14396 // map multiple keys to one action by string
14397 var map = new Roo.KeyMap("my-element", {
14398     key: "a\r\n\t",
14399     fn: myHandler,
14400     scope: myObject
14401 });
14402
14403 // map multiple keys to multiple actions by strings and array of codes
14404 var map = new Roo.KeyMap("my-element", [
14405     {
14406         key: [10,13],
14407         fn: function(){ alert("Return was pressed"); }
14408     }, {
14409         key: "abc",
14410         fn: function(){ alert('a, b or c was pressed'); }
14411     }, {
14412         key: "\t",
14413         ctrl:true,
14414         shift:true,
14415         fn: function(){ alert('Control + shift + tab was pressed.'); }
14416     }
14417 ]);
14418 </code></pre>
14419  * <b>Note: A KeyMap starts enabled</b>
14420  * @constructor
14421  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14422  * @param {Object} config The config (see {@link #addBinding})
14423  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14424  */
14425 Roo.KeyMap = function(el, config, eventName){
14426     this.el  = Roo.get(el);
14427     this.eventName = eventName || "keydown";
14428     this.bindings = [];
14429     if(config){
14430         this.addBinding(config);
14431     }
14432     this.enable();
14433 };
14434
14435 Roo.KeyMap.prototype = {
14436     /**
14437      * True to stop the event from bubbling and prevent the default browser action if the
14438      * key was handled by the KeyMap (defaults to false)
14439      * @type Boolean
14440      */
14441     stopEvent : false,
14442
14443     /**
14444      * Add a new binding to this KeyMap. The following config object properties are supported:
14445      * <pre>
14446 Property    Type             Description
14447 ----------  ---------------  ----------------------------------------------------------------------
14448 key         String/Array     A single keycode or an array of keycodes to handle
14449 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14450 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14451 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14452 fn          Function         The function to call when KeyMap finds the expected key combination
14453 scope       Object           The scope of the callback function
14454 </pre>
14455      *
14456      * Usage:
14457      * <pre><code>
14458 // Create a KeyMap
14459 var map = new Roo.KeyMap(document, {
14460     key: Roo.EventObject.ENTER,
14461     fn: handleKey,
14462     scope: this
14463 });
14464
14465 //Add a new binding to the existing KeyMap later
14466 map.addBinding({
14467     key: 'abc',
14468     shift: true,
14469     fn: handleKey,
14470     scope: this
14471 });
14472 </code></pre>
14473      * @param {Object/Array} config A single KeyMap config or an array of configs
14474      */
14475         addBinding : function(config){
14476         if(config instanceof Array){
14477             for(var i = 0, len = config.length; i < len; i++){
14478                 this.addBinding(config[i]);
14479             }
14480             return;
14481         }
14482         var keyCode = config.key,
14483             shift = config.shift, 
14484             ctrl = config.ctrl, 
14485             alt = config.alt,
14486             fn = config.fn,
14487             scope = config.scope;
14488         if(typeof keyCode == "string"){
14489             var ks = [];
14490             var keyString = keyCode.toUpperCase();
14491             for(var j = 0, len = keyString.length; j < len; j++){
14492                 ks.push(keyString.charCodeAt(j));
14493             }
14494             keyCode = ks;
14495         }
14496         var keyArray = keyCode instanceof Array;
14497         var handler = function(e){
14498             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14499                 var k = e.getKey();
14500                 if(keyArray){
14501                     for(var i = 0, len = keyCode.length; i < len; i++){
14502                         if(keyCode[i] == k){
14503                           if(this.stopEvent){
14504                               e.stopEvent();
14505                           }
14506                           fn.call(scope || window, k, e);
14507                           return;
14508                         }
14509                     }
14510                 }else{
14511                     if(k == keyCode){
14512                         if(this.stopEvent){
14513                            e.stopEvent();
14514                         }
14515                         fn.call(scope || window, k, e);
14516                     }
14517                 }
14518             }
14519         };
14520         this.bindings.push(handler);  
14521         },
14522
14523     /**
14524      * Shorthand for adding a single key listener
14525      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14526      * following options:
14527      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14528      * @param {Function} fn The function to call
14529      * @param {Object} scope (optional) The scope of the function
14530      */
14531     on : function(key, fn, scope){
14532         var keyCode, shift, ctrl, alt;
14533         if(typeof key == "object" && !(key instanceof Array)){
14534             keyCode = key.key;
14535             shift = key.shift;
14536             ctrl = key.ctrl;
14537             alt = key.alt;
14538         }else{
14539             keyCode = key;
14540         }
14541         this.addBinding({
14542             key: keyCode,
14543             shift: shift,
14544             ctrl: ctrl,
14545             alt: alt,
14546             fn: fn,
14547             scope: scope
14548         })
14549     },
14550
14551     // private
14552     handleKeyDown : function(e){
14553             if(this.enabled){ //just in case
14554             var b = this.bindings;
14555             for(var i = 0, len = b.length; i < len; i++){
14556                 b[i].call(this, e);
14557             }
14558             }
14559         },
14560         
14561         /**
14562          * Returns true if this KeyMap is enabled
14563          * @return {Boolean} 
14564          */
14565         isEnabled : function(){
14566             return this.enabled;  
14567         },
14568         
14569         /**
14570          * Enables this KeyMap
14571          */
14572         enable: function(){
14573                 if(!this.enabled){
14574                     this.el.on(this.eventName, this.handleKeyDown, this);
14575                     this.enabled = true;
14576                 }
14577         },
14578
14579         /**
14580          * Disable this KeyMap
14581          */
14582         disable: function(){
14583                 if(this.enabled){
14584                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14585                     this.enabled = false;
14586                 }
14587         }
14588 };/*
14589  * Based on:
14590  * Ext JS Library 1.1.1
14591  * Copyright(c) 2006-2007, Ext JS, LLC.
14592  *
14593  * Originally Released Under LGPL - original licence link has changed is not relivant.
14594  *
14595  * Fork - LGPL
14596  * <script type="text/javascript">
14597  */
14598
14599  
14600 /**
14601  * @class Roo.util.TextMetrics
14602  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14603  * wide, in pixels, a given block of text will be.
14604  * @singleton
14605  */
14606 Roo.util.TextMetrics = function(){
14607     var shared;
14608     return {
14609         /**
14610          * Measures the size of the specified text
14611          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14612          * that can affect the size of the rendered text
14613          * @param {String} text The text to measure
14614          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14615          * in order to accurately measure the text height
14616          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14617          */
14618         measure : function(el, text, fixedWidth){
14619             if(!shared){
14620                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14621             }
14622             shared.bind(el);
14623             shared.setFixedWidth(fixedWidth || 'auto');
14624             return shared.getSize(text);
14625         },
14626
14627         /**
14628          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14629          * the overhead of multiple calls to initialize the style properties on each measurement.
14630          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14631          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14632          * in order to accurately measure the text height
14633          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14634          */
14635         createInstance : function(el, fixedWidth){
14636             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14637         }
14638     };
14639 }();
14640
14641  
14642
14643 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14644     var ml = new Roo.Element(document.createElement('div'));
14645     document.body.appendChild(ml.dom);
14646     ml.position('absolute');
14647     ml.setLeftTop(-1000, -1000);
14648     ml.hide();
14649
14650     if(fixedWidth){
14651         ml.setWidth(fixedWidth);
14652     }
14653      
14654     var instance = {
14655         /**
14656          * Returns the size of the specified text based on the internal element's style and width properties
14657          * @memberOf Roo.util.TextMetrics.Instance#
14658          * @param {String} text The text to measure
14659          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14660          */
14661         getSize : function(text){
14662             ml.update(text);
14663             var s = ml.getSize();
14664             ml.update('');
14665             return s;
14666         },
14667
14668         /**
14669          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14670          * that can affect the size of the rendered text
14671          * @memberOf Roo.util.TextMetrics.Instance#
14672          * @param {String/HTMLElement} el The element, dom node or id
14673          */
14674         bind : function(el){
14675             ml.setStyle(
14676                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14677             );
14678         },
14679
14680         /**
14681          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14682          * to set a fixed width in order to accurately measure the text height.
14683          * @memberOf Roo.util.TextMetrics.Instance#
14684          * @param {Number} width The width to set on the element
14685          */
14686         setFixedWidth : function(width){
14687             ml.setWidth(width);
14688         },
14689
14690         /**
14691          * Returns the measured width of the specified text
14692          * @memberOf Roo.util.TextMetrics.Instance#
14693          * @param {String} text The text to measure
14694          * @return {Number} width The width in pixels
14695          */
14696         getWidth : function(text){
14697             ml.dom.style.width = 'auto';
14698             return this.getSize(text).width;
14699         },
14700
14701         /**
14702          * Returns the measured height of the specified text.  For multiline text, be sure to call
14703          * {@link #setFixedWidth} if necessary.
14704          * @memberOf Roo.util.TextMetrics.Instance#
14705          * @param {String} text The text to measure
14706          * @return {Number} height The height in pixels
14707          */
14708         getHeight : function(text){
14709             return this.getSize(text).height;
14710         }
14711     };
14712
14713     instance.bind(bindTo);
14714
14715     return instance;
14716 };
14717
14718 // backwards compat
14719 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14720  * Based on:
14721  * Ext JS Library 1.1.1
14722  * Copyright(c) 2006-2007, Ext JS, LLC.
14723  *
14724  * Originally Released Under LGPL - original licence link has changed is not relivant.
14725  *
14726  * Fork - LGPL
14727  * <script type="text/javascript">
14728  */
14729
14730 /**
14731  * @class Roo.state.Provider
14732  * Abstract base class for state provider implementations. This class provides methods
14733  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14734  * Provider interface.
14735  */
14736 Roo.state.Provider = function(){
14737     /**
14738      * @event statechange
14739      * Fires when a state change occurs.
14740      * @param {Provider} this This state provider
14741      * @param {String} key The state key which was changed
14742      * @param {String} value The encoded value for the state
14743      */
14744     this.addEvents({
14745         "statechange": true
14746     });
14747     this.state = {};
14748     Roo.state.Provider.superclass.constructor.call(this);
14749 };
14750 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14751     /**
14752      * Returns the current value for a key
14753      * @param {String} name The key name
14754      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14755      * @return {Mixed} The state data
14756      */
14757     get : function(name, defaultValue){
14758         return typeof this.state[name] == "undefined" ?
14759             defaultValue : this.state[name];
14760     },
14761     
14762     /**
14763      * Clears a value from the state
14764      * @param {String} name The key name
14765      */
14766     clear : function(name){
14767         delete this.state[name];
14768         this.fireEvent("statechange", this, name, null);
14769     },
14770     
14771     /**
14772      * Sets the value for a key
14773      * @param {String} name The key name
14774      * @param {Mixed} value The value to set
14775      */
14776     set : function(name, value){
14777         this.state[name] = value;
14778         this.fireEvent("statechange", this, name, value);
14779     },
14780     
14781     /**
14782      * Decodes a string previously encoded with {@link #encodeValue}.
14783      * @param {String} value The value to decode
14784      * @return {Mixed} The decoded value
14785      */
14786     decodeValue : function(cookie){
14787         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14788         var matches = re.exec(unescape(cookie));
14789         if(!matches || !matches[1]) return; // non state cookie
14790         var type = matches[1];
14791         var v = matches[2];
14792         switch(type){
14793             case "n":
14794                 return parseFloat(v);
14795             case "d":
14796                 return new Date(Date.parse(v));
14797             case "b":
14798                 return (v == "1");
14799             case "a":
14800                 var all = [];
14801                 var values = v.split("^");
14802                 for(var i = 0, len = values.length; i < len; i++){
14803                     all.push(this.decodeValue(values[i]));
14804                 }
14805                 return all;
14806            case "o":
14807                 var all = {};
14808                 var values = v.split("^");
14809                 for(var i = 0, len = values.length; i < len; i++){
14810                     var kv = values[i].split("=");
14811                     all[kv[0]] = this.decodeValue(kv[1]);
14812                 }
14813                 return all;
14814            default:
14815                 return v;
14816         }
14817     },
14818     
14819     /**
14820      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14821      * @param {Mixed} value The value to encode
14822      * @return {String} The encoded value
14823      */
14824     encodeValue : function(v){
14825         var enc;
14826         if(typeof v == "number"){
14827             enc = "n:" + v;
14828         }else if(typeof v == "boolean"){
14829             enc = "b:" + (v ? "1" : "0");
14830         }else if(v instanceof Date){
14831             enc = "d:" + v.toGMTString();
14832         }else if(v instanceof Array){
14833             var flat = "";
14834             for(var i = 0, len = v.length; i < len; i++){
14835                 flat += this.encodeValue(v[i]);
14836                 if(i != len-1) flat += "^";
14837             }
14838             enc = "a:" + flat;
14839         }else if(typeof v == "object"){
14840             var flat = "";
14841             for(var key in v){
14842                 if(typeof v[key] != "function"){
14843                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14844                 }
14845             }
14846             enc = "o:" + flat.substring(0, flat.length-1);
14847         }else{
14848             enc = "s:" + v;
14849         }
14850         return escape(enc);        
14851     }
14852 });
14853
14854 /*
14855  * Based on:
14856  * Ext JS Library 1.1.1
14857  * Copyright(c) 2006-2007, Ext JS, LLC.
14858  *
14859  * Originally Released Under LGPL - original licence link has changed is not relivant.
14860  *
14861  * Fork - LGPL
14862  * <script type="text/javascript">
14863  */
14864 /**
14865  * @class Roo.state.Manager
14866  * This is the global state manager. By default all components that are "state aware" check this class
14867  * for state information if you don't pass them a custom state provider. In order for this class
14868  * to be useful, it must be initialized with a provider when your application initializes.
14869  <pre><code>
14870 // in your initialization function
14871 init : function(){
14872    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14873    ...
14874    // supposed you have a {@link Roo.BorderLayout}
14875    var layout = new Roo.BorderLayout(...);
14876    layout.restoreState();
14877    // or a {Roo.BasicDialog}
14878    var dialog = new Roo.BasicDialog(...);
14879    dialog.restoreState();
14880  </code></pre>
14881  * @singleton
14882  */
14883 Roo.state.Manager = function(){
14884     var provider = new Roo.state.Provider();
14885     
14886     return {
14887         /**
14888          * Configures the default state provider for your application
14889          * @param {Provider} stateProvider The state provider to set
14890          */
14891         setProvider : function(stateProvider){
14892             provider = stateProvider;
14893         },
14894         
14895         /**
14896          * Returns the current value for a key
14897          * @param {String} name The key name
14898          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14899          * @return {Mixed} The state data
14900          */
14901         get : function(key, defaultValue){
14902             return provider.get(key, defaultValue);
14903         },
14904         
14905         /**
14906          * Sets the value for a key
14907          * @param {String} name The key name
14908          * @param {Mixed} value The state data
14909          */
14910          set : function(key, value){
14911             provider.set(key, value);
14912         },
14913         
14914         /**
14915          * Clears a value from the state
14916          * @param {String} name The key name
14917          */
14918         clear : function(key){
14919             provider.clear(key);
14920         },
14921         
14922         /**
14923          * Gets the currently configured state provider
14924          * @return {Provider} The state provider
14925          */
14926         getProvider : function(){
14927             return provider;
14928         }
14929     };
14930 }();
14931 /*
14932  * Based on:
14933  * Ext JS Library 1.1.1
14934  * Copyright(c) 2006-2007, Ext JS, LLC.
14935  *
14936  * Originally Released Under LGPL - original licence link has changed is not relivant.
14937  *
14938  * Fork - LGPL
14939  * <script type="text/javascript">
14940  */
14941 /**
14942  * @class Roo.state.CookieProvider
14943  * @extends Roo.state.Provider
14944  * The default Provider implementation which saves state via cookies.
14945  * <br />Usage:
14946  <pre><code>
14947    var cp = new Roo.state.CookieProvider({
14948        path: "/cgi-bin/",
14949        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14950        domain: "roojs.com"
14951    })
14952    Roo.state.Manager.setProvider(cp);
14953  </code></pre>
14954  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14955  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14956  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14957  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14958  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14959  * domain the page is running on including the 'www' like 'www.roojs.com')
14960  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14961  * @constructor
14962  * Create a new CookieProvider
14963  * @param {Object} config The configuration object
14964  */
14965 Roo.state.CookieProvider = function(config){
14966     Roo.state.CookieProvider.superclass.constructor.call(this);
14967     this.path = "/";
14968     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14969     this.domain = null;
14970     this.secure = false;
14971     Roo.apply(this, config);
14972     this.state = this.readCookies();
14973 };
14974
14975 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14976     // private
14977     set : function(name, value){
14978         if(typeof value == "undefined" || value === null){
14979             this.clear(name);
14980             return;
14981         }
14982         this.setCookie(name, value);
14983         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14984     },
14985
14986     // private
14987     clear : function(name){
14988         this.clearCookie(name);
14989         Roo.state.CookieProvider.superclass.clear.call(this, name);
14990     },
14991
14992     // private
14993     readCookies : function(){
14994         var cookies = {};
14995         var c = document.cookie + ";";
14996         var re = /\s?(.*?)=(.*?);/g;
14997         var matches;
14998         while((matches = re.exec(c)) != null){
14999             var name = matches[1];
15000             var value = matches[2];
15001             if(name && name.substring(0,3) == "ys-"){
15002                 cookies[name.substr(3)] = this.decodeValue(value);
15003             }
15004         }
15005         return cookies;
15006     },
15007
15008     // private
15009     setCookie : function(name, value){
15010         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15011            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15012            ((this.path == null) ? "" : ("; path=" + this.path)) +
15013            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15014            ((this.secure == true) ? "; secure" : "");
15015     },
15016
15017     // private
15018     clearCookie : function(name){
15019         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15020            ((this.path == null) ? "" : ("; path=" + this.path)) +
15021            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15022            ((this.secure == true) ? "; secure" : "");
15023     }
15024 });/*
15025  * Based on:
15026  * Ext JS Library 1.1.1
15027  * Copyright(c) 2006-2007, Ext JS, LLC.
15028  *
15029  * Originally Released Under LGPL - original licence link has changed is not relivant.
15030  *
15031  * Fork - LGPL
15032  * <script type="text/javascript">
15033  */
15034  
15035
15036 /**
15037  * @class Roo.ComponentMgr
15038  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15039  * @singleton
15040  */
15041 Roo.ComponentMgr = function(){
15042     var all = new Roo.util.MixedCollection();
15043
15044     return {
15045         /**
15046          * Registers a component.
15047          * @param {Roo.Component} c The component
15048          */
15049         register : function(c){
15050             all.add(c);
15051         },
15052
15053         /**
15054          * Unregisters a component.
15055          * @param {Roo.Component} c The component
15056          */
15057         unregister : function(c){
15058             all.remove(c);
15059         },
15060
15061         /**
15062          * Returns a component by id
15063          * @param {String} id The component id
15064          */
15065         get : function(id){
15066             return all.get(id);
15067         },
15068
15069         /**
15070          * Registers a function that will be called when a specified component is added to ComponentMgr
15071          * @param {String} id The component id
15072          * @param {Funtction} fn The callback function
15073          * @param {Object} scope The scope of the callback
15074          */
15075         onAvailable : function(id, fn, scope){
15076             all.on("add", function(index, o){
15077                 if(o.id == id){
15078                     fn.call(scope || o, o);
15079                     all.un("add", fn, scope);
15080                 }
15081             });
15082         }
15083     };
15084 }();/*
15085  * Based on:
15086  * Ext JS Library 1.1.1
15087  * Copyright(c) 2006-2007, Ext JS, LLC.
15088  *
15089  * Originally Released Under LGPL - original licence link has changed is not relivant.
15090  *
15091  * Fork - LGPL
15092  * <script type="text/javascript">
15093  */
15094  
15095 /**
15096  * @class Roo.Component
15097  * @extends Roo.util.Observable
15098  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15099  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15100  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15101  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15102  * All visual components (widgets) that require rendering into a layout should subclass Component.
15103  * @constructor
15104  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15105  * 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
15106  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15107  */
15108 Roo.Component = function(config){
15109     config = config || {};
15110     if(config.tagName || config.dom || typeof config == "string"){ // element object
15111         config = {el: config, id: config.id || config};
15112     }
15113     this.initialConfig = config;
15114
15115     Roo.apply(this, config);
15116     this.addEvents({
15117         /**
15118          * @event disable
15119          * Fires after the component is disabled.
15120              * @param {Roo.Component} this
15121              */
15122         disable : true,
15123         /**
15124          * @event enable
15125          * Fires after the component is enabled.
15126              * @param {Roo.Component} this
15127              */
15128         enable : true,
15129         /**
15130          * @event beforeshow
15131          * Fires before the component is shown.  Return false to stop the show.
15132              * @param {Roo.Component} this
15133              */
15134         beforeshow : true,
15135         /**
15136          * @event show
15137          * Fires after the component is shown.
15138              * @param {Roo.Component} this
15139              */
15140         show : true,
15141         /**
15142          * @event beforehide
15143          * Fires before the component is hidden. Return false to stop the hide.
15144              * @param {Roo.Component} this
15145              */
15146         beforehide : true,
15147         /**
15148          * @event hide
15149          * Fires after the component is hidden.
15150              * @param {Roo.Component} this
15151              */
15152         hide : true,
15153         /**
15154          * @event beforerender
15155          * Fires before the component is rendered. Return false to stop the render.
15156              * @param {Roo.Component} this
15157              */
15158         beforerender : true,
15159         /**
15160          * @event render
15161          * Fires after the component is rendered.
15162              * @param {Roo.Component} this
15163              */
15164         render : true,
15165         /**
15166          * @event beforedestroy
15167          * Fires before the component is destroyed. Return false to stop the destroy.
15168              * @param {Roo.Component} this
15169              */
15170         beforedestroy : true,
15171         /**
15172          * @event destroy
15173          * Fires after the component is destroyed.
15174              * @param {Roo.Component} this
15175              */
15176         destroy : true
15177     });
15178     if(!this.id){
15179         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15180     }
15181     Roo.ComponentMgr.register(this);
15182     Roo.Component.superclass.constructor.call(this);
15183     this.initComponent();
15184     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15185         this.render(this.renderTo);
15186         delete this.renderTo;
15187     }
15188 };
15189
15190 /** @private */
15191 Roo.Component.AUTO_ID = 1000;
15192
15193 Roo.extend(Roo.Component, Roo.util.Observable, {
15194     /**
15195      * @scope Roo.Component.prototype
15196      * @type {Boolean}
15197      * true if this component is hidden. Read-only.
15198      */
15199     hidden : false,
15200     /**
15201      * @type {Boolean}
15202      * true if this component is disabled. Read-only.
15203      */
15204     disabled : false,
15205     /**
15206      * @type {Boolean}
15207      * true if this component has been rendered. Read-only.
15208      */
15209     rendered : false,
15210     
15211     /** @cfg {String} disableClass
15212      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15213      */
15214     disabledClass : "x-item-disabled",
15215         /** @cfg {Boolean} allowDomMove
15216          * Whether the component can move the Dom node when rendering (defaults to true).
15217          */
15218     allowDomMove : true,
15219     /** @cfg {String} hideMode (display|visibility)
15220      * How this component should hidden. Supported values are
15221      * "visibility" (css visibility), "offsets" (negative offset position) and
15222      * "display" (css display) - defaults to "display".
15223      */
15224     hideMode: 'display',
15225
15226     /** @private */
15227     ctype : "Roo.Component",
15228
15229     /**
15230      * @cfg {String} actionMode 
15231      * which property holds the element that used for  hide() / show() / disable() / enable()
15232      * default is 'el' 
15233      */
15234     actionMode : "el",
15235
15236     /** @private */
15237     getActionEl : function(){
15238         return this[this.actionMode];
15239     },
15240
15241     initComponent : Roo.emptyFn,
15242     /**
15243      * If this is a lazy rendering component, render it to its container element.
15244      * @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.
15245      */
15246     render : function(container, position){
15247         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15248             if(!container && this.el){
15249                 this.el = Roo.get(this.el);
15250                 container = this.el.dom.parentNode;
15251                 this.allowDomMove = false;
15252             }
15253             this.container = Roo.get(container);
15254             this.rendered = true;
15255             if(position !== undefined){
15256                 if(typeof position == 'number'){
15257                     position = this.container.dom.childNodes[position];
15258                 }else{
15259                     position = Roo.getDom(position);
15260                 }
15261             }
15262             this.onRender(this.container, position || null);
15263             if(this.cls){
15264                 this.el.addClass(this.cls);
15265                 delete this.cls;
15266             }
15267             if(this.style){
15268                 this.el.applyStyles(this.style);
15269                 delete this.style;
15270             }
15271             this.fireEvent("render", this);
15272             this.afterRender(this.container);
15273             if(this.hidden){
15274                 this.hide();
15275             }
15276             if(this.disabled){
15277                 this.disable();
15278             }
15279         }
15280         return this;
15281     },
15282
15283     /** @private */
15284     // default function is not really useful
15285     onRender : function(ct, position){
15286         if(this.el){
15287             this.el = Roo.get(this.el);
15288             if(this.allowDomMove !== false){
15289                 ct.dom.insertBefore(this.el.dom, position);
15290             }
15291         }
15292     },
15293
15294     /** @private */
15295     getAutoCreate : function(){
15296         var cfg = typeof this.autoCreate == "object" ?
15297                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15298         if(this.id && !cfg.id){
15299             cfg.id = this.id;
15300         }
15301         return cfg;
15302     },
15303
15304     /** @private */
15305     afterRender : Roo.emptyFn,
15306
15307     /**
15308      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15309      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15310      */
15311     destroy : function(){
15312         if(this.fireEvent("beforedestroy", this) !== false){
15313             this.purgeListeners();
15314             this.beforeDestroy();
15315             if(this.rendered){
15316                 this.el.removeAllListeners();
15317                 this.el.remove();
15318                 if(this.actionMode == "container"){
15319                     this.container.remove();
15320                 }
15321             }
15322             this.onDestroy();
15323             Roo.ComponentMgr.unregister(this);
15324             this.fireEvent("destroy", this);
15325         }
15326     },
15327
15328         /** @private */
15329     beforeDestroy : function(){
15330
15331     },
15332
15333         /** @private */
15334         onDestroy : function(){
15335
15336     },
15337
15338     /**
15339      * Returns the underlying {@link Roo.Element}.
15340      * @return {Roo.Element} The element
15341      */
15342     getEl : function(){
15343         return this.el;
15344     },
15345
15346     /**
15347      * Returns the id of this component.
15348      * @return {String}
15349      */
15350     getId : function(){
15351         return this.id;
15352     },
15353
15354     /**
15355      * Try to focus this component.
15356      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15357      * @return {Roo.Component} this
15358      */
15359     focus : function(selectText){
15360         if(this.rendered){
15361             this.el.focus();
15362             if(selectText === true){
15363                 this.el.dom.select();
15364             }
15365         }
15366         return this;
15367     },
15368
15369     /** @private */
15370     blur : function(){
15371         if(this.rendered){
15372             this.el.blur();
15373         }
15374         return this;
15375     },
15376
15377     /**
15378      * Disable this component.
15379      * @return {Roo.Component} this
15380      */
15381     disable : function(){
15382         if(this.rendered){
15383             this.onDisable();
15384         }
15385         this.disabled = true;
15386         this.fireEvent("disable", this);
15387         return this;
15388     },
15389
15390         // private
15391     onDisable : function(){
15392         this.getActionEl().addClass(this.disabledClass);
15393         this.el.dom.disabled = true;
15394     },
15395
15396     /**
15397      * Enable this component.
15398      * @return {Roo.Component} this
15399      */
15400     enable : function(){
15401         if(this.rendered){
15402             this.onEnable();
15403         }
15404         this.disabled = false;
15405         this.fireEvent("enable", this);
15406         return this;
15407     },
15408
15409         // private
15410     onEnable : function(){
15411         this.getActionEl().removeClass(this.disabledClass);
15412         this.el.dom.disabled = false;
15413     },
15414
15415     /**
15416      * Convenience function for setting disabled/enabled by boolean.
15417      * @param {Boolean} disabled
15418      */
15419     setDisabled : function(disabled){
15420         this[disabled ? "disable" : "enable"]();
15421     },
15422
15423     /**
15424      * Show this component.
15425      * @return {Roo.Component} this
15426      */
15427     show: function(){
15428         if(this.fireEvent("beforeshow", this) !== false){
15429             this.hidden = false;
15430             if(this.rendered){
15431                 this.onShow();
15432             }
15433             this.fireEvent("show", this);
15434         }
15435         return this;
15436     },
15437
15438     // private
15439     onShow : function(){
15440         var ae = this.getActionEl();
15441         if(this.hideMode == 'visibility'){
15442             ae.dom.style.visibility = "visible";
15443         }else if(this.hideMode == 'offsets'){
15444             ae.removeClass('x-hidden');
15445         }else{
15446             ae.dom.style.display = "";
15447         }
15448     },
15449
15450     /**
15451      * Hide this component.
15452      * @return {Roo.Component} this
15453      */
15454     hide: function(){
15455         if(this.fireEvent("beforehide", this) !== false){
15456             this.hidden = true;
15457             if(this.rendered){
15458                 this.onHide();
15459             }
15460             this.fireEvent("hide", this);
15461         }
15462         return this;
15463     },
15464
15465     // private
15466     onHide : function(){
15467         var ae = this.getActionEl();
15468         if(this.hideMode == 'visibility'){
15469             ae.dom.style.visibility = "hidden";
15470         }else if(this.hideMode == 'offsets'){
15471             ae.addClass('x-hidden');
15472         }else{
15473             ae.dom.style.display = "none";
15474         }
15475     },
15476
15477     /**
15478      * Convenience function to hide or show this component by boolean.
15479      * @param {Boolean} visible True to show, false to hide
15480      * @return {Roo.Component} this
15481      */
15482     setVisible: function(visible){
15483         if(visible) {
15484             this.show();
15485         }else{
15486             this.hide();
15487         }
15488         return this;
15489     },
15490
15491     /**
15492      * Returns true if this component is visible.
15493      */
15494     isVisible : function(){
15495         return this.getActionEl().isVisible();
15496     },
15497
15498     cloneConfig : function(overrides){
15499         overrides = overrides || {};
15500         var id = overrides.id || Roo.id();
15501         var cfg = Roo.applyIf(overrides, this.initialConfig);
15502         cfg.id = id; // prevent dup id
15503         return new this.constructor(cfg);
15504     }
15505 });/*
15506  * Based on:
15507  * Ext JS Library 1.1.1
15508  * Copyright(c) 2006-2007, Ext JS, LLC.
15509  *
15510  * Originally Released Under LGPL - original licence link has changed is not relivant.
15511  *
15512  * Fork - LGPL
15513  * <script type="text/javascript">
15514  */
15515
15516 /**
15517  * @class Roo.BoxComponent
15518  * @extends Roo.Component
15519  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15520  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15521  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15522  * layout containers.
15523  * @constructor
15524  * @param {Roo.Element/String/Object} config The configuration options.
15525  */
15526 Roo.BoxComponent = function(config){
15527     Roo.Component.call(this, config);
15528     this.addEvents({
15529         /**
15530          * @event resize
15531          * Fires after the component is resized.
15532              * @param {Roo.Component} this
15533              * @param {Number} adjWidth The box-adjusted width that was set
15534              * @param {Number} adjHeight The box-adjusted height that was set
15535              * @param {Number} rawWidth The width that was originally specified
15536              * @param {Number} rawHeight The height that was originally specified
15537              */
15538         resize : true,
15539         /**
15540          * @event move
15541          * Fires after the component is moved.
15542              * @param {Roo.Component} this
15543              * @param {Number} x The new x position
15544              * @param {Number} y The new y position
15545              */
15546         move : true
15547     });
15548 };
15549
15550 Roo.extend(Roo.BoxComponent, Roo.Component, {
15551     // private, set in afterRender to signify that the component has been rendered
15552     boxReady : false,
15553     // private, used to defer height settings to subclasses
15554     deferHeight: false,
15555     /** @cfg {Number} width
15556      * width (optional) size of component
15557      */
15558      /** @cfg {Number} height
15559      * height (optional) size of component
15560      */
15561      
15562     /**
15563      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15564      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15565      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15566      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15567      * @return {Roo.BoxComponent} this
15568      */
15569     setSize : function(w, h){
15570         // support for standard size objects
15571         if(typeof w == 'object'){
15572             h = w.height;
15573             w = w.width;
15574         }
15575         // not rendered
15576         if(!this.boxReady){
15577             this.width = w;
15578             this.height = h;
15579             return this;
15580         }
15581
15582         // prevent recalcs when not needed
15583         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15584             return this;
15585         }
15586         this.lastSize = {width: w, height: h};
15587
15588         var adj = this.adjustSize(w, h);
15589         var aw = adj.width, ah = adj.height;
15590         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15591             var rz = this.getResizeEl();
15592             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15593                 rz.setSize(aw, ah);
15594             }else if(!this.deferHeight && ah !== undefined){
15595                 rz.setHeight(ah);
15596             }else if(aw !== undefined){
15597                 rz.setWidth(aw);
15598             }
15599             this.onResize(aw, ah, w, h);
15600             this.fireEvent('resize', this, aw, ah, w, h);
15601         }
15602         return this;
15603     },
15604
15605     /**
15606      * Gets the current size of the component's underlying element.
15607      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15608      */
15609     getSize : function(){
15610         return this.el.getSize();
15611     },
15612
15613     /**
15614      * Gets the current XY position of the component's underlying element.
15615      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15616      * @return {Array} The XY position of the element (e.g., [100, 200])
15617      */
15618     getPosition : function(local){
15619         if(local === true){
15620             return [this.el.getLeft(true), this.el.getTop(true)];
15621         }
15622         return this.xy || this.el.getXY();
15623     },
15624
15625     /**
15626      * Gets the current box measurements of the component's underlying element.
15627      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15628      * @returns {Object} box An object in the format {x, y, width, height}
15629      */
15630     getBox : function(local){
15631         var s = this.el.getSize();
15632         if(local){
15633             s.x = this.el.getLeft(true);
15634             s.y = this.el.getTop(true);
15635         }else{
15636             var xy = this.xy || this.el.getXY();
15637             s.x = xy[0];
15638             s.y = xy[1];
15639         }
15640         return s;
15641     },
15642
15643     /**
15644      * Sets the current box measurements of the component's underlying element.
15645      * @param {Object} box An object in the format {x, y, width, height}
15646      * @returns {Roo.BoxComponent} this
15647      */
15648     updateBox : function(box){
15649         this.setSize(box.width, box.height);
15650         this.setPagePosition(box.x, box.y);
15651         return this;
15652     },
15653
15654     // protected
15655     getResizeEl : function(){
15656         return this.resizeEl || this.el;
15657     },
15658
15659     // protected
15660     getPositionEl : function(){
15661         return this.positionEl || this.el;
15662     },
15663
15664     /**
15665      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15666      * This method fires the move event.
15667      * @param {Number} left The new left
15668      * @param {Number} top The new top
15669      * @returns {Roo.BoxComponent} this
15670      */
15671     setPosition : function(x, y){
15672         this.x = x;
15673         this.y = y;
15674         if(!this.boxReady){
15675             return this;
15676         }
15677         var adj = this.adjustPosition(x, y);
15678         var ax = adj.x, ay = adj.y;
15679
15680         var el = this.getPositionEl();
15681         if(ax !== undefined || ay !== undefined){
15682             if(ax !== undefined && ay !== undefined){
15683                 el.setLeftTop(ax, ay);
15684             }else if(ax !== undefined){
15685                 el.setLeft(ax);
15686             }else if(ay !== undefined){
15687                 el.setTop(ay);
15688             }
15689             this.onPosition(ax, ay);
15690             this.fireEvent('move', this, ax, ay);
15691         }
15692         return this;
15693     },
15694
15695     /**
15696      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15697      * This method fires the move event.
15698      * @param {Number} x The new x position
15699      * @param {Number} y The new y position
15700      * @returns {Roo.BoxComponent} this
15701      */
15702     setPagePosition : function(x, y){
15703         this.pageX = x;
15704         this.pageY = y;
15705         if(!this.boxReady){
15706             return;
15707         }
15708         if(x === undefined || y === undefined){ // cannot translate undefined points
15709             return;
15710         }
15711         var p = this.el.translatePoints(x, y);
15712         this.setPosition(p.left, p.top);
15713         return this;
15714     },
15715
15716     // private
15717     onRender : function(ct, position){
15718         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15719         if(this.resizeEl){
15720             this.resizeEl = Roo.get(this.resizeEl);
15721         }
15722         if(this.positionEl){
15723             this.positionEl = Roo.get(this.positionEl);
15724         }
15725     },
15726
15727     // private
15728     afterRender : function(){
15729         Roo.BoxComponent.superclass.afterRender.call(this);
15730         this.boxReady = true;
15731         this.setSize(this.width, this.height);
15732         if(this.x || this.y){
15733             this.setPosition(this.x, this.y);
15734         }
15735         if(this.pageX || this.pageY){
15736             this.setPagePosition(this.pageX, this.pageY);
15737         }
15738     },
15739
15740     /**
15741      * Force the component's size to recalculate based on the underlying element's current height and width.
15742      * @returns {Roo.BoxComponent} this
15743      */
15744     syncSize : function(){
15745         delete this.lastSize;
15746         this.setSize(this.el.getWidth(), this.el.getHeight());
15747         return this;
15748     },
15749
15750     /**
15751      * Called after the component is resized, this method is empty by default but can be implemented by any
15752      * subclass that needs to perform custom logic after a resize occurs.
15753      * @param {Number} adjWidth The box-adjusted width that was set
15754      * @param {Number} adjHeight The box-adjusted height that was set
15755      * @param {Number} rawWidth The width that was originally specified
15756      * @param {Number} rawHeight The height that was originally specified
15757      */
15758     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15759
15760     },
15761
15762     /**
15763      * Called after the component is moved, this method is empty by default but can be implemented by any
15764      * subclass that needs to perform custom logic after a move occurs.
15765      * @param {Number} x The new x position
15766      * @param {Number} y The new y position
15767      */
15768     onPosition : function(x, y){
15769
15770     },
15771
15772     // private
15773     adjustSize : function(w, h){
15774         if(this.autoWidth){
15775             w = 'auto';
15776         }
15777         if(this.autoHeight){
15778             h = 'auto';
15779         }
15780         return {width : w, height: h};
15781     },
15782
15783     // private
15784     adjustPosition : function(x, y){
15785         return {x : x, y: y};
15786     }
15787 });/*
15788  * Original code for Roojs - LGPL
15789  * <script type="text/javascript">
15790  */
15791  
15792 /**
15793  * @class Roo.XComponent
15794  * A delayed Element creator...
15795  * Or a way to group chunks of interface together.
15796  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15797  *  used in conjunction with XComponent.build() it will create an instance of each element,
15798  *  then call addxtype() to build the User interface.
15799  * 
15800  * Mypart.xyx = new Roo.XComponent({
15801
15802     parent : 'Mypart.xyz', // empty == document.element.!!
15803     order : '001',
15804     name : 'xxxx'
15805     region : 'xxxx'
15806     disabled : function() {} 
15807      
15808     tree : function() { // return an tree of xtype declared components
15809         var MODULE = this;
15810         return 
15811         {
15812             xtype : 'NestedLayoutPanel',
15813             // technicall
15814         }
15815      ]
15816  *})
15817  *
15818  *
15819  * It can be used to build a big heiracy, with parent etc.
15820  * or you can just use this to render a single compoent to a dom element
15821  * MYPART.render(Roo.Element | String(id) | dom_element )
15822  *
15823  *
15824  * Usage patterns.
15825  *
15826  * Classic Roo
15827  *
15828  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15829  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15830  *
15831  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15832  *
15833  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15834  * - if mulitple topModules exist, the last one is defined as the top module.
15835  *
15836  * Embeded Roo
15837  * 
15838  * When the top level or multiple modules are to embedded into a existing HTML page,
15839  * the parent element can container '#id' of the element where the module will be drawn.
15840  *
15841  * Bootstrap Roo
15842  *
15843  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15844  * it relies more on a include mechanism, where sub modules are included into an outer page.
15845  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15846  * 
15847  * Bootstrap Roo Included elements
15848  *
15849  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15850  * hence confusing the component builder as it thinks there are multiple top level elements. 
15851  *
15852  * 
15853  * 
15854  * @extends Roo.util.Observable
15855  * @constructor
15856  * @param cfg {Object} configuration of component
15857  * 
15858  */
15859 Roo.XComponent = function(cfg) {
15860     Roo.apply(this, cfg);
15861     this.addEvents({ 
15862         /**
15863              * @event built
15864              * Fires when this the componnt is built
15865              * @param {Roo.XComponent} c the component
15866              */
15867         'built' : true
15868         
15869     });
15870     this.region = this.region || 'center'; // default..
15871     Roo.XComponent.register(this);
15872     this.modules = false;
15873     this.el = false; // where the layout goes..
15874     
15875     
15876 }
15877 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15878     /**
15879      * @property el
15880      * The created element (with Roo.factory())
15881      * @type {Roo.Layout}
15882      */
15883     el  : false,
15884     
15885     /**
15886      * @property el
15887      * for BC  - use el in new code
15888      * @type {Roo.Layout}
15889      */
15890     panel : false,
15891     
15892     /**
15893      * @property layout
15894      * for BC  - use el in new code
15895      * @type {Roo.Layout}
15896      */
15897     layout : false,
15898     
15899      /**
15900      * @cfg {Function|boolean} disabled
15901      * If this module is disabled by some rule, return true from the funtion
15902      */
15903     disabled : false,
15904     
15905     /**
15906      * @cfg {String} parent 
15907      * Name of parent element which it get xtype added to..
15908      */
15909     parent: false,
15910     
15911     /**
15912      * @cfg {String} order
15913      * Used to set the order in which elements are created (usefull for multiple tabs)
15914      */
15915     
15916     order : false,
15917     /**
15918      * @cfg {String} name
15919      * String to display while loading.
15920      */
15921     name : false,
15922     /**
15923      * @cfg {String} region
15924      * Region to render component to (defaults to center)
15925      */
15926     region : 'center',
15927     
15928     /**
15929      * @cfg {Array} items
15930      * A single item array - the first element is the root of the tree..
15931      * It's done this way to stay compatible with the Xtype system...
15932      */
15933     items : false,
15934     
15935     /**
15936      * @property _tree
15937      * The method that retuns the tree of parts that make up this compoennt 
15938      * @type {function}
15939      */
15940     _tree  : false,
15941     
15942      /**
15943      * render
15944      * render element to dom or tree
15945      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15946      */
15947     
15948     render : function(el)
15949     {
15950         
15951         el = el || false;
15952         var hp = this.parent ? 1 : 0;
15953         Roo.debug &&  Roo.log(this);
15954         
15955         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15956             // if parent is a '#.....' string, then let's use that..
15957             var ename = this.parent.substr(1);
15958             this.parent = false;
15959             Roo.debug && Roo.log(ename);
15960             switch (ename) {
15961                 case 'bootstrap-body' :
15962                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15963                         this.parent = { el :  new  Roo.bootstrap.Body() };
15964                         Roo.debug && Roo.log("setting el to doc body");
15965                          
15966                     } else {
15967                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15968                     }
15969                     break;
15970                 case 'bootstrap':
15971                     this.parent = { el : true};
15972                     // fall through
15973                 default:
15974                     el = Roo.get(ename);
15975                     break;
15976             }
15977                 
15978             
15979             if (!el && !this.parent) {
15980                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15981                 return;
15982             }
15983         }
15984         Roo.debug && Roo.log("EL:");
15985         Roo.debug && Roo.log(el);
15986         Roo.debug && Roo.log("this.parent.el:");
15987         Roo.debug && Roo.log(this.parent.el);
15988         
15989         var tree = this._tree ? this._tree() : this.tree();
15990
15991         // altertive root elements ??? - we need a better way to indicate these.
15992         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15993                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15994         
15995         if (!this.parent && is_alt) {
15996             //el = Roo.get(document.body);
15997             this.parent = { el : true };
15998         }
15999             
16000             
16001         
16002         if (!this.parent) {
16003             
16004             Roo.debug && Roo.log("no parent - creating one");
16005             
16006             el = el ? Roo.get(el) : false;      
16007             
16008             // it's a top level one..
16009             this.parent =  {
16010                 el : new Roo.BorderLayout(el || document.body, {
16011                 
16012                      center: {
16013                          titlebar: false,
16014                          autoScroll:false,
16015                          closeOnTab: true,
16016                          tabPosition: 'top',
16017                           //resizeTabs: true,
16018                          alwaysShowTabs: el && hp? false :  true,
16019                          hideTabs: el || !hp ? true :  false,
16020                          minTabWidth: 140
16021                      }
16022                  })
16023             }
16024         }
16025         
16026         if (!this.parent.el) {
16027                 // probably an old style ctor, which has been disabled.
16028                 return;
16029
16030         }
16031                 // The 'tree' method is  '_tree now' 
16032             
16033         tree.region = tree.region || this.region;
16034         
16035         if (this.parent.el === true) {
16036             // bootstrap... - body..
16037             this.parent.el = Roo.factory(tree);
16038         }
16039         
16040         this.el = this.parent.el.addxtype(tree);
16041         this.fireEvent('built', this);
16042         
16043         this.panel = this.el;
16044         this.layout = this.panel.layout;
16045         this.parentLayout = this.parent.layout  || false;  
16046          
16047     }
16048     
16049 });
16050
16051 Roo.apply(Roo.XComponent, {
16052     /**
16053      * @property  hideProgress
16054      * true to disable the building progress bar.. usefull on single page renders.
16055      * @type Boolean
16056      */
16057     hideProgress : false,
16058     /**
16059      * @property  buildCompleted
16060      * True when the builder has completed building the interface.
16061      * @type Boolean
16062      */
16063     buildCompleted : false,
16064      
16065     /**
16066      * @property  topModule
16067      * the upper most module - uses document.element as it's constructor.
16068      * @type Object
16069      */
16070      
16071     topModule  : false,
16072       
16073     /**
16074      * @property  modules
16075      * array of modules to be created by registration system.
16076      * @type {Array} of Roo.XComponent
16077      */
16078     
16079     modules : [],
16080     /**
16081      * @property  elmodules
16082      * array of modules to be created by which use #ID 
16083      * @type {Array} of Roo.XComponent
16084      */
16085      
16086     elmodules : [],
16087
16088      /**
16089      * @property  build_from_html
16090      * Build elements from html - used by bootstrap HTML stuff 
16091      *    - this is cleared after build is completed
16092      * @type {boolean} true  (default false)
16093      */
16094      
16095     build_from_html : false,
16096
16097     /**
16098      * Register components to be built later.
16099      *
16100      * This solves the following issues
16101      * - Building is not done on page load, but after an authentication process has occured.
16102      * - Interface elements are registered on page load
16103      * - Parent Interface elements may not be loaded before child, so this handles that..
16104      * 
16105      *
16106      * example:
16107      * 
16108      * MyApp.register({
16109           order : '000001',
16110           module : 'Pman.Tab.projectMgr',
16111           region : 'center',
16112           parent : 'Pman.layout',
16113           disabled : false,  // or use a function..
16114         })
16115      
16116      * * @param {Object} details about module
16117      */
16118     register : function(obj) {
16119                 
16120         Roo.XComponent.event.fireEvent('register', obj);
16121         switch(typeof(obj.disabled) ) {
16122                 
16123             case 'undefined':
16124                 break;
16125             
16126             case 'function':
16127                 if ( obj.disabled() ) {
16128                         return;
16129                 }
16130                 break;
16131             
16132             default:
16133                 if (obj.disabled) {
16134                         return;
16135                 }
16136                 break;
16137         }
16138                 
16139         this.modules.push(obj);
16140          
16141     },
16142     /**
16143      * convert a string to an object..
16144      * eg. 'AAA.BBB' -> finds AAA.BBB
16145
16146      */
16147     
16148     toObject : function(str)
16149     {
16150         if (!str || typeof(str) == 'object') {
16151             return str;
16152         }
16153         if (str.substring(0,1) == '#') {
16154             return str;
16155         }
16156
16157         var ar = str.split('.');
16158         var rt, o;
16159         rt = ar.shift();
16160             /** eval:var:o */
16161         try {
16162             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16163         } catch (e) {
16164             throw "Module not found : " + str;
16165         }
16166         
16167         if (o === false) {
16168             throw "Module not found : " + str;
16169         }
16170         Roo.each(ar, function(e) {
16171             if (typeof(o[e]) == 'undefined') {
16172                 throw "Module not found : " + str;
16173             }
16174             o = o[e];
16175         });
16176         
16177         return o;
16178         
16179     },
16180     
16181     
16182     /**
16183      * move modules into their correct place in the tree..
16184      * 
16185      */
16186     preBuild : function ()
16187     {
16188         var _t = this;
16189         Roo.each(this.modules , function (obj)
16190         {
16191             Roo.XComponent.event.fireEvent('beforebuild', obj);
16192             
16193             var opar = obj.parent;
16194             try { 
16195                 obj.parent = this.toObject(opar);
16196             } catch(e) {
16197                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16198                 return;
16199             }
16200             
16201             if (!obj.parent) {
16202                 Roo.debug && Roo.log("GOT top level module");
16203                 Roo.debug && Roo.log(obj);
16204                 obj.modules = new Roo.util.MixedCollection(false, 
16205                     function(o) { return o.order + '' }
16206                 );
16207                 this.topModule = obj;
16208                 return;
16209             }
16210                         // parent is a string (usually a dom element name..)
16211             if (typeof(obj.parent) == 'string') {
16212                 this.elmodules.push(obj);
16213                 return;
16214             }
16215             if (obj.parent.constructor != Roo.XComponent) {
16216                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16217             }
16218             if (!obj.parent.modules) {
16219                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16220                     function(o) { return o.order + '' }
16221                 );
16222             }
16223             if (obj.parent.disabled) {
16224                 obj.disabled = true;
16225             }
16226             obj.parent.modules.add(obj);
16227         }, this);
16228     },
16229     
16230      /**
16231      * make a list of modules to build.
16232      * @return {Array} list of modules. 
16233      */ 
16234     
16235     buildOrder : function()
16236     {
16237         var _this = this;
16238         var cmp = function(a,b) {   
16239             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16240         };
16241         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16242             throw "No top level modules to build";
16243         }
16244         
16245         // make a flat list in order of modules to build.
16246         var mods = this.topModule ? [ this.topModule ] : [];
16247                 
16248         
16249         // elmodules (is a list of DOM based modules )
16250         Roo.each(this.elmodules, function(e) {
16251             mods.push(e);
16252             if (!this.topModule &&
16253                 typeof(e.parent) == 'string' &&
16254                 e.parent.substring(0,1) == '#' &&
16255                 Roo.get(e.parent.substr(1))
16256                ) {
16257                 
16258                 _this.topModule = e;
16259             }
16260             
16261         });
16262
16263         
16264         // add modules to their parents..
16265         var addMod = function(m) {
16266             Roo.debug && Roo.log("build Order: add: " + m.name);
16267                 
16268             mods.push(m);
16269             if (m.modules && !m.disabled) {
16270                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16271                 m.modules.keySort('ASC',  cmp );
16272                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16273     
16274                 m.modules.each(addMod);
16275             } else {
16276                 Roo.debug && Roo.log("build Order: no child modules");
16277             }
16278             // not sure if this is used any more..
16279             if (m.finalize) {
16280                 m.finalize.name = m.name + " (clean up) ";
16281                 mods.push(m.finalize);
16282             }
16283             
16284         }
16285         if (this.topModule && this.topModule.modules) { 
16286             this.topModule.modules.keySort('ASC',  cmp );
16287             this.topModule.modules.each(addMod);
16288         } 
16289         return mods;
16290     },
16291     
16292      /**
16293      * Build the registered modules.
16294      * @param {Object} parent element.
16295      * @param {Function} optional method to call after module has been added.
16296      * 
16297      */ 
16298    
16299     build : function(opts) 
16300     {
16301         
16302         if (typeof(opts) != 'undefined') {
16303             Roo.apply(this,opts);
16304         }
16305         
16306         this.preBuild();
16307         var mods = this.buildOrder();
16308       
16309         //this.allmods = mods;
16310         //Roo.debug && Roo.log(mods);
16311         //return;
16312         if (!mods.length) { // should not happen
16313             throw "NO modules!!!";
16314         }
16315         
16316         
16317         var msg = "Building Interface...";
16318         // flash it up as modal - so we store the mask!?
16319         if (!this.hideProgress && Roo.MessageBox) {
16320             Roo.MessageBox.show({ title: 'loading' });
16321             Roo.MessageBox.show({
16322                title: "Please wait...",
16323                msg: msg,
16324                width:450,
16325                progress:true,
16326                closable:false,
16327                modal: false
16328               
16329             });
16330         }
16331         var total = mods.length;
16332         
16333         var _this = this;
16334         var progressRun = function() {
16335             if (!mods.length) {
16336                 Roo.debug && Roo.log('hide?');
16337                 if (!this.hideProgress && Roo.MessageBox) {
16338                     Roo.MessageBox.hide();
16339                 }
16340                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16341                 
16342                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16343                 
16344                 // THE END...
16345                 return false;   
16346             }
16347             
16348             var m = mods.shift();
16349             
16350             
16351             Roo.debug && Roo.log(m);
16352             // not sure if this is supported any more.. - modules that are are just function
16353             if (typeof(m) == 'function') { 
16354                 m.call(this);
16355                 return progressRun.defer(10, _this);
16356             } 
16357             
16358             
16359             msg = "Building Interface " + (total  - mods.length) + 
16360                     " of " + total + 
16361                     (m.name ? (' - ' + m.name) : '');
16362                         Roo.debug && Roo.log(msg);
16363             if (!this.hideProgress &&  Roo.MessageBox) { 
16364                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16365             }
16366             
16367          
16368             // is the module disabled?
16369             var disabled = (typeof(m.disabled) == 'function') ?
16370                 m.disabled.call(m.module.disabled) : m.disabled;    
16371             
16372             
16373             if (disabled) {
16374                 return progressRun(); // we do not update the display!
16375             }
16376             
16377             // now build 
16378             
16379                         
16380                         
16381             m.render();
16382             // it's 10 on top level, and 1 on others??? why...
16383             return progressRun.defer(10, _this);
16384              
16385         }
16386         progressRun.defer(1, _this);
16387      
16388         
16389         
16390     },
16391         
16392         
16393         /**
16394          * Event Object.
16395          *
16396          *
16397          */
16398         event: false, 
16399     /**
16400          * wrapper for event.on - aliased later..  
16401          * Typically use to register a event handler for register:
16402          *
16403          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16404          *
16405          */
16406     on : false
16407    
16408     
16409     
16410 });
16411
16412 Roo.XComponent.event = new Roo.util.Observable({
16413                 events : { 
16414                         /**
16415                          * @event register
16416                          * Fires when an Component is registered,
16417                          * set the disable property on the Component to stop registration.
16418                          * @param {Roo.XComponent} c the component being registerd.
16419                          * 
16420                          */
16421                         'register' : true,
16422             /**
16423                          * @event beforebuild
16424                          * Fires before each Component is built
16425                          * can be used to apply permissions.
16426                          * @param {Roo.XComponent} c the component being registerd.
16427                          * 
16428                          */
16429                         'beforebuild' : true,
16430                         /**
16431                          * @event buildcomplete
16432                          * Fires on the top level element when all elements have been built
16433                          * @param {Roo.XComponent} the top level component.
16434                          */
16435                         'buildcomplete' : true
16436                         
16437                 }
16438 });
16439
16440 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16441