roojs-core-debug.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      * Checks whether or not the specified object exists in the array.
929      * @param {Object} o The object to check for
930      * @return {Number} The index of o in the array (or -1 if it is not found)
931      */
932     indexOf : function(o){
933        for (var i = 0, len = this.length; i < len; i++){
934               if(this[i] == o) return i;
935        }
936            return -1;
937     },
938
939     /**
940      * Removes the specified object from the array.  If the object is not found nothing happens.
941      * @param {Object} o The object to remove
942      */
943     remove : function(o){
944        var index = this.indexOf(o);
945        if(index != -1){
946            this.splice(index, 1);
947        }
948     },
949     /**
950      * Map (JS 1.6 compatibility)
951      * @param {Function} function  to call
952      */
953     map : function(fun )
954     {
955         var len = this.length >>> 0;
956         if (typeof fun != "function")
957             throw new TypeError();
958
959         var res = new Array(len);
960         var thisp = arguments[1];
961         for (var i = 0; i < len; i++)
962         {
963             if (i in this)
964                 res[i] = fun.call(thisp, this[i], i, this);
965         }
966
967         return res;
968     }
969     
970 });
971
972
973  /*
974  * Based on:
975  * Ext JS Library 1.1.1
976  * Copyright(c) 2006-2007, Ext JS, LLC.
977  *
978  * Originally Released Under LGPL - original licence link has changed is not relivant.
979  *
980  * Fork - LGPL
981  * <script type="text/javascript">
982  */
983
984 /**
985  * @class Date
986  *
987  * The date parsing and format syntax is a subset of
988  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
989  * supported will provide results equivalent to their PHP versions.
990  *
991  * Following is the list of all currently supported formats:
992  *<pre>
993 Sample date:
994 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
995
996 Format  Output      Description
997 ------  ----------  --------------------------------------------------------------
998   d      10         Day of the month, 2 digits with leading zeros
999   D      Wed        A textual representation of a day, three letters
1000   j      10         Day of the month without leading zeros
1001   l      Wednesday  A full textual representation of the day of the week
1002   S      th         English ordinal day of month suffix, 2 chars (use with j)
1003   w      3          Numeric representation of the day of the week
1004   z      9          The julian date, or day of the year (0-365)
1005   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1006   F      January    A full textual representation of the month
1007   m      01         Numeric representation of a month, with leading zeros
1008   M      Jan        Month name abbreviation, three letters
1009   n      1          Numeric representation of a month, without leading zeros
1010   t      31         Number of days in the given month
1011   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1012   Y      2007       A full numeric representation of a year, 4 digits
1013   y      07         A two digit representation of a year
1014   a      pm         Lowercase Ante meridiem and Post meridiem
1015   A      PM         Uppercase Ante meridiem and Post meridiem
1016   g      3          12-hour format of an hour without leading zeros
1017   G      15         24-hour format of an hour without leading zeros
1018   h      03         12-hour format of an hour with leading zeros
1019   H      15         24-hour format of an hour with leading zeros
1020   i      05         Minutes with leading zeros
1021   s      01         Seconds, with leading zeros
1022   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1023   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1024   T      CST        Timezone setting of the machine running the code
1025   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1026 </pre>
1027  *
1028  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1029  * <pre><code>
1030 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1031 document.write(dt.format('Y-m-d'));                         //2007-01-10
1032 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1033 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
1034  </code></pre>
1035  *
1036  * Here are some standard date/time patterns that you might find helpful.  They
1037  * are not part of the source of Date.js, but to use them you can simply copy this
1038  * block of code into any script that is included after Date.js and they will also become
1039  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1040  * <pre><code>
1041 Date.patterns = {
1042     ISO8601Long:"Y-m-d H:i:s",
1043     ISO8601Short:"Y-m-d",
1044     ShortDate: "n/j/Y",
1045     LongDate: "l, F d, Y",
1046     FullDateTime: "l, F d, Y g:i:s A",
1047     MonthDay: "F d",
1048     ShortTime: "g:i A",
1049     LongTime: "g:i:s A",
1050     SortableDateTime: "Y-m-d\\TH:i:s",
1051     UniversalSortableDateTime: "Y-m-d H:i:sO",
1052     YearMonth: "F, Y"
1053 };
1054 </code></pre>
1055  *
1056  * Example usage:
1057  * <pre><code>
1058 var dt = new Date();
1059 document.write(dt.format(Date.patterns.ShortDate));
1060  </code></pre>
1061  */
1062
1063 /*
1064  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1065  * They generate precompiled functions from date formats instead of parsing and
1066  * processing the pattern every time you format a date.  These functions are available
1067  * on every Date object (any javascript function).
1068  *
1069  * The original article and download are here:
1070  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1071  *
1072  */
1073  
1074  
1075  // was in core
1076 /**
1077  Returns the number of milliseconds between this date and date
1078  @param {Date} date (optional) Defaults to now
1079  @return {Number} The diff in milliseconds
1080  @member Date getElapsed
1081  */
1082 Date.prototype.getElapsed = function(date) {
1083         return Math.abs((date || new Date()).getTime()-this.getTime());
1084 };
1085 // was in date file..
1086
1087
1088 // private
1089 Date.parseFunctions = {count:0};
1090 // private
1091 Date.parseRegexes = [];
1092 // private
1093 Date.formatFunctions = {count:0};
1094
1095 // private
1096 Date.prototype.dateFormat = function(format) {
1097     if (Date.formatFunctions[format] == null) {
1098         Date.createNewFormat(format);
1099     }
1100     var func = Date.formatFunctions[format];
1101     return this[func]();
1102 };
1103
1104
1105 /**
1106  * Formats a date given the supplied format string
1107  * @param {String} format The format string
1108  * @return {String} The formatted date
1109  * @method
1110  */
1111 Date.prototype.format = Date.prototype.dateFormat;
1112
1113 // private
1114 Date.createNewFormat = function(format) {
1115     var funcName = "format" + Date.formatFunctions.count++;
1116     Date.formatFunctions[format] = funcName;
1117     var code = "Date.prototype." + funcName + " = function(){return ";
1118     var special = false;
1119     var ch = '';
1120     for (var i = 0; i < format.length; ++i) {
1121         ch = format.charAt(i);
1122         if (!special && ch == "\\") {
1123             special = true;
1124         }
1125         else if (special) {
1126             special = false;
1127             code += "'" + String.escape(ch) + "' + ";
1128         }
1129         else {
1130             code += Date.getFormatCode(ch);
1131         }
1132     }
1133     /** eval:var:zzzzzzzzzzzzz */
1134     eval(code.substring(0, code.length - 3) + ";}");
1135 };
1136
1137 // private
1138 Date.getFormatCode = function(character) {
1139     switch (character) {
1140     case "d":
1141         return "String.leftPad(this.getDate(), 2, '0') + ";
1142     case "D":
1143         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1144     case "j":
1145         return "this.getDate() + ";
1146     case "l":
1147         return "Date.dayNames[this.getDay()] + ";
1148     case "S":
1149         return "this.getSuffix() + ";
1150     case "w":
1151         return "this.getDay() + ";
1152     case "z":
1153         return "this.getDayOfYear() + ";
1154     case "W":
1155         return "this.getWeekOfYear() + ";
1156     case "F":
1157         return "Date.monthNames[this.getMonth()] + ";
1158     case "m":
1159         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1160     case "M":
1161         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1162     case "n":
1163         return "(this.getMonth() + 1) + ";
1164     case "t":
1165         return "this.getDaysInMonth() + ";
1166     case "L":
1167         return "(this.isLeapYear() ? 1 : 0) + ";
1168     case "Y":
1169         return "this.getFullYear() + ";
1170     case "y":
1171         return "('' + this.getFullYear()).substring(2, 4) + ";
1172     case "a":
1173         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1174     case "A":
1175         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1176     case "g":
1177         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1178     case "G":
1179         return "this.getHours() + ";
1180     case "h":
1181         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1182     case "H":
1183         return "String.leftPad(this.getHours(), 2, '0') + ";
1184     case "i":
1185         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1186     case "s":
1187         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1188     case "O":
1189         return "this.getGMTOffset() + ";
1190     case "P":
1191         return "this.getGMTColonOffset() + ";
1192     case "T":
1193         return "this.getTimezone() + ";
1194     case "Z":
1195         return "(this.getTimezoneOffset() * -60) + ";
1196     default:
1197         return "'" + String.escape(character) + "' + ";
1198     }
1199 };
1200
1201 /**
1202  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1203  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1204  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1205  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1206  * string or the parse operation will fail.
1207  * Example Usage:
1208 <pre><code>
1209 //dt = Fri May 25 2007 (current date)
1210 var dt = new Date();
1211
1212 //dt = Thu May 25 2006 (today's month/day in 2006)
1213 dt = Date.parseDate("2006", "Y");
1214
1215 //dt = Sun Jan 15 2006 (all date parts specified)
1216 dt = Date.parseDate("2006-1-15", "Y-m-d");
1217
1218 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1219 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1220 </code></pre>
1221  * @param {String} input The unparsed date as a string
1222  * @param {String} format The format the date is in
1223  * @return {Date} The parsed date
1224  * @static
1225  */
1226 Date.parseDate = function(input, format) {
1227     if (Date.parseFunctions[format] == null) {
1228         Date.createParser(format);
1229     }
1230     var func = Date.parseFunctions[format];
1231     return Date[func](input);
1232 };
1233 /**
1234  * @private
1235  */
1236 Date.createParser = function(format) {
1237     var funcName = "parse" + Date.parseFunctions.count++;
1238     var regexNum = Date.parseRegexes.length;
1239     var currentGroup = 1;
1240     Date.parseFunctions[format] = funcName;
1241
1242     var code = "Date." + funcName + " = function(input){\n"
1243         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1244         + "var d = new Date();\n"
1245         + "y = d.getFullYear();\n"
1246         + "m = d.getMonth();\n"
1247         + "d = d.getDate();\n"
1248         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1249         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1250         + "if (results && results.length > 0) {";
1251     var regex = "";
1252
1253     var special = false;
1254     var ch = '';
1255     for (var i = 0; i < format.length; ++i) {
1256         ch = format.charAt(i);
1257         if (!special && ch == "\\") {
1258             special = true;
1259         }
1260         else if (special) {
1261             special = false;
1262             regex += String.escape(ch);
1263         }
1264         else {
1265             var obj = Date.formatCodeToRegex(ch, currentGroup);
1266             currentGroup += obj.g;
1267             regex += obj.s;
1268             if (obj.g && obj.c) {
1269                 code += obj.c;
1270             }
1271         }
1272     }
1273
1274     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1275         + "{v = new Date(y, m, d, h, i, s);}\n"
1276         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1277         + "{v = new Date(y, m, d, h, i);}\n"
1278         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1279         + "{v = new Date(y, m, d, h);}\n"
1280         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1281         + "{v = new Date(y, m, d);}\n"
1282         + "else if (y >= 0 && m >= 0)\n"
1283         + "{v = new Date(y, m);}\n"
1284         + "else if (y >= 0)\n"
1285         + "{v = new Date(y);}\n"
1286         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1287         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1288         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1289         + ";}";
1290
1291     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1292     /** eval:var:zzzzzzzzzzzzz */
1293     eval(code);
1294 };
1295
1296 // private
1297 Date.formatCodeToRegex = function(character, currentGroup) {
1298     switch (character) {
1299     case "D":
1300         return {g:0,
1301         c:null,
1302         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1303     case "j":
1304         return {g:1,
1305             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1306             s:"(\\d{1,2})"}; // day of month without leading zeroes
1307     case "d":
1308         return {g:1,
1309             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1310             s:"(\\d{2})"}; // day of month with leading zeroes
1311     case "l":
1312         return {g:0,
1313             c:null,
1314             s:"(?:" + Date.dayNames.join("|") + ")"};
1315     case "S":
1316         return {g:0,
1317             c:null,
1318             s:"(?:st|nd|rd|th)"};
1319     case "w":
1320         return {g:0,
1321             c:null,
1322             s:"\\d"};
1323     case "z":
1324         return {g:0,
1325             c:null,
1326             s:"(?:\\d{1,3})"};
1327     case "W":
1328         return {g:0,
1329             c:null,
1330             s:"(?:\\d{2})"};
1331     case "F":
1332         return {g:1,
1333             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1334             s:"(" + Date.monthNames.join("|") + ")"};
1335     case "M":
1336         return {g:1,
1337             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1338             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1339     case "n":
1340         return {g:1,
1341             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1342             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1343     case "m":
1344         return {g:1,
1345             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1346             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1347     case "t":
1348         return {g:0,
1349             c:null,
1350             s:"\\d{1,2}"};
1351     case "L":
1352         return {g:0,
1353             c:null,
1354             s:"(?:1|0)"};
1355     case "Y":
1356         return {g:1,
1357             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1358             s:"(\\d{4})"};
1359     case "y":
1360         return {g:1,
1361             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1362                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1363             s:"(\\d{1,2})"};
1364     case "a":
1365         return {g:1,
1366             c:"if (results[" + currentGroup + "] == 'am') {\n"
1367                 + "if (h == 12) { h = 0; }\n"
1368                 + "} else { if (h < 12) { h += 12; }}",
1369             s:"(am|pm)"};
1370     case "A":
1371         return {g:1,
1372             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1373                 + "if (h == 12) { h = 0; }\n"
1374                 + "} else { if (h < 12) { h += 12; }}",
1375             s:"(AM|PM)"};
1376     case "g":
1377     case "G":
1378         return {g:1,
1379             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1380             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1381     case "h":
1382     case "H":
1383         return {g:1,
1384             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1385             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1386     case "i":
1387         return {g:1,
1388             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1389             s:"(\\d{2})"};
1390     case "s":
1391         return {g:1,
1392             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1393             s:"(\\d{2})"};
1394     case "O":
1395         return {g:1,
1396             c:[
1397                 "o = results[", currentGroup, "];\n",
1398                 "var sn = o.substring(0,1);\n", // get + / - sign
1399                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1400                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1401                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1402                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1403             ].join(""),
1404             s:"([+\-]\\d{2,4})"};
1405     
1406     
1407     case "P":
1408         return {g:1,
1409                 c:[
1410                    "o = results[", currentGroup, "];\n",
1411                    "var sn = o.substring(0,1);\n",
1412                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1413                    "var mn = o.substring(4,6) % 60;\n",
1414                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1415                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1416             ].join(""),
1417             s:"([+\-]\\d{4})"};
1418     case "T":
1419         return {g:0,
1420             c:null,
1421             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1422     case "Z":
1423         return {g:1,
1424             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1425                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1426             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1427     default:
1428         return {g:0,
1429             c:null,
1430             s:String.escape(character)};
1431     }
1432 };
1433
1434 /**
1435  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1436  * @return {String} The abbreviated timezone name (e.g. 'CST')
1437  */
1438 Date.prototype.getTimezone = function() {
1439     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1440 };
1441
1442 /**
1443  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1444  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1445  */
1446 Date.prototype.getGMTOffset = function() {
1447     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1448         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1449         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1450 };
1451
1452 /**
1453  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1454  * @return {String} 2-characters representing hours and 2-characters representing minutes
1455  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1456  */
1457 Date.prototype.getGMTColonOffset = function() {
1458         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1459                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1460                 + ":"
1461                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1462 }
1463
1464 /**
1465  * Get the numeric day number of the year, adjusted for leap year.
1466  * @return {Number} 0 through 364 (365 in leap years)
1467  */
1468 Date.prototype.getDayOfYear = function() {
1469     var num = 0;
1470     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1471     for (var i = 0; i < this.getMonth(); ++i) {
1472         num += Date.daysInMonth[i];
1473     }
1474     return num + this.getDate() - 1;
1475 };
1476
1477 /**
1478  * Get the string representation of the numeric week number of the year
1479  * (equivalent to the format specifier 'W').
1480  * @return {String} '00' through '52'
1481  */
1482 Date.prototype.getWeekOfYear = function() {
1483     // Skip to Thursday of this week
1484     var now = this.getDayOfYear() + (4 - this.getDay());
1485     // Find the first Thursday of the year
1486     var jan1 = new Date(this.getFullYear(), 0, 1);
1487     var then = (7 - jan1.getDay() + 4);
1488     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1489 };
1490
1491 /**
1492  * Whether or not the current date is in a leap year.
1493  * @return {Boolean} True if the current date is in a leap year, else false
1494  */
1495 Date.prototype.isLeapYear = function() {
1496     var year = this.getFullYear();
1497     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1498 };
1499
1500 /**
1501  * Get the first day of the current month, adjusted for leap year.  The returned value
1502  * is the numeric day index within the week (0-6) which can be used in conjunction with
1503  * the {@link #monthNames} array to retrieve the textual day name.
1504  * Example:
1505  *<pre><code>
1506 var dt = new Date('1/10/2007');
1507 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1508 </code></pre>
1509  * @return {Number} The day number (0-6)
1510  */
1511 Date.prototype.getFirstDayOfMonth = function() {
1512     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1513     return (day < 0) ? (day + 7) : day;
1514 };
1515
1516 /**
1517  * Get the last day of the current month, adjusted for leap year.  The returned value
1518  * is the numeric day index within the week (0-6) which can be used in conjunction with
1519  * the {@link #monthNames} array to retrieve the textual day name.
1520  * Example:
1521  *<pre><code>
1522 var dt = new Date('1/10/2007');
1523 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1524 </code></pre>
1525  * @return {Number} The day number (0-6)
1526  */
1527 Date.prototype.getLastDayOfMonth = function() {
1528     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1529     return (day < 0) ? (day + 7) : day;
1530 };
1531
1532
1533 /**
1534  * Get the first date of this date's month
1535  * @return {Date}
1536  */
1537 Date.prototype.getFirstDateOfMonth = function() {
1538     return new Date(this.getFullYear(), this.getMonth(), 1);
1539 };
1540
1541 /**
1542  * Get the last date of this date's month
1543  * @return {Date}
1544  */
1545 Date.prototype.getLastDateOfMonth = function() {
1546     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1547 };
1548 /**
1549  * Get the number of days in the current month, adjusted for leap year.
1550  * @return {Number} The number of days in the month
1551  */
1552 Date.prototype.getDaysInMonth = function() {
1553     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1554     return Date.daysInMonth[this.getMonth()];
1555 };
1556
1557 /**
1558  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1559  * @return {String} 'st, 'nd', 'rd' or 'th'
1560  */
1561 Date.prototype.getSuffix = function() {
1562     switch (this.getDate()) {
1563         case 1:
1564         case 21:
1565         case 31:
1566             return "st";
1567         case 2:
1568         case 22:
1569             return "nd";
1570         case 3:
1571         case 23:
1572             return "rd";
1573         default:
1574             return "th";
1575     }
1576 };
1577
1578 // private
1579 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1580
1581 /**
1582  * An array of textual month names.
1583  * Override these values for international dates, for example...
1584  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1585  * @type Array
1586  * @static
1587  */
1588 Date.monthNames =
1589    ["January",
1590     "February",
1591     "March",
1592     "April",
1593     "May",
1594     "June",
1595     "July",
1596     "August",
1597     "September",
1598     "October",
1599     "November",
1600     "December"];
1601
1602 /**
1603  * An array of textual day names.
1604  * Override these values for international dates, for example...
1605  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1606  * @type Array
1607  * @static
1608  */
1609 Date.dayNames =
1610    ["Sunday",
1611     "Monday",
1612     "Tuesday",
1613     "Wednesday",
1614     "Thursday",
1615     "Friday",
1616     "Saturday"];
1617
1618 // private
1619 Date.y2kYear = 50;
1620 // private
1621 Date.monthNumbers = {
1622     Jan:0,
1623     Feb:1,
1624     Mar:2,
1625     Apr:3,
1626     May:4,
1627     Jun:5,
1628     Jul:6,
1629     Aug:7,
1630     Sep:8,
1631     Oct:9,
1632     Nov:10,
1633     Dec:11};
1634
1635 /**
1636  * Creates and returns a new Date instance with the exact same date value as the called instance.
1637  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1638  * variable will also be changed.  When the intention is to create a new variable that will not
1639  * modify the original instance, you should create a clone.
1640  *
1641  * Example of correctly cloning a date:
1642  * <pre><code>
1643 //wrong way:
1644 var orig = new Date('10/1/2006');
1645 var copy = orig;
1646 copy.setDate(5);
1647 document.write(orig);  //returns 'Thu Oct 05 2006'!
1648
1649 //correct way:
1650 var orig = new Date('10/1/2006');
1651 var copy = orig.clone();
1652 copy.setDate(5);
1653 document.write(orig);  //returns 'Thu Oct 01 2006'
1654 </code></pre>
1655  * @return {Date} The new Date instance
1656  */
1657 Date.prototype.clone = function() {
1658         return new Date(this.getTime());
1659 };
1660
1661 /**
1662  * Clears any time information from this date
1663  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1664  @return {Date} this or the clone
1665  */
1666 Date.prototype.clearTime = function(clone){
1667     if(clone){
1668         return this.clone().clearTime();
1669     }
1670     this.setHours(0);
1671     this.setMinutes(0);
1672     this.setSeconds(0);
1673     this.setMilliseconds(0);
1674     return this;
1675 };
1676
1677 // private
1678 // safari setMonth is broken
1679 if(Roo.isSafari){
1680     Date.brokenSetMonth = Date.prototype.setMonth;
1681         Date.prototype.setMonth = function(num){
1682                 if(num <= -1){
1683                         var n = Math.ceil(-num);
1684                         var back_year = Math.ceil(n/12);
1685                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1686                         this.setFullYear(this.getFullYear() - back_year);
1687                         return Date.brokenSetMonth.call(this, month);
1688                 } else {
1689                         return Date.brokenSetMonth.apply(this, arguments);
1690                 }
1691         };
1692 }
1693
1694 /** Date interval constant 
1695 * @static 
1696 * @type String */
1697 Date.MILLI = "ms";
1698 /** Date interval constant 
1699 * @static 
1700 * @type String */
1701 Date.SECOND = "s";
1702 /** Date interval constant 
1703 * @static 
1704 * @type String */
1705 Date.MINUTE = "mi";
1706 /** Date interval constant 
1707 * @static 
1708 * @type String */
1709 Date.HOUR = "h";
1710 /** Date interval constant 
1711 * @static 
1712 * @type String */
1713 Date.DAY = "d";
1714 /** Date interval constant 
1715 * @static 
1716 * @type String */
1717 Date.MONTH = "mo";
1718 /** Date interval constant 
1719 * @static 
1720 * @type String */
1721 Date.YEAR = "y";
1722
1723 /**
1724  * Provides a convenient method of performing basic date arithmetic.  This method
1725  * does not modify the Date instance being called - it creates and returns
1726  * a new Date instance containing the resulting date value.
1727  *
1728  * Examples:
1729  * <pre><code>
1730 //Basic usage:
1731 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1732 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1733
1734 //Negative values will subtract correctly:
1735 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1736 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1737
1738 //You can even chain several calls together in one line!
1739 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1740 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1741  </code></pre>
1742  *
1743  * @param {String} interval   A valid date interval enum value
1744  * @param {Number} value      The amount to add to the current date
1745  * @return {Date} The new Date instance
1746  */
1747 Date.prototype.add = function(interval, value){
1748   var d = this.clone();
1749   if (!interval || value === 0) return d;
1750   switch(interval.toLowerCase()){
1751     case Date.MILLI:
1752       d.setMilliseconds(this.getMilliseconds() + value);
1753       break;
1754     case Date.SECOND:
1755       d.setSeconds(this.getSeconds() + value);
1756       break;
1757     case Date.MINUTE:
1758       d.setMinutes(this.getMinutes() + value);
1759       break;
1760     case Date.HOUR:
1761       d.setHours(this.getHours() + value);
1762       break;
1763     case Date.DAY:
1764       d.setDate(this.getDate() + value);
1765       break;
1766     case Date.MONTH:
1767       var day = this.getDate();
1768       if(day > 28){
1769           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1770       }
1771       d.setDate(day);
1772       d.setMonth(this.getMonth() + value);
1773       break;
1774     case Date.YEAR:
1775       d.setFullYear(this.getFullYear() + value);
1776       break;
1777   }
1778   return d;
1779 };
1780 /*
1781  * Based on:
1782  * Ext JS Library 1.1.1
1783  * Copyright(c) 2006-2007, Ext JS, LLC.
1784  *
1785  * Originally Released Under LGPL - original licence link has changed is not relivant.
1786  *
1787  * Fork - LGPL
1788  * <script type="text/javascript">
1789  */
1790
1791 /**
1792  * @class Roo.lib.Dom
1793  * @static
1794  * 
1795  * Dom utils (from YIU afaik)
1796  * 
1797  **/
1798 Roo.lib.Dom = {
1799     /**
1800      * Get the view width
1801      * @param {Boolean} full True will get the full document, otherwise it's the view width
1802      * @return {Number} The width
1803      */
1804      
1805     getViewWidth : function(full) {
1806         return full ? this.getDocumentWidth() : this.getViewportWidth();
1807     },
1808     /**
1809      * Get the view height
1810      * @param {Boolean} full True will get the full document, otherwise it's the view height
1811      * @return {Number} The height
1812      */
1813     getViewHeight : function(full) {
1814         return full ? this.getDocumentHeight() : this.getViewportHeight();
1815     },
1816
1817     getDocumentHeight: function() {
1818         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1819         return Math.max(scrollHeight, this.getViewportHeight());
1820     },
1821
1822     getDocumentWidth: function() {
1823         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1824         return Math.max(scrollWidth, this.getViewportWidth());
1825     },
1826
1827     getViewportHeight: function() {
1828         var height = self.innerHeight;
1829         var mode = document.compatMode;
1830
1831         if ((mode || Roo.isIE) && !Roo.isOpera) {
1832             height = (mode == "CSS1Compat") ?
1833                      document.documentElement.clientHeight :
1834                      document.body.clientHeight;
1835         }
1836
1837         return height;
1838     },
1839
1840     getViewportWidth: function() {
1841         var width = self.innerWidth;
1842         var mode = document.compatMode;
1843
1844         if (mode || Roo.isIE) {
1845             width = (mode == "CSS1Compat") ?
1846                     document.documentElement.clientWidth :
1847                     document.body.clientWidth;
1848         }
1849         return width;
1850     },
1851
1852     isAncestor : function(p, c) {
1853         p = Roo.getDom(p);
1854         c = Roo.getDom(c);
1855         if (!p || !c) {
1856             return false;
1857         }
1858
1859         if (p.contains && !Roo.isSafari) {
1860             return p.contains(c);
1861         } else if (p.compareDocumentPosition) {
1862             return !!(p.compareDocumentPosition(c) & 16);
1863         } else {
1864             var parent = c.parentNode;
1865             while (parent) {
1866                 if (parent == p) {
1867                     return true;
1868                 }
1869                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1870                     return false;
1871                 }
1872                 parent = parent.parentNode;
1873             }
1874             return false;
1875         }
1876     },
1877
1878     getRegion : function(el) {
1879         return Roo.lib.Region.getRegion(el);
1880     },
1881
1882     getY : function(el) {
1883         return this.getXY(el)[1];
1884     },
1885
1886     getX : function(el) {
1887         return this.getXY(el)[0];
1888     },
1889
1890     getXY : function(el) {
1891         var p, pe, b, scroll, bd = document.body;
1892         el = Roo.getDom(el);
1893         var fly = Roo.lib.AnimBase.fly;
1894         if (el.getBoundingClientRect) {
1895             b = el.getBoundingClientRect();
1896             scroll = fly(document).getScroll();
1897             return [b.left + scroll.left, b.top + scroll.top];
1898         }
1899         var x = 0, y = 0;
1900
1901         p = el;
1902
1903         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1904
1905         while (p) {
1906
1907             x += p.offsetLeft;
1908             y += p.offsetTop;
1909
1910             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1911                 hasAbsolute = true;
1912             }
1913
1914             if (Roo.isGecko) {
1915                 pe = fly(p);
1916
1917                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1918                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1919
1920
1921                 x += bl;
1922                 y += bt;
1923
1924
1925                 if (p != el && pe.getStyle('overflow') != 'visible') {
1926                     x += bl;
1927                     y += bt;
1928                 }
1929             }
1930             p = p.offsetParent;
1931         }
1932
1933         if (Roo.isSafari && hasAbsolute) {
1934             x -= bd.offsetLeft;
1935             y -= bd.offsetTop;
1936         }
1937
1938         if (Roo.isGecko && !hasAbsolute) {
1939             var dbd = fly(bd);
1940             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1941             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1942         }
1943
1944         p = el.parentNode;
1945         while (p && p != bd) {
1946             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1947                 x -= p.scrollLeft;
1948                 y -= p.scrollTop;
1949             }
1950             p = p.parentNode;
1951         }
1952         return [x, y];
1953     },
1954  
1955   
1956
1957
1958     setXY : function(el, xy) {
1959         el = Roo.fly(el, '_setXY');
1960         el.position();
1961         var pts = el.translatePoints(xy);
1962         if (xy[0] !== false) {
1963             el.dom.style.left = pts.left + "px";
1964         }
1965         if (xy[1] !== false) {
1966             el.dom.style.top = pts.top + "px";
1967         }
1968     },
1969
1970     setX : function(el, x) {
1971         this.setXY(el, [x, false]);
1972     },
1973
1974     setY : function(el, y) {
1975         this.setXY(el, [false, y]);
1976     }
1977 };
1978 /*
1979  * Portions of this file are based on pieces of Yahoo User Interface Library
1980  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1981  * YUI licensed under the BSD License:
1982  * http://developer.yahoo.net/yui/license.txt
1983  * <script type="text/javascript">
1984  *
1985  */
1986
1987 Roo.lib.Event = function() {
1988     var loadComplete = false;
1989     var listeners = [];
1990     var unloadListeners = [];
1991     var retryCount = 0;
1992     var onAvailStack = [];
1993     var counter = 0;
1994     var lastError = null;
1995
1996     return {
1997         POLL_RETRYS: 200,
1998         POLL_INTERVAL: 20,
1999         EL: 0,
2000         TYPE: 1,
2001         FN: 2,
2002         WFN: 3,
2003         OBJ: 3,
2004         ADJ_SCOPE: 4,
2005         _interval: null,
2006
2007         startInterval: function() {
2008             if (!this._interval) {
2009                 var self = this;
2010                 var callback = function() {
2011                     self._tryPreloadAttach();
2012                 };
2013                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2014
2015             }
2016         },
2017
2018         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2019             onAvailStack.push({ id:         p_id,
2020                 fn:         p_fn,
2021                 obj:        p_obj,
2022                 override:   p_override,
2023                 checkReady: false    });
2024
2025             retryCount = this.POLL_RETRYS;
2026             this.startInterval();
2027         },
2028
2029
2030         addListener: function(el, eventName, fn) {
2031             el = Roo.getDom(el);
2032             if (!el || !fn) {
2033                 return false;
2034             }
2035
2036             if ("unload" == eventName) {
2037                 unloadListeners[unloadListeners.length] =
2038                 [el, eventName, fn];
2039                 return true;
2040             }
2041
2042             var wrappedFn = function(e) {
2043                 return fn(Roo.lib.Event.getEvent(e));
2044             };
2045
2046             var li = [el, eventName, fn, wrappedFn];
2047
2048             var index = listeners.length;
2049             listeners[index] = li;
2050
2051             this.doAdd(el, eventName, wrappedFn, false);
2052             return true;
2053
2054         },
2055
2056
2057         removeListener: function(el, eventName, fn) {
2058             var i, len;
2059
2060             el = Roo.getDom(el);
2061
2062             if(!fn) {
2063                 return this.purgeElement(el, false, eventName);
2064             }
2065
2066
2067             if ("unload" == eventName) {
2068
2069                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2070                     var li = unloadListeners[i];
2071                     if (li &&
2072                         li[0] == el &&
2073                         li[1] == eventName &&
2074                         li[2] == fn) {
2075                         unloadListeners.splice(i, 1);
2076                         return true;
2077                     }
2078                 }
2079
2080                 return false;
2081             }
2082
2083             var cacheItem = null;
2084
2085
2086             var index = arguments[3];
2087
2088             if ("undefined" == typeof index) {
2089                 index = this._getCacheIndex(el, eventName, fn);
2090             }
2091
2092             if (index >= 0) {
2093                 cacheItem = listeners[index];
2094             }
2095
2096             if (!el || !cacheItem) {
2097                 return false;
2098             }
2099
2100             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2101
2102             delete listeners[index][this.WFN];
2103             delete listeners[index][this.FN];
2104             listeners.splice(index, 1);
2105
2106             return true;
2107
2108         },
2109
2110
2111         getTarget: function(ev, resolveTextNode) {
2112             ev = ev.browserEvent || ev;
2113             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2114             var t = ev.target || ev.srcElement;
2115             return this.resolveTextNode(t);
2116         },
2117
2118
2119         resolveTextNode: function(node) {
2120             if (Roo.isSafari && node && 3 == node.nodeType) {
2121                 return node.parentNode;
2122             } else {
2123                 return node;
2124             }
2125         },
2126
2127
2128         getPageX: function(ev) {
2129             ev = ev.browserEvent || ev;
2130             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2131             var x = ev.pageX;
2132             if (!x && 0 !== x) {
2133                 x = ev.clientX || 0;
2134
2135                 if (Roo.isIE) {
2136                     x += this.getScroll()[1];
2137                 }
2138             }
2139
2140             return x;
2141         },
2142
2143
2144         getPageY: function(ev) {
2145             ev = ev.browserEvent || ev;
2146             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2147             var y = ev.pageY;
2148             if (!y && 0 !== y) {
2149                 y = ev.clientY || 0;
2150
2151                 if (Roo.isIE) {
2152                     y += this.getScroll()[0];
2153                 }
2154             }
2155
2156
2157             return y;
2158         },
2159
2160
2161         getXY: function(ev) {
2162             ev = ev.browserEvent || ev;
2163             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2164             return [this.getPageX(ev), this.getPageY(ev)];
2165         },
2166
2167
2168         getRelatedTarget: function(ev) {
2169             ev = ev.browserEvent || ev;
2170             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2171             var t = ev.relatedTarget;
2172             if (!t) {
2173                 if (ev.type == "mouseout") {
2174                     t = ev.toElement;
2175                 } else if (ev.type == "mouseover") {
2176                     t = ev.fromElement;
2177                 }
2178             }
2179
2180             return this.resolveTextNode(t);
2181         },
2182
2183
2184         getTime: function(ev) {
2185             ev = ev.browserEvent || ev;
2186             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2187             if (!ev.time) {
2188                 var t = new Date().getTime();
2189                 try {
2190                     ev.time = t;
2191                 } catch(ex) {
2192                     this.lastError = ex;
2193                     return t;
2194                 }
2195             }
2196
2197             return ev.time;
2198         },
2199
2200
2201         stopEvent: function(ev) {
2202             this.stopPropagation(ev);
2203             this.preventDefault(ev);
2204         },
2205
2206
2207         stopPropagation: function(ev) {
2208             ev = ev.browserEvent || ev;
2209             if (ev.stopPropagation) {
2210                 ev.stopPropagation();
2211             } else {
2212                 ev.cancelBubble = true;
2213             }
2214         },
2215
2216
2217         preventDefault: function(ev) {
2218             ev = ev.browserEvent || ev;
2219             if(ev.preventDefault) {
2220                 ev.preventDefault();
2221             } else {
2222                 ev.returnValue = false;
2223             }
2224         },
2225
2226
2227         getEvent: function(e) {
2228             var ev = e || window.event;
2229             if (!ev) {
2230                 var c = this.getEvent.caller;
2231                 while (c) {
2232                     ev = c.arguments[0];
2233                     if (ev && Event == ev.constructor) {
2234                         break;
2235                     }
2236                     c = c.caller;
2237                 }
2238             }
2239             return ev;
2240         },
2241
2242
2243         getCharCode: function(ev) {
2244             ev = ev.browserEvent || ev;
2245             return ev.charCode || ev.keyCode || 0;
2246         },
2247
2248
2249         _getCacheIndex: function(el, eventName, fn) {
2250             for (var i = 0,len = listeners.length; i < len; ++i) {
2251                 var li = listeners[i];
2252                 if (li &&
2253                     li[this.FN] == fn &&
2254                     li[this.EL] == el &&
2255                     li[this.TYPE] == eventName) {
2256                     return i;
2257                 }
2258             }
2259
2260             return -1;
2261         },
2262
2263
2264         elCache: {},
2265
2266
2267         getEl: function(id) {
2268             return document.getElementById(id);
2269         },
2270
2271
2272         clearCache: function() {
2273         },
2274
2275
2276         _load: function(e) {
2277             loadComplete = true;
2278             var EU = Roo.lib.Event;
2279
2280
2281             if (Roo.isIE) {
2282                 EU.doRemove(window, "load", EU._load);
2283             }
2284         },
2285
2286
2287         _tryPreloadAttach: function() {
2288
2289             if (this.locked) {
2290                 return false;
2291             }
2292
2293             this.locked = true;
2294
2295
2296             var tryAgain = !loadComplete;
2297             if (!tryAgain) {
2298                 tryAgain = (retryCount > 0);
2299             }
2300
2301
2302             var notAvail = [];
2303             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2304                 var item = onAvailStack[i];
2305                 if (item) {
2306                     var el = this.getEl(item.id);
2307
2308                     if (el) {
2309                         if (!item.checkReady ||
2310                             loadComplete ||
2311                             el.nextSibling ||
2312                             (document && document.body)) {
2313
2314                             var scope = el;
2315                             if (item.override) {
2316                                 if (item.override === true) {
2317                                     scope = item.obj;
2318                                 } else {
2319                                     scope = item.override;
2320                                 }
2321                             }
2322                             item.fn.call(scope, item.obj);
2323                             onAvailStack[i] = null;
2324                         }
2325                     } else {
2326                         notAvail.push(item);
2327                     }
2328                 }
2329             }
2330
2331             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2332
2333             if (tryAgain) {
2334
2335                 this.startInterval();
2336             } else {
2337                 clearInterval(this._interval);
2338                 this._interval = null;
2339             }
2340
2341             this.locked = false;
2342
2343             return true;
2344
2345         },
2346
2347
2348         purgeElement: function(el, recurse, eventName) {
2349             var elListeners = this.getListeners(el, eventName);
2350             if (elListeners) {
2351                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2352                     var l = elListeners[i];
2353                     this.removeListener(el, l.type, l.fn);
2354                 }
2355             }
2356
2357             if (recurse && el && el.childNodes) {
2358                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2359                     this.purgeElement(el.childNodes[i], recurse, eventName);
2360                 }
2361             }
2362         },
2363
2364
2365         getListeners: function(el, eventName) {
2366             var results = [], searchLists;
2367             if (!eventName) {
2368                 searchLists = [listeners, unloadListeners];
2369             } else if (eventName == "unload") {
2370                 searchLists = [unloadListeners];
2371             } else {
2372                 searchLists = [listeners];
2373             }
2374
2375             for (var j = 0; j < searchLists.length; ++j) {
2376                 var searchList = searchLists[j];
2377                 if (searchList && searchList.length > 0) {
2378                     for (var i = 0,len = searchList.length; i < len; ++i) {
2379                         var l = searchList[i];
2380                         if (l && l[this.EL] === el &&
2381                             (!eventName || eventName === l[this.TYPE])) {
2382                             results.push({
2383                                 type:   l[this.TYPE],
2384                                 fn:     l[this.FN],
2385                                 obj:    l[this.OBJ],
2386                                 adjust: l[this.ADJ_SCOPE],
2387                                 index:  i
2388                             });
2389                         }
2390                     }
2391                 }
2392             }
2393
2394             return (results.length) ? results : null;
2395         },
2396
2397
2398         _unload: function(e) {
2399
2400             var EU = Roo.lib.Event, i, j, l, len, index;
2401
2402             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2403                 l = unloadListeners[i];
2404                 if (l) {
2405                     var scope = window;
2406                     if (l[EU.ADJ_SCOPE]) {
2407                         if (l[EU.ADJ_SCOPE] === true) {
2408                             scope = l[EU.OBJ];
2409                         } else {
2410                             scope = l[EU.ADJ_SCOPE];
2411                         }
2412                     }
2413                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2414                     unloadListeners[i] = null;
2415                     l = null;
2416                     scope = null;
2417                 }
2418             }
2419
2420             unloadListeners = null;
2421
2422             if (listeners && listeners.length > 0) {
2423                 j = listeners.length;
2424                 while (j) {
2425                     index = j - 1;
2426                     l = listeners[index];
2427                     if (l) {
2428                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2429                                 l[EU.FN], index);
2430                     }
2431                     j = j - 1;
2432                 }
2433                 l = null;
2434
2435                 EU.clearCache();
2436             }
2437
2438             EU.doRemove(window, "unload", EU._unload);
2439
2440         },
2441
2442
2443         getScroll: function() {
2444             var dd = document.documentElement, db = document.body;
2445             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2446                 return [dd.scrollTop, dd.scrollLeft];
2447             } else if (db) {
2448                 return [db.scrollTop, db.scrollLeft];
2449             } else {
2450                 return [0, 0];
2451             }
2452         },
2453
2454
2455         doAdd: function () {
2456             if (window.addEventListener) {
2457                 return function(el, eventName, fn, capture) {
2458                     el.addEventListener(eventName, fn, (capture));
2459                 };
2460             } else if (window.attachEvent) {
2461                 return function(el, eventName, fn, capture) {
2462                     el.attachEvent("on" + eventName, fn);
2463                 };
2464             } else {
2465                 return function() {
2466                 };
2467             }
2468         }(),
2469
2470
2471         doRemove: function() {
2472             if (window.removeEventListener) {
2473                 return function (el, eventName, fn, capture) {
2474                     el.removeEventListener(eventName, fn, (capture));
2475                 };
2476             } else if (window.detachEvent) {
2477                 return function (el, eventName, fn) {
2478                     el.detachEvent("on" + eventName, fn);
2479                 };
2480             } else {
2481                 return function() {
2482                 };
2483             }
2484         }()
2485     };
2486     
2487 }();
2488 (function() {     
2489    
2490     var E = Roo.lib.Event;
2491     E.on = E.addListener;
2492     E.un = E.removeListener;
2493
2494     if (document && document.body) {
2495         E._load();
2496     } else {
2497         E.doAdd(window, "load", E._load);
2498     }
2499     E.doAdd(window, "unload", E._unload);
2500     E._tryPreloadAttach();
2501 })();
2502
2503 /*
2504  * Portions of this file are based on pieces of Yahoo User Interface Library
2505  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2506  * YUI licensed under the BSD License:
2507  * http://developer.yahoo.net/yui/license.txt
2508  * <script type="text/javascript">
2509  *
2510  */
2511
2512 (function() {
2513     /**
2514      * @class Roo.lib.Ajax
2515      *
2516      */
2517     Roo.lib.Ajax = {
2518         /**
2519          * @static 
2520          */
2521         request : function(method, uri, cb, data, options) {
2522             if(options){
2523                 var hs = options.headers;
2524                 if(hs){
2525                     for(var h in hs){
2526                         if(hs.hasOwnProperty(h)){
2527                             this.initHeader(h, hs[h], false);
2528                         }
2529                     }
2530                 }
2531                 if(options.xmlData){
2532                     this.initHeader('Content-Type', 'text/xml', false);
2533                     method = 'POST';
2534                     data = options.xmlData;
2535                 }
2536             }
2537
2538             return this.asyncRequest(method, uri, cb, data);
2539         },
2540
2541         serializeForm : function(form) {
2542             if(typeof form == 'string') {
2543                 form = (document.getElementById(form) || document.forms[form]);
2544             }
2545
2546             var el, name, val, disabled, data = '', hasSubmit = false;
2547             for (var i = 0; i < form.elements.length; i++) {
2548                 el = form.elements[i];
2549                 disabled = form.elements[i].disabled;
2550                 name = form.elements[i].name;
2551                 val = form.elements[i].value;
2552
2553                 if (!disabled && name){
2554                     switch (el.type)
2555                             {
2556                         case 'select-one':
2557                         case 'select-multiple':
2558                             for (var j = 0; j < el.options.length; j++) {
2559                                 if (el.options[j].selected) {
2560                                     if (Roo.isIE) {
2561                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2562                                     }
2563                                     else {
2564                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2565                                     }
2566                                 }
2567                             }
2568                             break;
2569                         case 'radio':
2570                         case 'checkbox':
2571                             if (el.checked) {
2572                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2573                             }
2574                             break;
2575                         case 'file':
2576
2577                         case undefined:
2578
2579                         case 'reset':
2580
2581                         case 'button':
2582
2583                             break;
2584                         case 'submit':
2585                             if(hasSubmit == false) {
2586                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2587                                 hasSubmit = true;
2588                             }
2589                             break;
2590                         default:
2591                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2592                             break;
2593                     }
2594                 }
2595             }
2596             data = data.substr(0, data.length - 1);
2597             return data;
2598         },
2599
2600         headers:{},
2601
2602         hasHeaders:false,
2603
2604         useDefaultHeader:true,
2605
2606         defaultPostHeader:'application/x-www-form-urlencoded',
2607
2608         useDefaultXhrHeader:true,
2609
2610         defaultXhrHeader:'XMLHttpRequest',
2611
2612         hasDefaultHeaders:true,
2613
2614         defaultHeaders:{},
2615
2616         poll:{},
2617
2618         timeout:{},
2619
2620         pollInterval:50,
2621
2622         transactionId:0,
2623
2624         setProgId:function(id)
2625         {
2626             this.activeX.unshift(id);
2627         },
2628
2629         setDefaultPostHeader:function(b)
2630         {
2631             this.useDefaultHeader = b;
2632         },
2633
2634         setDefaultXhrHeader:function(b)
2635         {
2636             this.useDefaultXhrHeader = b;
2637         },
2638
2639         setPollingInterval:function(i)
2640         {
2641             if (typeof i == 'number' && isFinite(i)) {
2642                 this.pollInterval = i;
2643             }
2644         },
2645
2646         createXhrObject:function(transactionId)
2647         {
2648             var obj,http;
2649             try
2650             {
2651
2652                 http = new XMLHttpRequest();
2653
2654                 obj = { conn:http, tId:transactionId };
2655             }
2656             catch(e)
2657             {
2658                 for (var i = 0; i < this.activeX.length; ++i) {
2659                     try
2660                     {
2661
2662                         http = new ActiveXObject(this.activeX[i]);
2663
2664                         obj = { conn:http, tId:transactionId };
2665                         break;
2666                     }
2667                     catch(e) {
2668                     }
2669                 }
2670             }
2671             finally
2672             {
2673                 return obj;
2674             }
2675         },
2676
2677         getConnectionObject:function()
2678         {
2679             var o;
2680             var tId = this.transactionId;
2681
2682             try
2683             {
2684                 o = this.createXhrObject(tId);
2685                 if (o) {
2686                     this.transactionId++;
2687                 }
2688             }
2689             catch(e) {
2690             }
2691             finally
2692             {
2693                 return o;
2694             }
2695         },
2696
2697         asyncRequest:function(method, uri, callback, postData)
2698         {
2699             var o = this.getConnectionObject();
2700
2701             if (!o) {
2702                 return null;
2703             }
2704             else {
2705                 o.conn.open(method, uri, true);
2706
2707                 if (this.useDefaultXhrHeader) {
2708                     if (!this.defaultHeaders['X-Requested-With']) {
2709                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2710                     }
2711                 }
2712
2713                 if(postData && this.useDefaultHeader){
2714                     this.initHeader('Content-Type', this.defaultPostHeader);
2715                 }
2716
2717                  if (this.hasDefaultHeaders || this.hasHeaders) {
2718                     this.setHeader(o);
2719                 }
2720
2721                 this.handleReadyState(o, callback);
2722                 o.conn.send(postData || null);
2723
2724                 return o;
2725             }
2726         },
2727
2728         handleReadyState:function(o, callback)
2729         {
2730             var oConn = this;
2731
2732             if (callback && callback.timeout) {
2733                 
2734                 this.timeout[o.tId] = window.setTimeout(function() {
2735                     oConn.abort(o, callback, true);
2736                 }, callback.timeout);
2737             }
2738
2739             this.poll[o.tId] = window.setInterval(
2740                     function() {
2741                         if (o.conn && o.conn.readyState == 4) {
2742                             window.clearInterval(oConn.poll[o.tId]);
2743                             delete oConn.poll[o.tId];
2744
2745                             if(callback && callback.timeout) {
2746                                 window.clearTimeout(oConn.timeout[o.tId]);
2747                                 delete oConn.timeout[o.tId];
2748                             }
2749
2750                             oConn.handleTransactionResponse(o, callback);
2751                         }
2752                     }
2753                     , this.pollInterval);
2754         },
2755
2756         handleTransactionResponse:function(o, callback, isAbort)
2757         {
2758
2759             if (!callback) {
2760                 this.releaseObject(o);
2761                 return;
2762             }
2763
2764             var httpStatus, responseObject;
2765
2766             try
2767             {
2768                 if (o.conn.status !== undefined && o.conn.status != 0) {
2769                     httpStatus = o.conn.status;
2770                 }
2771                 else {
2772                     httpStatus = 13030;
2773                 }
2774             }
2775             catch(e) {
2776
2777
2778                 httpStatus = 13030;
2779             }
2780
2781             if (httpStatus >= 200 && httpStatus < 300) {
2782                 responseObject = this.createResponseObject(o, callback.argument);
2783                 if (callback.success) {
2784                     if (!callback.scope) {
2785                         callback.success(responseObject);
2786                     }
2787                     else {
2788
2789
2790                         callback.success.apply(callback.scope, [responseObject]);
2791                     }
2792                 }
2793             }
2794             else {
2795                 switch (httpStatus) {
2796
2797                     case 12002:
2798                     case 12029:
2799                     case 12030:
2800                     case 12031:
2801                     case 12152:
2802                     case 13030:
2803                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2804                         if (callback.failure) {
2805                             if (!callback.scope) {
2806                                 callback.failure(responseObject);
2807                             }
2808                             else {
2809                                 callback.failure.apply(callback.scope, [responseObject]);
2810                             }
2811                         }
2812                         break;
2813                     default:
2814                         responseObject = this.createResponseObject(o, callback.argument);
2815                         if (callback.failure) {
2816                             if (!callback.scope) {
2817                                 callback.failure(responseObject);
2818                             }
2819                             else {
2820                                 callback.failure.apply(callback.scope, [responseObject]);
2821                             }
2822                         }
2823                 }
2824             }
2825
2826             this.releaseObject(o);
2827             responseObject = null;
2828         },
2829
2830         createResponseObject:function(o, callbackArg)
2831         {
2832             var obj = {};
2833             var headerObj = {};
2834
2835             try
2836             {
2837                 var headerStr = o.conn.getAllResponseHeaders();
2838                 var header = headerStr.split('\n');
2839                 for (var i = 0; i < header.length; i++) {
2840                     var delimitPos = header[i].indexOf(':');
2841                     if (delimitPos != -1) {
2842                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2843                     }
2844                 }
2845             }
2846             catch(e) {
2847             }
2848
2849             obj.tId = o.tId;
2850             obj.status = o.conn.status;
2851             obj.statusText = o.conn.statusText;
2852             obj.getResponseHeader = headerObj;
2853             obj.getAllResponseHeaders = headerStr;
2854             obj.responseText = o.conn.responseText;
2855             obj.responseXML = o.conn.responseXML;
2856
2857             if (typeof callbackArg !== undefined) {
2858                 obj.argument = callbackArg;
2859             }
2860
2861             return obj;
2862         },
2863
2864         createExceptionObject:function(tId, callbackArg, isAbort)
2865         {
2866             var COMM_CODE = 0;
2867             var COMM_ERROR = 'communication failure';
2868             var ABORT_CODE = -1;
2869             var ABORT_ERROR = 'transaction aborted';
2870
2871             var obj = {};
2872
2873             obj.tId = tId;
2874             if (isAbort) {
2875                 obj.status = ABORT_CODE;
2876                 obj.statusText = ABORT_ERROR;
2877             }
2878             else {
2879                 obj.status = COMM_CODE;
2880                 obj.statusText = COMM_ERROR;
2881             }
2882
2883             if (callbackArg) {
2884                 obj.argument = callbackArg;
2885             }
2886
2887             return obj;
2888         },
2889
2890         initHeader:function(label, value, isDefault)
2891         {
2892             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2893
2894             if (headerObj[label] === undefined) {
2895                 headerObj[label] = value;
2896             }
2897             else {
2898
2899
2900                 headerObj[label] = value + "," + headerObj[label];
2901             }
2902
2903             if (isDefault) {
2904                 this.hasDefaultHeaders = true;
2905             }
2906             else {
2907                 this.hasHeaders = true;
2908             }
2909         },
2910
2911
2912         setHeader:function(o)
2913         {
2914             if (this.hasDefaultHeaders) {
2915                 for (var prop in this.defaultHeaders) {
2916                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2917                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2918                     }
2919                 }
2920             }
2921
2922             if (this.hasHeaders) {
2923                 for (var prop in this.headers) {
2924                     if (this.headers.hasOwnProperty(prop)) {
2925                         o.conn.setRequestHeader(prop, this.headers[prop]);
2926                     }
2927                 }
2928                 this.headers = {};
2929                 this.hasHeaders = false;
2930             }
2931         },
2932
2933         resetDefaultHeaders:function() {
2934             delete this.defaultHeaders;
2935             this.defaultHeaders = {};
2936             this.hasDefaultHeaders = false;
2937         },
2938
2939         abort:function(o, callback, isTimeout)
2940         {
2941             if(this.isCallInProgress(o)) {
2942                 o.conn.abort();
2943                 window.clearInterval(this.poll[o.tId]);
2944                 delete this.poll[o.tId];
2945                 if (isTimeout) {
2946                     delete this.timeout[o.tId];
2947                 }
2948
2949                 this.handleTransactionResponse(o, callback, true);
2950
2951                 return true;
2952             }
2953             else {
2954                 return false;
2955             }
2956         },
2957
2958
2959         isCallInProgress:function(o)
2960         {
2961             if (o && o.conn) {
2962                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2963             }
2964             else {
2965
2966                 return false;
2967             }
2968         },
2969
2970
2971         releaseObject:function(o)
2972         {
2973
2974             o.conn = null;
2975
2976             o = null;
2977         },
2978
2979         activeX:[
2980         'MSXML2.XMLHTTP.3.0',
2981         'MSXML2.XMLHTTP',
2982         'Microsoft.XMLHTTP'
2983         ]
2984
2985
2986     };
2987 })();/*
2988  * Portions of this file are based on pieces of Yahoo User Interface Library
2989  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2990  * YUI licensed under the BSD License:
2991  * http://developer.yahoo.net/yui/license.txt
2992  * <script type="text/javascript">
2993  *
2994  */
2995
2996 Roo.lib.Region = function(t, r, b, l) {
2997     this.top = t;
2998     this[1] = t;
2999     this.right = r;
3000     this.bottom = b;
3001     this.left = l;
3002     this[0] = l;
3003 };
3004
3005
3006 Roo.lib.Region.prototype = {
3007     contains : function(region) {
3008         return ( region.left >= this.left &&
3009                  region.right <= this.right &&
3010                  region.top >= this.top &&
3011                  region.bottom <= this.bottom    );
3012
3013     },
3014
3015     getArea : function() {
3016         return ( (this.bottom - this.top) * (this.right - this.left) );
3017     },
3018
3019     intersect : function(region) {
3020         var t = Math.max(this.top, region.top);
3021         var r = Math.min(this.right, region.right);
3022         var b = Math.min(this.bottom, region.bottom);
3023         var l = Math.max(this.left, region.left);
3024
3025         if (b >= t && r >= l) {
3026             return new Roo.lib.Region(t, r, b, l);
3027         } else {
3028             return null;
3029         }
3030     },
3031     union : function(region) {
3032         var t = Math.min(this.top, region.top);
3033         var r = Math.max(this.right, region.right);
3034         var b = Math.max(this.bottom, region.bottom);
3035         var l = Math.min(this.left, region.left);
3036
3037         return new Roo.lib.Region(t, r, b, l);
3038     },
3039
3040     adjust : function(t, l, b, r) {
3041         this.top += t;
3042         this.left += l;
3043         this.right += r;
3044         this.bottom += b;
3045         return this;
3046     }
3047 };
3048
3049 Roo.lib.Region.getRegion = function(el) {
3050     var p = Roo.lib.Dom.getXY(el);
3051
3052     var t = p[1];
3053     var r = p[0] + el.offsetWidth;
3054     var b = p[1] + el.offsetHeight;
3055     var l = p[0];
3056
3057     return new Roo.lib.Region(t, r, b, l);
3058 };
3059 /*
3060  * Portions of this file are based on pieces of Yahoo User Interface Library
3061  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3062  * YUI licensed under the BSD License:
3063  * http://developer.yahoo.net/yui/license.txt
3064  * <script type="text/javascript">
3065  *
3066  */
3067 //@@dep Roo.lib.Region
3068
3069
3070 Roo.lib.Point = function(x, y) {
3071     if (x instanceof Array) {
3072         y = x[1];
3073         x = x[0];
3074     }
3075     this.x = this.right = this.left = this[0] = x;
3076     this.y = this.top = this.bottom = this[1] = y;
3077 };
3078
3079 Roo.lib.Point.prototype = new Roo.lib.Region();
3080 /*
3081  * Portions of this file are based on pieces of Yahoo User Interface Library
3082  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3083  * YUI licensed under the BSD License:
3084  * http://developer.yahoo.net/yui/license.txt
3085  * <script type="text/javascript">
3086  *
3087  */
3088  
3089 (function() {   
3090
3091     Roo.lib.Anim = {
3092         scroll : function(el, args, duration, easing, cb, scope) {
3093             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3094         },
3095
3096         motion : function(el, args, duration, easing, cb, scope) {
3097             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3098         },
3099
3100         color : function(el, args, duration, easing, cb, scope) {
3101             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3102         },
3103
3104         run : function(el, args, duration, easing, cb, scope, type) {
3105             type = type || Roo.lib.AnimBase;
3106             if (typeof easing == "string") {
3107                 easing = Roo.lib.Easing[easing];
3108             }
3109             var anim = new type(el, args, duration, easing);
3110             anim.animateX(function() {
3111                 Roo.callback(cb, scope);
3112             });
3113             return anim;
3114         }
3115     };
3116 })();/*
3117  * Portions of this file are based on pieces of Yahoo User Interface Library
3118  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3119  * YUI licensed under the BSD License:
3120  * http://developer.yahoo.net/yui/license.txt
3121  * <script type="text/javascript">
3122  *
3123  */
3124
3125 (function() {    
3126     var libFlyweight;
3127     
3128     function fly(el) {
3129         if (!libFlyweight) {
3130             libFlyweight = new Roo.Element.Flyweight();
3131         }
3132         libFlyweight.dom = el;
3133         return libFlyweight;
3134     }
3135
3136     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3137     
3138    
3139     
3140     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3141         if (el) {
3142             this.init(el, attributes, duration, method);
3143         }
3144     };
3145
3146     Roo.lib.AnimBase.fly = fly;
3147     
3148     
3149     
3150     Roo.lib.AnimBase.prototype = {
3151
3152         toString: function() {
3153             var el = this.getEl();
3154             var id = el.id || el.tagName;
3155             return ("Anim " + id);
3156         },
3157
3158         patterns: {
3159             noNegatives:        /width|height|opacity|padding/i,
3160             offsetAttribute:  /^((width|height)|(top|left))$/,
3161             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3162             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3163         },
3164
3165
3166         doMethod: function(attr, start, end) {
3167             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3168         },
3169
3170
3171         setAttribute: function(attr, val, unit) {
3172             if (this.patterns.noNegatives.test(attr)) {
3173                 val = (val > 0) ? val : 0;
3174             }
3175
3176             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3177         },
3178
3179
3180         getAttribute: function(attr) {
3181             var el = this.getEl();
3182             var val = fly(el).getStyle(attr);
3183
3184             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3185                 return parseFloat(val);
3186             }
3187
3188             var a = this.patterns.offsetAttribute.exec(attr) || [];
3189             var pos = !!( a[3] );
3190             var box = !!( a[2] );
3191
3192
3193             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3194                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3195             } else {
3196                 val = 0;
3197             }
3198
3199             return val;
3200         },
3201
3202
3203         getDefaultUnit: function(attr) {
3204             if (this.patterns.defaultUnit.test(attr)) {
3205                 return 'px';
3206             }
3207
3208             return '';
3209         },
3210
3211         animateX : function(callback, scope) {
3212             var f = function() {
3213                 this.onComplete.removeListener(f);
3214                 if (typeof callback == "function") {
3215                     callback.call(scope || this, this);
3216                 }
3217             };
3218             this.onComplete.addListener(f, this);
3219             this.animate();
3220         },
3221
3222
3223         setRuntimeAttribute: function(attr) {
3224             var start;
3225             var end;
3226             var attributes = this.attributes;
3227
3228             this.runtimeAttributes[attr] = {};
3229
3230             var isset = function(prop) {
3231                 return (typeof prop !== 'undefined');
3232             };
3233
3234             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3235                 return false;
3236             }
3237
3238             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3239
3240
3241             if (isset(attributes[attr]['to'])) {
3242                 end = attributes[attr]['to'];
3243             } else if (isset(attributes[attr]['by'])) {
3244                 if (start.constructor == Array) {
3245                     end = [];
3246                     for (var i = 0, len = start.length; i < len; ++i) {
3247                         end[i] = start[i] + attributes[attr]['by'][i];
3248                     }
3249                 } else {
3250                     end = start + attributes[attr]['by'];
3251                 }
3252             }
3253
3254             this.runtimeAttributes[attr].start = start;
3255             this.runtimeAttributes[attr].end = end;
3256
3257
3258             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3259         },
3260
3261
3262         init: function(el, attributes, duration, method) {
3263
3264             var isAnimated = false;
3265
3266
3267             var startTime = null;
3268
3269
3270             var actualFrames = 0;
3271
3272
3273             el = Roo.getDom(el);
3274
3275
3276             this.attributes = attributes || {};
3277
3278
3279             this.duration = duration || 1;
3280
3281
3282             this.method = method || Roo.lib.Easing.easeNone;
3283
3284
3285             this.useSeconds = true;
3286
3287
3288             this.currentFrame = 0;
3289
3290
3291             this.totalFrames = Roo.lib.AnimMgr.fps;
3292
3293
3294             this.getEl = function() {
3295                 return el;
3296             };
3297
3298
3299             this.isAnimated = function() {
3300                 return isAnimated;
3301             };
3302
3303
3304             this.getStartTime = function() {
3305                 return startTime;
3306             };
3307
3308             this.runtimeAttributes = {};
3309
3310
3311             this.animate = function() {
3312                 if (this.isAnimated()) {
3313                     return false;
3314                 }
3315
3316                 this.currentFrame = 0;
3317
3318                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3319
3320                 Roo.lib.AnimMgr.registerElement(this);
3321             };
3322
3323
3324             this.stop = function(finish) {
3325                 if (finish) {
3326                     this.currentFrame = this.totalFrames;
3327                     this._onTween.fire();
3328                 }
3329                 Roo.lib.AnimMgr.stop(this);
3330             };
3331
3332             var onStart = function() {
3333                 this.onStart.fire();
3334
3335                 this.runtimeAttributes = {};
3336                 for (var attr in this.attributes) {
3337                     this.setRuntimeAttribute(attr);
3338                 }
3339
3340                 isAnimated = true;
3341                 actualFrames = 0;
3342                 startTime = new Date();
3343             };
3344
3345
3346             var onTween = function() {
3347                 var data = {
3348                     duration: new Date() - this.getStartTime(),
3349                     currentFrame: this.currentFrame
3350                 };
3351
3352                 data.toString = function() {
3353                     return (
3354                             'duration: ' + data.duration +
3355                             ', currentFrame: ' + data.currentFrame
3356                             );
3357                 };
3358
3359                 this.onTween.fire(data);
3360
3361                 var runtimeAttributes = this.runtimeAttributes;
3362
3363                 for (var attr in runtimeAttributes) {
3364                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3365                 }
3366
3367                 actualFrames += 1;
3368             };
3369
3370             var onComplete = function() {
3371                 var actual_duration = (new Date() - startTime) / 1000 ;
3372
3373                 var data = {
3374                     duration: actual_duration,
3375                     frames: actualFrames,
3376                     fps: actualFrames / actual_duration
3377                 };
3378
3379                 data.toString = function() {
3380                     return (
3381                             'duration: ' + data.duration +
3382                             ', frames: ' + data.frames +
3383                             ', fps: ' + data.fps
3384                             );
3385                 };
3386
3387                 isAnimated = false;
3388                 actualFrames = 0;
3389                 this.onComplete.fire(data);
3390             };
3391
3392
3393             this._onStart = new Roo.util.Event(this);
3394             this.onStart = new Roo.util.Event(this);
3395             this.onTween = new Roo.util.Event(this);
3396             this._onTween = new Roo.util.Event(this);
3397             this.onComplete = new Roo.util.Event(this);
3398             this._onComplete = new Roo.util.Event(this);
3399             this._onStart.addListener(onStart);
3400             this._onTween.addListener(onTween);
3401             this._onComplete.addListener(onComplete);
3402         }
3403     };
3404 })();
3405 /*
3406  * Portions of this file are based on pieces of Yahoo User Interface Library
3407  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3408  * YUI licensed under the BSD License:
3409  * http://developer.yahoo.net/yui/license.txt
3410  * <script type="text/javascript">
3411  *
3412  */
3413
3414 Roo.lib.AnimMgr = new function() {
3415
3416     var thread = null;
3417
3418
3419     var queue = [];
3420
3421
3422     var tweenCount = 0;
3423
3424
3425     this.fps = 1000;
3426
3427
3428     this.delay = 1;
3429
3430
3431     this.registerElement = function(tween) {
3432         queue[queue.length] = tween;
3433         tweenCount += 1;
3434         tween._onStart.fire();
3435         this.start();
3436     };
3437
3438
3439     this.unRegister = function(tween, index) {
3440         tween._onComplete.fire();
3441         index = index || getIndex(tween);
3442         if (index != -1) {
3443             queue.splice(index, 1);
3444         }
3445
3446         tweenCount -= 1;
3447         if (tweenCount <= 0) {
3448             this.stop();
3449         }
3450     };
3451
3452
3453     this.start = function() {
3454         if (thread === null) {
3455             thread = setInterval(this.run, this.delay);
3456         }
3457     };
3458
3459
3460     this.stop = function(tween) {
3461         if (!tween) {
3462             clearInterval(thread);
3463
3464             for (var i = 0, len = queue.length; i < len; ++i) {
3465                 if (queue[0].isAnimated()) {
3466                     this.unRegister(queue[0], 0);
3467                 }
3468             }
3469
3470             queue = [];
3471             thread = null;
3472             tweenCount = 0;
3473         }
3474         else {
3475             this.unRegister(tween);
3476         }
3477     };
3478
3479
3480     this.run = function() {
3481         for (var i = 0, len = queue.length; i < len; ++i) {
3482             var tween = queue[i];
3483             if (!tween || !tween.isAnimated()) {
3484                 continue;
3485             }
3486
3487             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3488             {
3489                 tween.currentFrame += 1;
3490
3491                 if (tween.useSeconds) {
3492                     correctFrame(tween);
3493                 }
3494                 tween._onTween.fire();
3495             }
3496             else {
3497                 Roo.lib.AnimMgr.stop(tween, i);
3498             }
3499         }
3500     };
3501
3502     var getIndex = function(anim) {
3503         for (var i = 0, len = queue.length; i < len; ++i) {
3504             if (queue[i] == anim) {
3505                 return i;
3506             }
3507         }
3508         return -1;
3509     };
3510
3511
3512     var correctFrame = function(tween) {
3513         var frames = tween.totalFrames;
3514         var frame = tween.currentFrame;
3515         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3516         var elapsed = (new Date() - tween.getStartTime());
3517         var tweak = 0;
3518
3519         if (elapsed < tween.duration * 1000) {
3520             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3521         } else {
3522             tweak = frames - (frame + 1);
3523         }
3524         if (tweak > 0 && isFinite(tweak)) {
3525             if (tween.currentFrame + tweak >= frames) {
3526                 tweak = frames - (frame + 1);
3527             }
3528
3529             tween.currentFrame += tweak;
3530         }
3531     };
3532 };
3533
3534     /*
3535  * Portions of this file are based on pieces of Yahoo User Interface Library
3536  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3537  * YUI licensed under the BSD License:
3538  * http://developer.yahoo.net/yui/license.txt
3539  * <script type="text/javascript">
3540  *
3541  */
3542 Roo.lib.Bezier = new function() {
3543
3544         this.getPosition = function(points, t) {
3545             var n = points.length;
3546             var tmp = [];
3547
3548             for (var i = 0; i < n; ++i) {
3549                 tmp[i] = [points[i][0], points[i][1]];
3550             }
3551
3552             for (var j = 1; j < n; ++j) {
3553                 for (i = 0; i < n - j; ++i) {
3554                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3555                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3556                 }
3557             }
3558
3559             return [ tmp[0][0], tmp[0][1] ];
3560
3561         };
3562     };/*
3563  * Portions of this file are based on pieces of Yahoo User Interface Library
3564  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3565  * YUI licensed under the BSD License:
3566  * http://developer.yahoo.net/yui/license.txt
3567  * <script type="text/javascript">
3568  *
3569  */
3570 (function() {
3571
3572     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3573         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3574     };
3575
3576     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3577
3578     var fly = Roo.lib.AnimBase.fly;
3579     var Y = Roo.lib;
3580     var superclass = Y.ColorAnim.superclass;
3581     var proto = Y.ColorAnim.prototype;
3582
3583     proto.toString = function() {
3584         var el = this.getEl();
3585         var id = el.id || el.tagName;
3586         return ("ColorAnim " + id);
3587     };
3588
3589     proto.patterns.color = /color$/i;
3590     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3591     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3592     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3593     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3594
3595
3596     proto.parseColor = function(s) {
3597         if (s.length == 3) {
3598             return s;
3599         }
3600
3601         var c = this.patterns.hex.exec(s);
3602         if (c && c.length == 4) {
3603             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3604         }
3605
3606         c = this.patterns.rgb.exec(s);
3607         if (c && c.length == 4) {
3608             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3609         }
3610
3611         c = this.patterns.hex3.exec(s);
3612         if (c && c.length == 4) {
3613             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3614         }
3615
3616         return null;
3617     };
3618     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3619     proto.getAttribute = function(attr) {
3620         var el = this.getEl();
3621         if (this.patterns.color.test(attr)) {
3622             var val = fly(el).getStyle(attr);
3623
3624             if (this.patterns.transparent.test(val)) {
3625                 var parent = el.parentNode;
3626                 val = fly(parent).getStyle(attr);
3627
3628                 while (parent && this.patterns.transparent.test(val)) {
3629                     parent = parent.parentNode;
3630                     val = fly(parent).getStyle(attr);
3631                     if (parent.tagName.toUpperCase() == 'HTML') {
3632                         val = '#fff';
3633                     }
3634                 }
3635             }
3636         } else {
3637             val = superclass.getAttribute.call(this, attr);
3638         }
3639
3640         return val;
3641     };
3642     proto.getAttribute = function(attr) {
3643         var el = this.getEl();
3644         if (this.patterns.color.test(attr)) {
3645             var val = fly(el).getStyle(attr);
3646
3647             if (this.patterns.transparent.test(val)) {
3648                 var parent = el.parentNode;
3649                 val = fly(parent).getStyle(attr);
3650
3651                 while (parent && this.patterns.transparent.test(val)) {
3652                     parent = parent.parentNode;
3653                     val = fly(parent).getStyle(attr);
3654                     if (parent.tagName.toUpperCase() == 'HTML') {
3655                         val = '#fff';
3656                     }
3657                 }
3658             }
3659         } else {
3660             val = superclass.getAttribute.call(this, attr);
3661         }
3662
3663         return val;
3664     };
3665
3666     proto.doMethod = function(attr, start, end) {
3667         var val;
3668
3669         if (this.patterns.color.test(attr)) {
3670             val = [];
3671             for (var i = 0, len = start.length; i < len; ++i) {
3672                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3673             }
3674
3675             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3676         }
3677         else {
3678             val = superclass.doMethod.call(this, attr, start, end);
3679         }
3680
3681         return val;
3682     };
3683
3684     proto.setRuntimeAttribute = function(attr) {
3685         superclass.setRuntimeAttribute.call(this, attr);
3686
3687         if (this.patterns.color.test(attr)) {
3688             var attributes = this.attributes;
3689             var start = this.parseColor(this.runtimeAttributes[attr].start);
3690             var end = this.parseColor(this.runtimeAttributes[attr].end);
3691
3692             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3693                 end = this.parseColor(attributes[attr].by);
3694
3695                 for (var i = 0, len = start.length; i < len; ++i) {
3696                     end[i] = start[i] + end[i];
3697                 }
3698             }
3699
3700             this.runtimeAttributes[attr].start = start;
3701             this.runtimeAttributes[attr].end = end;
3702         }
3703     };
3704 })();
3705
3706 /*
3707  * Portions of this file are based on pieces of Yahoo User Interface Library
3708  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3709  * YUI licensed under the BSD License:
3710  * http://developer.yahoo.net/yui/license.txt
3711  * <script type="text/javascript">
3712  *
3713  */
3714 Roo.lib.Easing = {
3715
3716
3717     easeNone: function (t, b, c, d) {
3718         return c * t / d + b;
3719     },
3720
3721
3722     easeIn: function (t, b, c, d) {
3723         return c * (t /= d) * t + b;
3724     },
3725
3726
3727     easeOut: function (t, b, c, d) {
3728         return -c * (t /= d) * (t - 2) + b;
3729     },
3730
3731
3732     easeBoth: function (t, b, c, d) {
3733         if ((t /= d / 2) < 1) {
3734             return c / 2 * t * t + b;
3735         }
3736
3737         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3738     },
3739
3740
3741     easeInStrong: function (t, b, c, d) {
3742         return c * (t /= d) * t * t * t + b;
3743     },
3744
3745
3746     easeOutStrong: function (t, b, c, d) {
3747         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3748     },
3749
3750
3751     easeBothStrong: function (t, b, c, d) {
3752         if ((t /= d / 2) < 1) {
3753             return c / 2 * t * t * t * t + b;
3754         }
3755
3756         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3757     },
3758
3759
3760
3761     elasticIn: function (t, b, c, d, a, p) {
3762         if (t == 0) {
3763             return b;
3764         }
3765         if ((t /= d) == 1) {
3766             return b + c;
3767         }
3768         if (!p) {
3769             p = d * .3;
3770         }
3771
3772         if (!a || a < Math.abs(c)) {
3773             a = c;
3774             var s = p / 4;
3775         }
3776         else {
3777             var s = p / (2 * Math.PI) * Math.asin(c / a);
3778         }
3779
3780         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3781     },
3782
3783
3784     elasticOut: function (t, b, c, d, a, p) {
3785         if (t == 0) {
3786             return b;
3787         }
3788         if ((t /= d) == 1) {
3789             return b + c;
3790         }
3791         if (!p) {
3792             p = d * .3;
3793         }
3794
3795         if (!a || a < Math.abs(c)) {
3796             a = c;
3797             var s = p / 4;
3798         }
3799         else {
3800             var s = p / (2 * Math.PI) * Math.asin(c / a);
3801         }
3802
3803         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3804     },
3805
3806
3807     elasticBoth: function (t, b, c, d, a, p) {
3808         if (t == 0) {
3809             return b;
3810         }
3811
3812         if ((t /= d / 2) == 2) {
3813             return b + c;
3814         }
3815
3816         if (!p) {
3817             p = d * (.3 * 1.5);
3818         }
3819
3820         if (!a || a < Math.abs(c)) {
3821             a = c;
3822             var s = p / 4;
3823         }
3824         else {
3825             var s = p / (2 * Math.PI) * Math.asin(c / a);
3826         }
3827
3828         if (t < 1) {
3829             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3830                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3831         }
3832         return a * Math.pow(2, -10 * (t -= 1)) *
3833                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3834     },
3835
3836
3837
3838     backIn: function (t, b, c, d, s) {
3839         if (typeof s == 'undefined') {
3840             s = 1.70158;
3841         }
3842         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3843     },
3844
3845
3846     backOut: function (t, b, c, d, s) {
3847         if (typeof s == 'undefined') {
3848             s = 1.70158;
3849         }
3850         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3851     },
3852
3853
3854     backBoth: function (t, b, c, d, s) {
3855         if (typeof s == 'undefined') {
3856             s = 1.70158;
3857         }
3858
3859         if ((t /= d / 2 ) < 1) {
3860             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3861         }
3862         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3863     },
3864
3865
3866     bounceIn: function (t, b, c, d) {
3867         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3868     },
3869
3870
3871     bounceOut: function (t, b, c, d) {
3872         if ((t /= d) < (1 / 2.75)) {
3873             return c * (7.5625 * t * t) + b;
3874         } else if (t < (2 / 2.75)) {
3875             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3876         } else if (t < (2.5 / 2.75)) {
3877             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3878         }
3879         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3880     },
3881
3882
3883     bounceBoth: function (t, b, c, d) {
3884         if (t < d / 2) {
3885             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3886         }
3887         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3888     }
3889 };/*
3890  * Portions of this file are based on pieces of Yahoo User Interface Library
3891  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3892  * YUI licensed under the BSD License:
3893  * http://developer.yahoo.net/yui/license.txt
3894  * <script type="text/javascript">
3895  *
3896  */
3897     (function() {
3898         Roo.lib.Motion = function(el, attributes, duration, method) {
3899             if (el) {
3900                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3901             }
3902         };
3903
3904         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3905
3906
3907         var Y = Roo.lib;
3908         var superclass = Y.Motion.superclass;
3909         var proto = Y.Motion.prototype;
3910
3911         proto.toString = function() {
3912             var el = this.getEl();
3913             var id = el.id || el.tagName;
3914             return ("Motion " + id);
3915         };
3916
3917         proto.patterns.points = /^points$/i;
3918
3919         proto.setAttribute = function(attr, val, unit) {
3920             if (this.patterns.points.test(attr)) {
3921                 unit = unit || 'px';
3922                 superclass.setAttribute.call(this, 'left', val[0], unit);
3923                 superclass.setAttribute.call(this, 'top', val[1], unit);
3924             } else {
3925                 superclass.setAttribute.call(this, attr, val, unit);
3926             }
3927         };
3928
3929         proto.getAttribute = function(attr) {
3930             if (this.patterns.points.test(attr)) {
3931                 var val = [
3932                         superclass.getAttribute.call(this, 'left'),
3933                         superclass.getAttribute.call(this, 'top')
3934                         ];
3935             } else {
3936                 val = superclass.getAttribute.call(this, attr);
3937             }
3938
3939             return val;
3940         };
3941
3942         proto.doMethod = function(attr, start, end) {
3943             var val = null;
3944
3945             if (this.patterns.points.test(attr)) {
3946                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3947                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3948             } else {
3949                 val = superclass.doMethod.call(this, attr, start, end);
3950             }
3951             return val;
3952         };
3953
3954         proto.setRuntimeAttribute = function(attr) {
3955             if (this.patterns.points.test(attr)) {
3956                 var el = this.getEl();
3957                 var attributes = this.attributes;
3958                 var start;
3959                 var control = attributes['points']['control'] || [];
3960                 var end;
3961                 var i, len;
3962
3963                 if (control.length > 0 && !(control[0] instanceof Array)) {
3964                     control = [control];
3965                 } else {
3966                     var tmp = [];
3967                     for (i = 0,len = control.length; i < len; ++i) {
3968                         tmp[i] = control[i];
3969                     }
3970                     control = tmp;
3971                 }
3972
3973                 Roo.fly(el).position();
3974
3975                 if (isset(attributes['points']['from'])) {
3976                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3977                 }
3978                 else {
3979                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3980                 }
3981
3982                 start = this.getAttribute('points');
3983
3984
3985                 if (isset(attributes['points']['to'])) {
3986                     end = translateValues.call(this, attributes['points']['to'], start);
3987
3988                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
3989                     for (i = 0,len = control.length; i < len; ++i) {
3990                         control[i] = translateValues.call(this, control[i], start);
3991                     }
3992
3993
3994                 } else if (isset(attributes['points']['by'])) {
3995                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
3996
3997                     for (i = 0,len = control.length; i < len; ++i) {
3998                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
3999                     }
4000                 }
4001
4002                 this.runtimeAttributes[attr] = [start];
4003
4004                 if (control.length > 0) {
4005                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4006                 }
4007
4008                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4009             }
4010             else {
4011                 superclass.setRuntimeAttribute.call(this, attr);
4012             }
4013         };
4014
4015         var translateValues = function(val, start) {
4016             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4017             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4018
4019             return val;
4020         };
4021
4022         var isset = function(prop) {
4023             return (typeof prop !== 'undefined');
4024         };
4025     })();
4026 /*
4027  * Portions of this file are based on pieces of Yahoo User Interface Library
4028  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4029  * YUI licensed under the BSD License:
4030  * http://developer.yahoo.net/yui/license.txt
4031  * <script type="text/javascript">
4032  *
4033  */
4034     (function() {
4035         Roo.lib.Scroll = function(el, attributes, duration, method) {
4036             if (el) {
4037                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4038             }
4039         };
4040
4041         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4042
4043
4044         var Y = Roo.lib;
4045         var superclass = Y.Scroll.superclass;
4046         var proto = Y.Scroll.prototype;
4047
4048         proto.toString = function() {
4049             var el = this.getEl();
4050             var id = el.id || el.tagName;
4051             return ("Scroll " + id);
4052         };
4053
4054         proto.doMethod = function(attr, start, end) {
4055             var val = null;
4056
4057             if (attr == 'scroll') {
4058                 val = [
4059                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4060                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4061                         ];
4062
4063             } else {
4064                 val = superclass.doMethod.call(this, attr, start, end);
4065             }
4066             return val;
4067         };
4068
4069         proto.getAttribute = function(attr) {
4070             var val = null;
4071             var el = this.getEl();
4072
4073             if (attr == 'scroll') {
4074                 val = [ el.scrollLeft, el.scrollTop ];
4075             } else {
4076                 val = superclass.getAttribute.call(this, attr);
4077             }
4078
4079             return val;
4080         };
4081
4082         proto.setAttribute = function(attr, val, unit) {
4083             var el = this.getEl();
4084
4085             if (attr == 'scroll') {
4086                 el.scrollLeft = val[0];
4087                 el.scrollTop = val[1];
4088             } else {
4089                 superclass.setAttribute.call(this, attr, val, unit);
4090             }
4091         };
4092     })();
4093 /*
4094  * Based on:
4095  * Ext JS Library 1.1.1
4096  * Copyright(c) 2006-2007, Ext JS, LLC.
4097  *
4098  * Originally Released Under LGPL - original licence link has changed is not relivant.
4099  *
4100  * Fork - LGPL
4101  * <script type="text/javascript">
4102  */
4103
4104
4105 // nasty IE9 hack - what a pile of crap that is..
4106
4107  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4108     Range.prototype.createContextualFragment = function (html) {
4109         var doc = window.document;
4110         var container = doc.createElement("div");
4111         container.innerHTML = html;
4112         var frag = doc.createDocumentFragment(), n;
4113         while ((n = container.firstChild)) {
4114             frag.appendChild(n);
4115         }
4116         return frag;
4117     };
4118 }
4119
4120 /**
4121  * @class Roo.DomHelper
4122  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4123  * 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>.
4124  * @singleton
4125  */
4126 Roo.DomHelper = function(){
4127     var tempTableEl = null;
4128     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4129     var tableRe = /^table|tbody|tr|td$/i;
4130     var xmlns = {};
4131     // build as innerHTML where available
4132     /** @ignore */
4133     var createHtml = function(o){
4134         if(typeof o == 'string'){
4135             return o;
4136         }
4137         var b = "";
4138         if(!o.tag){
4139             o.tag = "div";
4140         }
4141         b += "<" + o.tag;
4142         for(var attr in o){
4143             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4144             if(attr == "style"){
4145                 var s = o["style"];
4146                 if(typeof s == "function"){
4147                     s = s.call();
4148                 }
4149                 if(typeof s == "string"){
4150                     b += ' style="' + s + '"';
4151                 }else if(typeof s == "object"){
4152                     b += ' style="';
4153                     for(var key in s){
4154                         if(typeof s[key] != "function"){
4155                             b += key + ":" + s[key] + ";";
4156                         }
4157                     }
4158                     b += '"';
4159                 }
4160             }else{
4161                 if(attr == "cls"){
4162                     b += ' class="' + o["cls"] + '"';
4163                 }else if(attr == "htmlFor"){
4164                     b += ' for="' + o["htmlFor"] + '"';
4165                 }else{
4166                     b += " " + attr + '="' + o[attr] + '"';
4167                 }
4168             }
4169         }
4170         if(emptyTags.test(o.tag)){
4171             b += "/>";
4172         }else{
4173             b += ">";
4174             var cn = o.children || o.cn;
4175             if(cn){
4176                 //http://bugs.kde.org/show_bug.cgi?id=71506
4177                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4178                     for(var i = 0, len = cn.length; i < len; i++) {
4179                         b += createHtml(cn[i], b);
4180                     }
4181                 }else{
4182                     b += createHtml(cn, b);
4183                 }
4184             }
4185             if(o.html){
4186                 b += o.html;
4187             }
4188             b += "</" + o.tag + ">";
4189         }
4190         return b;
4191     };
4192
4193     // build as dom
4194     /** @ignore */
4195     var createDom = function(o, parentNode){
4196          
4197         // defininition craeted..
4198         var ns = false;
4199         if (o.ns && o.ns != 'html') {
4200                
4201             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4202                 xmlns[o.ns] = o.xmlns;
4203                 ns = o.xmlns;
4204             }
4205             if (typeof(xmlns[o.ns]) == 'undefined') {
4206                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4207             }
4208             ns = xmlns[o.ns];
4209         }
4210         
4211         
4212         if (typeof(o) == 'string') {
4213             return parentNode.appendChild(document.createTextNode(o));
4214         }
4215         o.tag = o.tag || div;
4216         if (o.ns && Roo.isIE) {
4217             ns = false;
4218             o.tag = o.ns + ':' + o.tag;
4219             
4220         }
4221         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4222         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4223         for(var attr in o){
4224             
4225             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4226                     attr == "style" || typeof o[attr] == "function") continue;
4227                     
4228             if(attr=="cls" && Roo.isIE){
4229                 el.className = o["cls"];
4230             }else{
4231                 if(useSet) el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);
4232                 else el[attr] = o[attr];
4233             }
4234         }
4235         Roo.DomHelper.applyStyles(el, o.style);
4236         var cn = o.children || o.cn;
4237         if(cn){
4238             //http://bugs.kde.org/show_bug.cgi?id=71506
4239              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4240                 for(var i = 0, len = cn.length; i < len; i++) {
4241                     createDom(cn[i], el);
4242                 }
4243             }else{
4244                 createDom(cn, el);
4245             }
4246         }
4247         if(o.html){
4248             el.innerHTML = o.html;
4249         }
4250         if(parentNode){
4251            parentNode.appendChild(el);
4252         }
4253         return el;
4254     };
4255
4256     var ieTable = function(depth, s, h, e){
4257         tempTableEl.innerHTML = [s, h, e].join('');
4258         var i = -1, el = tempTableEl;
4259         while(++i < depth){
4260             el = el.firstChild;
4261         }
4262         return el;
4263     };
4264
4265     // kill repeat to save bytes
4266     var ts = '<table>',
4267         te = '</table>',
4268         tbs = ts+'<tbody>',
4269         tbe = '</tbody>'+te,
4270         trs = tbs + '<tr>',
4271         tre = '</tr>'+tbe;
4272
4273     /**
4274      * @ignore
4275      * Nasty code for IE's broken table implementation
4276      */
4277     var insertIntoTable = function(tag, where, el, html){
4278         if(!tempTableEl){
4279             tempTableEl = document.createElement('div');
4280         }
4281         var node;
4282         var before = null;
4283         if(tag == 'td'){
4284             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4285                 return;
4286             }
4287             if(where == 'beforebegin'){
4288                 before = el;
4289                 el = el.parentNode;
4290             } else{
4291                 before = el.nextSibling;
4292                 el = el.parentNode;
4293             }
4294             node = ieTable(4, trs, html, tre);
4295         }
4296         else if(tag == 'tr'){
4297             if(where == 'beforebegin'){
4298                 before = el;
4299                 el = el.parentNode;
4300                 node = ieTable(3, tbs, html, tbe);
4301             } else if(where == 'afterend'){
4302                 before = el.nextSibling;
4303                 el = el.parentNode;
4304                 node = ieTable(3, tbs, html, tbe);
4305             } else{ // INTO a TR
4306                 if(where == 'afterbegin'){
4307                     before = el.firstChild;
4308                 }
4309                 node = ieTable(4, trs, html, tre);
4310             }
4311         } else if(tag == 'tbody'){
4312             if(where == 'beforebegin'){
4313                 before = el;
4314                 el = el.parentNode;
4315                 node = ieTable(2, ts, html, te);
4316             } else if(where == 'afterend'){
4317                 before = el.nextSibling;
4318                 el = el.parentNode;
4319                 node = ieTable(2, ts, html, te);
4320             } else{
4321                 if(where == 'afterbegin'){
4322                     before = el.firstChild;
4323                 }
4324                 node = ieTable(3, tbs, html, tbe);
4325             }
4326         } else{ // TABLE
4327             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4328                 return;
4329             }
4330             if(where == 'afterbegin'){
4331                 before = el.firstChild;
4332             }
4333             node = ieTable(2, ts, html, te);
4334         }
4335         el.insertBefore(node, before);
4336         return node;
4337     };
4338
4339     return {
4340     /** True to force the use of DOM instead of html fragments @type Boolean */
4341     useDom : false,
4342
4343     /**
4344      * Returns the markup for the passed Element(s) config
4345      * @param {Object} o The Dom object spec (and children)
4346      * @return {String}
4347      */
4348     markup : function(o){
4349         return createHtml(o);
4350     },
4351
4352     /**
4353      * Applies a style specification to an element
4354      * @param {String/HTMLElement} el The element to apply styles to
4355      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4356      * a function which returns such a specification.
4357      */
4358     applyStyles : function(el, styles){
4359         if(styles){
4360            el = Roo.fly(el);
4361            if(typeof styles == "string"){
4362                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4363                var matches;
4364                while ((matches = re.exec(styles)) != null){
4365                    el.setStyle(matches[1], matches[2]);
4366                }
4367            }else if (typeof styles == "object"){
4368                for (var style in styles){
4369                   el.setStyle(style, styles[style]);
4370                }
4371            }else if (typeof styles == "function"){
4372                 Roo.DomHelper.applyStyles(el, styles.call());
4373            }
4374         }
4375     },
4376
4377     /**
4378      * Inserts an HTML fragment into the Dom
4379      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4380      * @param {HTMLElement} el The context element
4381      * @param {String} html The HTML fragmenet
4382      * @return {HTMLElement} The new node
4383      */
4384     insertHtml : function(where, el, html){
4385         where = where.toLowerCase();
4386         if(el.insertAdjacentHTML){
4387             if(tableRe.test(el.tagName)){
4388                 var rs;
4389                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4390                     return rs;
4391                 }
4392             }
4393             switch(where){
4394                 case "beforebegin":
4395                     el.insertAdjacentHTML('BeforeBegin', html);
4396                     return el.previousSibling;
4397                 case "afterbegin":
4398                     el.insertAdjacentHTML('AfterBegin', html);
4399                     return el.firstChild;
4400                 case "beforeend":
4401                     el.insertAdjacentHTML('BeforeEnd', html);
4402                     return el.lastChild;
4403                 case "afterend":
4404                     el.insertAdjacentHTML('AfterEnd', html);
4405                     return el.nextSibling;
4406             }
4407             throw 'Illegal insertion point -> "' + where + '"';
4408         }
4409         var range = el.ownerDocument.createRange();
4410         var frag;
4411         switch(where){
4412              case "beforebegin":
4413                 range.setStartBefore(el);
4414                 frag = range.createContextualFragment(html);
4415                 el.parentNode.insertBefore(frag, el);
4416                 return el.previousSibling;
4417              case "afterbegin":
4418                 if(el.firstChild){
4419                     range.setStartBefore(el.firstChild);
4420                     frag = range.createContextualFragment(html);
4421                     el.insertBefore(frag, el.firstChild);
4422                     return el.firstChild;
4423                 }else{
4424                     el.innerHTML = html;
4425                     return el.firstChild;
4426                 }
4427             case "beforeend":
4428                 if(el.lastChild){
4429                     range.setStartAfter(el.lastChild);
4430                     frag = range.createContextualFragment(html);
4431                     el.appendChild(frag);
4432                     return el.lastChild;
4433                 }else{
4434                     el.innerHTML = html;
4435                     return el.lastChild;
4436                 }
4437             case "afterend":
4438                 range.setStartAfter(el);
4439                 frag = range.createContextualFragment(html);
4440                 el.parentNode.insertBefore(frag, el.nextSibling);
4441                 return el.nextSibling;
4442             }
4443             throw 'Illegal insertion point -> "' + where + '"';
4444     },
4445
4446     /**
4447      * Creates new Dom element(s) and inserts them before el
4448      * @param {String/HTMLElement/Element} el The context element
4449      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4450      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4451      * @return {HTMLElement/Roo.Element} The new node
4452      */
4453     insertBefore : function(el, o, returnElement){
4454         return this.doInsert(el, o, returnElement, "beforeBegin");
4455     },
4456
4457     /**
4458      * Creates new Dom element(s) and inserts them after el
4459      * @param {String/HTMLElement/Element} el The context element
4460      * @param {Object} o The Dom object spec (and children)
4461      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4462      * @return {HTMLElement/Roo.Element} The new node
4463      */
4464     insertAfter : function(el, o, returnElement){
4465         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4466     },
4467
4468     /**
4469      * Creates new Dom element(s) and inserts them as the first child of el
4470      * @param {String/HTMLElement/Element} el The context element
4471      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4472      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473      * @return {HTMLElement/Roo.Element} The new node
4474      */
4475     insertFirst : function(el, o, returnElement){
4476         return this.doInsert(el, o, returnElement, "afterBegin");
4477     },
4478
4479     // private
4480     doInsert : function(el, o, returnElement, pos, sibling){
4481         el = Roo.getDom(el);
4482         var newNode;
4483         if(this.useDom || o.ns){
4484             newNode = createDom(o, null);
4485             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4486         }else{
4487             var html = createHtml(o);
4488             newNode = this.insertHtml(pos, el, html);
4489         }
4490         return returnElement ? Roo.get(newNode, true) : newNode;
4491     },
4492
4493     /**
4494      * Creates new Dom element(s) and appends them to el
4495      * @param {String/HTMLElement/Element} el The context element
4496      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4497      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4498      * @return {HTMLElement/Roo.Element} The new node
4499      */
4500     append : function(el, o, returnElement){
4501         el = Roo.getDom(el);
4502         var newNode;
4503         if(this.useDom || o.ns){
4504             newNode = createDom(o, null);
4505             el.appendChild(newNode);
4506         }else{
4507             var html = createHtml(o);
4508             newNode = this.insertHtml("beforeEnd", el, html);
4509         }
4510         return returnElement ? Roo.get(newNode, true) : newNode;
4511     },
4512
4513     /**
4514      * Creates new Dom element(s) and overwrites the contents of el with them
4515      * @param {String/HTMLElement/Element} el The context element
4516      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4517      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4518      * @return {HTMLElement/Roo.Element} The new node
4519      */
4520     overwrite : function(el, o, returnElement){
4521         el = Roo.getDom(el);
4522         if (o.ns) {
4523           
4524             while (el.childNodes.length) {
4525                 el.removeChild(el.firstChild);
4526             }
4527             createDom(o, el);
4528         } else {
4529             el.innerHTML = createHtml(o);   
4530         }
4531         
4532         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4533     },
4534
4535     /**
4536      * Creates a new Roo.DomHelper.Template from the Dom object spec
4537      * @param {Object} o The Dom object spec (and children)
4538      * @return {Roo.DomHelper.Template} The new template
4539      */
4540     createTemplate : function(o){
4541         var html = createHtml(o);
4542         return new Roo.Template(html);
4543     }
4544     };
4545 }();
4546 /*
4547  * Based on:
4548  * Ext JS Library 1.1.1
4549  * Copyright(c) 2006-2007, Ext JS, LLC.
4550  *
4551  * Originally Released Under LGPL - original licence link has changed is not relivant.
4552  *
4553  * Fork - LGPL
4554  * <script type="text/javascript">
4555  */
4556  
4557 /**
4558 * @class Roo.Template
4559 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4560 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4561 * Usage:
4562 <pre><code>
4563 var t = new Roo.Template({
4564     html :  '&lt;div name="{id}"&gt;' + 
4565         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4566         '&lt;/div&gt;',
4567     myformat: function (value, allValues) {
4568         return 'XX' + value;
4569     }
4570 });
4571 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4572 </code></pre>
4573 * For more information see this blog post with examples:
4574 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4575      - Create Elements using DOM, HTML fragments and Templates</a>. 
4576 * @constructor
4577 * @param {Object} cfg - Configuration object.
4578 */
4579 Roo.Template = function(cfg){
4580     // BC!
4581     if(cfg instanceof Array){
4582         cfg = cfg.join("");
4583     }else if(arguments.length > 1){
4584         cfg = Array.prototype.join.call(arguments, "");
4585     }
4586     
4587     
4588     if (typeof(cfg) == 'object') {
4589         Roo.apply(this,cfg)
4590     } else {
4591         // bc
4592         this.html = cfg;
4593     }
4594     if (this.url) {
4595         this.load();
4596     }
4597     
4598 };
4599 Roo.Template.prototype = {
4600     
4601     /**
4602      * @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..
4603      *                    it should be fixed so that template is observable...
4604      */
4605     url : false,
4606     /**
4607      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4608      */
4609     html : '',
4610     /**
4611      * Returns an HTML fragment of this template with the specified values applied.
4612      * @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'})
4613      * @return {String} The HTML fragment
4614      */
4615     applyTemplate : function(values){
4616         try {
4617            
4618             if(this.compiled){
4619                 return this.compiled(values);
4620             }
4621             var useF = this.disableFormats !== true;
4622             var fm = Roo.util.Format, tpl = this;
4623             var fn = function(m, name, format, args){
4624                 if(format && useF){
4625                     if(format.substr(0, 5) == "this."){
4626                         return tpl.call(format.substr(5), values[name], values);
4627                     }else{
4628                         if(args){
4629                             // quoted values are required for strings in compiled templates, 
4630                             // but for non compiled we need to strip them
4631                             // quoted reversed for jsmin
4632                             var re = /^\s*['"](.*)["']\s*$/;
4633                             args = args.split(',');
4634                             for(var i = 0, len = args.length; i < len; i++){
4635                                 args[i] = args[i].replace(re, "$1");
4636                             }
4637                             args = [values[name]].concat(args);
4638                         }else{
4639                             args = [values[name]];
4640                         }
4641                         return fm[format].apply(fm, args);
4642                     }
4643                 }else{
4644                     return values[name] !== undefined ? values[name] : "";
4645                 }
4646             };
4647             return this.html.replace(this.re, fn);
4648         } catch (e) {
4649             Roo.log(e);
4650             throw e;
4651         }
4652          
4653     },
4654     
4655     loading : false,
4656       
4657     load : function ()
4658     {
4659          
4660         if (this.loading) {
4661             return;
4662         }
4663         var _t = this;
4664         
4665         this.loading = true;
4666         this.compiled = false;
4667         
4668         var cx = new Roo.data.Connection();
4669         cx.request({
4670             url : this.url,
4671             method : 'GET',
4672             success : function (response) {
4673                 _t.loading = false;
4674                 _t.html = response.responseText;
4675                 _t.url = false;
4676                 _t.compile();
4677              },
4678             failure : function(response) {
4679                 Roo.log("Template failed to load from " + _t.url);
4680                 _t.loading = false;
4681             }
4682         });
4683     },
4684
4685     /**
4686      * Sets the HTML used as the template and optionally compiles it.
4687      * @param {String} html
4688      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4689      * @return {Roo.Template} this
4690      */
4691     set : function(html, compile){
4692         this.html = html;
4693         this.compiled = null;
4694         if(compile){
4695             this.compile();
4696         }
4697         return this;
4698     },
4699     
4700     /**
4701      * True to disable format functions (defaults to false)
4702      * @type Boolean
4703      */
4704     disableFormats : false,
4705     
4706     /**
4707     * The regular expression used to match template variables 
4708     * @type RegExp
4709     * @property 
4710     */
4711     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4712     
4713     /**
4714      * Compiles the template into an internal function, eliminating the RegEx overhead.
4715      * @return {Roo.Template} this
4716      */
4717     compile : function(){
4718         var fm = Roo.util.Format;
4719         var useF = this.disableFormats !== true;
4720         var sep = Roo.isGecko ? "+" : ",";
4721         var fn = function(m, name, format, args){
4722             if(format && useF){
4723                 args = args ? ',' + args : "";
4724                 if(format.substr(0, 5) != "this."){
4725                     format = "fm." + format + '(';
4726                 }else{
4727                     format = 'this.call("'+ format.substr(5) + '", ';
4728                     args = ", values";
4729                 }
4730             }else{
4731                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4732             }
4733             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4734         };
4735         var body;
4736         // branched to use + in gecko and [].join() in others
4737         if(Roo.isGecko){
4738             body = "this.compiled = function(values){ return '" +
4739                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4740                     "';};";
4741         }else{
4742             body = ["this.compiled = function(values){ return ['"];
4743             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4744             body.push("'].join('');};");
4745             body = body.join('');
4746         }
4747         /**
4748          * eval:var:values
4749          * eval:var:fm
4750          */
4751         eval(body);
4752         return this;
4753     },
4754     
4755     // private function used to call members
4756     call : function(fnName, value, allValues){
4757         return this[fnName](value, allValues);
4758     },
4759     
4760     /**
4761      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4762      * @param {String/HTMLElement/Roo.Element} el The context element
4763      * @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'})
4764      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4765      * @return {HTMLElement/Roo.Element} The new node or Element
4766      */
4767     insertFirst: function(el, values, returnElement){
4768         return this.doInsert('afterBegin', el, values, returnElement);
4769     },
4770
4771     /**
4772      * Applies the supplied values to the template and inserts the new node(s) before el.
4773      * @param {String/HTMLElement/Roo.Element} el The context element
4774      * @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'})
4775      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4776      * @return {HTMLElement/Roo.Element} The new node or Element
4777      */
4778     insertBefore: function(el, values, returnElement){
4779         return this.doInsert('beforeBegin', el, values, returnElement);
4780     },
4781
4782     /**
4783      * Applies the supplied values to the template and inserts the new node(s) after el.
4784      * @param {String/HTMLElement/Roo.Element} el The context element
4785      * @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'})
4786      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787      * @return {HTMLElement/Roo.Element} The new node or Element
4788      */
4789     insertAfter : function(el, values, returnElement){
4790         return this.doInsert('afterEnd', el, values, returnElement);
4791     },
4792     
4793     /**
4794      * Applies the supplied values to the template and appends the new node(s) to el.
4795      * @param {String/HTMLElement/Roo.Element} el The context element
4796      * @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'})
4797      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798      * @return {HTMLElement/Roo.Element} The new node or Element
4799      */
4800     append : function(el, values, returnElement){
4801         return this.doInsert('beforeEnd', el, values, returnElement);
4802     },
4803
4804     doInsert : function(where, el, values, returnEl){
4805         el = Roo.getDom(el);
4806         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4807         return returnEl ? Roo.get(newNode, true) : newNode;
4808     },
4809
4810     /**
4811      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4812      * @param {String/HTMLElement/Roo.Element} el The context element
4813      * @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'})
4814      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4815      * @return {HTMLElement/Roo.Element} The new node or Element
4816      */
4817     overwrite : function(el, values, returnElement){
4818         el = Roo.getDom(el);
4819         el.innerHTML = this.applyTemplate(values);
4820         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4821     }
4822 };
4823 /**
4824  * Alias for {@link #applyTemplate}
4825  * @method
4826  */
4827 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4828
4829 // backwards compat
4830 Roo.DomHelper.Template = Roo.Template;
4831
4832 /**
4833  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4834  * @param {String/HTMLElement} el A DOM element or its id
4835  * @returns {Roo.Template} The created template
4836  * @static
4837  */
4838 Roo.Template.from = function(el){
4839     el = Roo.getDom(el);
4840     return new Roo.Template(el.value || el.innerHTML);
4841 };/*
4842  * Based on:
4843  * Ext JS Library 1.1.1
4844  * Copyright(c) 2006-2007, Ext JS, LLC.
4845  *
4846  * Originally Released Under LGPL - original licence link has changed is not relivant.
4847  *
4848  * Fork - LGPL
4849  * <script type="text/javascript">
4850  */
4851  
4852
4853 /*
4854  * This is code is also distributed under MIT license for use
4855  * with jQuery and prototype JavaScript libraries.
4856  */
4857 /**
4858  * @class Roo.DomQuery
4859 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).
4860 <p>
4861 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>
4862
4863 <p>
4864 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.
4865 </p>
4866 <h4>Element Selectors:</h4>
4867 <ul class="list">
4868     <li> <b>*</b> any element</li>
4869     <li> <b>E</b> an element with the tag E</li>
4870     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4871     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4872     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4873     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4874 </ul>
4875 <h4>Attribute Selectors:</h4>
4876 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4877 <ul class="list">
4878     <li> <b>E[foo]</b> has an attribute "foo"</li>
4879     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4880     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4881     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4882     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4883     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4884     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4885 </ul>
4886 <h4>Pseudo Classes:</h4>
4887 <ul class="list">
4888     <li> <b>E:first-child</b> E is the first child of its parent</li>
4889     <li> <b>E:last-child</b> E is the last child of its parent</li>
4890     <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>
4891     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4892     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4893     <li> <b>E:only-child</b> E is the only child of its parent</li>
4894     <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>
4895     <li> <b>E:first</b> the first E in the resultset</li>
4896     <li> <b>E:last</b> the last E in the resultset</li>
4897     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4898     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4899     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4900     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4901     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4902     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4903     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4904     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4905     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4906 </ul>
4907 <h4>CSS Value Selectors:</h4>
4908 <ul class="list">
4909     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4910     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4911     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4912     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4913     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4914     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4915 </ul>
4916  * @singleton
4917  */
4918 Roo.DomQuery = function(){
4919     var cache = {}, simpleCache = {}, valueCache = {};
4920     var nonSpace = /\S/;
4921     var trimRe = /^\s+|\s+$/g;
4922     var tplRe = /\{(\d+)\}/g;
4923     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4924     var tagTokenRe = /^(#)?([\w-\*]+)/;
4925     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4926
4927     function child(p, index){
4928         var i = 0;
4929         var n = p.firstChild;
4930         while(n){
4931             if(n.nodeType == 1){
4932                if(++i == index){
4933                    return n;
4934                }
4935             }
4936             n = n.nextSibling;
4937         }
4938         return null;
4939     };
4940
4941     function next(n){
4942         while((n = n.nextSibling) && n.nodeType != 1);
4943         return n;
4944     };
4945
4946     function prev(n){
4947         while((n = n.previousSibling) && n.nodeType != 1);
4948         return n;
4949     };
4950
4951     function children(d){
4952         var n = d.firstChild, ni = -1;
4953             while(n){
4954                 var nx = n.nextSibling;
4955                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4956                     d.removeChild(n);
4957                 }else{
4958                     n.nodeIndex = ++ni;
4959                 }
4960                 n = nx;
4961             }
4962             return this;
4963         };
4964
4965     function byClassName(c, a, v){
4966         if(!v){
4967             return c;
4968         }
4969         var r = [], ri = -1, cn;
4970         for(var i = 0, ci; ci = c[i]; i++){
4971             if((' '+ci.className+' ').indexOf(v) != -1){
4972                 r[++ri] = ci;
4973             }
4974         }
4975         return r;
4976     };
4977
4978     function attrValue(n, attr){
4979         if(!n.tagName && typeof n.length != "undefined"){
4980             n = n[0];
4981         }
4982         if(!n){
4983             return null;
4984         }
4985         if(attr == "for"){
4986             return n.htmlFor;
4987         }
4988         if(attr == "class" || attr == "className"){
4989             return n.className;
4990         }
4991         return n.getAttribute(attr) || n[attr];
4992
4993     };
4994
4995     function getNodes(ns, mode, tagName){
4996         var result = [], ri = -1, cs;
4997         if(!ns){
4998             return result;
4999         }
5000         tagName = tagName || "*";
5001         if(typeof ns.getElementsByTagName != "undefined"){
5002             ns = [ns];
5003         }
5004         if(!mode){
5005             for(var i = 0, ni; ni = ns[i]; i++){
5006                 cs = ni.getElementsByTagName(tagName);
5007                 for(var j = 0, ci; ci = cs[j]; j++){
5008                     result[++ri] = ci;
5009                 }
5010             }
5011         }else if(mode == "/" || mode == ">"){
5012             var utag = tagName.toUpperCase();
5013             for(var i = 0, ni, cn; ni = ns[i]; i++){
5014                 cn = ni.children || ni.childNodes;
5015                 for(var j = 0, cj; cj = cn[j]; j++){
5016                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5017                         result[++ri] = cj;
5018                     }
5019                 }
5020             }
5021         }else if(mode == "+"){
5022             var utag = tagName.toUpperCase();
5023             for(var i = 0, n; n = ns[i]; i++){
5024                 while((n = n.nextSibling) && n.nodeType != 1);
5025                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5026                     result[++ri] = n;
5027                 }
5028             }
5029         }else if(mode == "~"){
5030             for(var i = 0, n; n = ns[i]; i++){
5031                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5032                 if(n){
5033                     result[++ri] = n;
5034                 }
5035             }
5036         }
5037         return result;
5038     };
5039
5040     function concat(a, b){
5041         if(b.slice){
5042             return a.concat(b);
5043         }
5044         for(var i = 0, l = b.length; i < l; i++){
5045             a[a.length] = b[i];
5046         }
5047         return a;
5048     }
5049
5050     function byTag(cs, tagName){
5051         if(cs.tagName || cs == document){
5052             cs = [cs];
5053         }
5054         if(!tagName){
5055             return cs;
5056         }
5057         var r = [], ri = -1;
5058         tagName = tagName.toLowerCase();
5059         for(var i = 0, ci; ci = cs[i]; i++){
5060             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5061                 r[++ri] = ci;
5062             }
5063         }
5064         return r;
5065     };
5066
5067     function byId(cs, attr, id){
5068         if(cs.tagName || cs == document){
5069             cs = [cs];
5070         }
5071         if(!id){
5072             return cs;
5073         }
5074         var r = [], ri = -1;
5075         for(var i = 0,ci; ci = cs[i]; i++){
5076             if(ci && ci.id == id){
5077                 r[++ri] = ci;
5078                 return r;
5079             }
5080         }
5081         return r;
5082     };
5083
5084     function byAttribute(cs, attr, value, op, custom){
5085         var r = [], ri = -1, st = custom=="{";
5086         var f = Roo.DomQuery.operators[op];
5087         for(var i = 0, ci; ci = cs[i]; i++){
5088             var a;
5089             if(st){
5090                 a = Roo.DomQuery.getStyle(ci, attr);
5091             }
5092             else if(attr == "class" || attr == "className"){
5093                 a = ci.className;
5094             }else if(attr == "for"){
5095                 a = ci.htmlFor;
5096             }else if(attr == "href"){
5097                 a = ci.getAttribute("href", 2);
5098             }else{
5099                 a = ci.getAttribute(attr);
5100             }
5101             if((f && f(a, value)) || (!f && a)){
5102                 r[++ri] = ci;
5103             }
5104         }
5105         return r;
5106     };
5107
5108     function byPseudo(cs, name, value){
5109         return Roo.DomQuery.pseudos[name](cs, value);
5110     };
5111
5112     // This is for IE MSXML which does not support expandos.
5113     // IE runs the same speed using setAttribute, however FF slows way down
5114     // and Safari completely fails so they need to continue to use expandos.
5115     var isIE = window.ActiveXObject ? true : false;
5116
5117     // this eval is stop the compressor from
5118     // renaming the variable to something shorter
5119     
5120     /** eval:var:batch */
5121     var batch = 30803; 
5122
5123     var key = 30803;
5124
5125     function nodupIEXml(cs){
5126         var d = ++key;
5127         cs[0].setAttribute("_nodup", d);
5128         var r = [cs[0]];
5129         for(var i = 1, len = cs.length; i < len; i++){
5130             var c = cs[i];
5131             if(!c.getAttribute("_nodup") != d){
5132                 c.setAttribute("_nodup", d);
5133                 r[r.length] = c;
5134             }
5135         }
5136         for(var i = 0, len = cs.length; i < len; i++){
5137             cs[i].removeAttribute("_nodup");
5138         }
5139         return r;
5140     }
5141
5142     function nodup(cs){
5143         if(!cs){
5144             return [];
5145         }
5146         var len = cs.length, c, i, r = cs, cj, ri = -1;
5147         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5148             return cs;
5149         }
5150         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5151             return nodupIEXml(cs);
5152         }
5153         var d = ++key;
5154         cs[0]._nodup = d;
5155         for(i = 1; c = cs[i]; i++){
5156             if(c._nodup != d){
5157                 c._nodup = d;
5158             }else{
5159                 r = [];
5160                 for(var j = 0; j < i; j++){
5161                     r[++ri] = cs[j];
5162                 }
5163                 for(j = i+1; cj = cs[j]; j++){
5164                     if(cj._nodup != d){
5165                         cj._nodup = d;
5166                         r[++ri] = cj;
5167                     }
5168                 }
5169                 return r;
5170             }
5171         }
5172         return r;
5173     }
5174
5175     function quickDiffIEXml(c1, c2){
5176         var d = ++key;
5177         for(var i = 0, len = c1.length; i < len; i++){
5178             c1[i].setAttribute("_qdiff", d);
5179         }
5180         var r = [];
5181         for(var i = 0, len = c2.length; i < len; i++){
5182             if(c2[i].getAttribute("_qdiff") != d){
5183                 r[r.length] = c2[i];
5184             }
5185         }
5186         for(var i = 0, len = c1.length; i < len; i++){
5187            c1[i].removeAttribute("_qdiff");
5188         }
5189         return r;
5190     }
5191
5192     function quickDiff(c1, c2){
5193         var len1 = c1.length;
5194         if(!len1){
5195             return c2;
5196         }
5197         if(isIE && c1[0].selectSingleNode){
5198             return quickDiffIEXml(c1, c2);
5199         }
5200         var d = ++key;
5201         for(var i = 0; i < len1; i++){
5202             c1[i]._qdiff = d;
5203         }
5204         var r = [];
5205         for(var i = 0, len = c2.length; i < len; i++){
5206             if(c2[i]._qdiff != d){
5207                 r[r.length] = c2[i];
5208             }
5209         }
5210         return r;
5211     }
5212
5213     function quickId(ns, mode, root, id){
5214         if(ns == root){
5215            var d = root.ownerDocument || root;
5216            return d.getElementById(id);
5217         }
5218         ns = getNodes(ns, mode, "*");
5219         return byId(ns, null, id);
5220     }
5221
5222     return {
5223         getStyle : function(el, name){
5224             return Roo.fly(el).getStyle(name);
5225         },
5226         /**
5227          * Compiles a selector/xpath query into a reusable function. The returned function
5228          * takes one parameter "root" (optional), which is the context node from where the query should start.
5229          * @param {String} selector The selector/xpath query
5230          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5231          * @return {Function}
5232          */
5233         compile : function(path, type){
5234             type = type || "select";
5235             
5236             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5237             var q = path, mode, lq;
5238             var tk = Roo.DomQuery.matchers;
5239             var tklen = tk.length;
5240             var mm;
5241
5242             // accept leading mode switch
5243             var lmode = q.match(modeRe);
5244             if(lmode && lmode[1]){
5245                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5246                 q = q.replace(lmode[1], "");
5247             }
5248             // strip leading slashes
5249             while(path.substr(0, 1)=="/"){
5250                 path = path.substr(1);
5251             }
5252
5253             while(q && lq != q){
5254                 lq = q;
5255                 var tm = q.match(tagTokenRe);
5256                 if(type == "select"){
5257                     if(tm){
5258                         if(tm[1] == "#"){
5259                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5260                         }else{
5261                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5262                         }
5263                         q = q.replace(tm[0], "");
5264                     }else if(q.substr(0, 1) != '@'){
5265                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5266                     }
5267                 }else{
5268                     if(tm){
5269                         if(tm[1] == "#"){
5270                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5271                         }else{
5272                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5273                         }
5274                         q = q.replace(tm[0], "");
5275                     }
5276                 }
5277                 while(!(mm = q.match(modeRe))){
5278                     var matched = false;
5279                     for(var j = 0; j < tklen; j++){
5280                         var t = tk[j];
5281                         var m = q.match(t.re);
5282                         if(m){
5283                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5284                                                     return m[i];
5285                                                 });
5286                             q = q.replace(m[0], "");
5287                             matched = true;
5288                             break;
5289                         }
5290                     }
5291                     // prevent infinite loop on bad selector
5292                     if(!matched){
5293                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5294                     }
5295                 }
5296                 if(mm[1]){
5297                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5298                     q = q.replace(mm[1], "");
5299                 }
5300             }
5301             fn[fn.length] = "return nodup(n);\n}";
5302             
5303              /** 
5304               * list of variables that need from compression as they are used by eval.
5305              *  eval:var:batch 
5306              *  eval:var:nodup
5307              *  eval:var:byTag
5308              *  eval:var:ById
5309              *  eval:var:getNodes
5310              *  eval:var:quickId
5311              *  eval:var:mode
5312              *  eval:var:root
5313              *  eval:var:n
5314              *  eval:var:byClassName
5315              *  eval:var:byPseudo
5316              *  eval:var:byAttribute
5317              *  eval:var:attrValue
5318              * 
5319              **/ 
5320             eval(fn.join(""));
5321             return f;
5322         },
5323
5324         /**
5325          * Selects a group of elements.
5326          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5327          * @param {Node} root (optional) The start of the query (defaults to document).
5328          * @return {Array}
5329          */
5330         select : function(path, root, type){
5331             if(!root || root == document){
5332                 root = document;
5333             }
5334             if(typeof root == "string"){
5335                 root = document.getElementById(root);
5336             }
5337             var paths = path.split(",");
5338             var results = [];
5339             for(var i = 0, len = paths.length; i < len; i++){
5340                 var p = paths[i].replace(trimRe, "");
5341                 if(!cache[p]){
5342                     cache[p] = Roo.DomQuery.compile(p);
5343                     if(!cache[p]){
5344                         throw p + " is not a valid selector";
5345                     }
5346                 }
5347                 var result = cache[p](root);
5348                 if(result && result != document){
5349                     results = results.concat(result);
5350                 }
5351             }
5352             if(paths.length > 1){
5353                 return nodup(results);
5354             }
5355             return results;
5356         },
5357
5358         /**
5359          * Selects a single element.
5360          * @param {String} selector The selector/xpath query
5361          * @param {Node} root (optional) The start of the query (defaults to document).
5362          * @return {Element}
5363          */
5364         selectNode : function(path, root){
5365             return Roo.DomQuery.select(path, root)[0];
5366         },
5367
5368         /**
5369          * Selects the value of a node, optionally replacing null with the defaultValue.
5370          * @param {String} selector The selector/xpath query
5371          * @param {Node} root (optional) The start of the query (defaults to document).
5372          * @param {String} defaultValue
5373          */
5374         selectValue : function(path, root, defaultValue){
5375             path = path.replace(trimRe, "");
5376             if(!valueCache[path]){
5377                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5378             }
5379             var n = valueCache[path](root);
5380             n = n[0] ? n[0] : n;
5381             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5382             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5383         },
5384
5385         /**
5386          * Selects the value of a node, parsing integers and floats.
5387          * @param {String} selector The selector/xpath query
5388          * @param {Node} root (optional) The start of the query (defaults to document).
5389          * @param {Number} defaultValue
5390          * @return {Number}
5391          */
5392         selectNumber : function(path, root, defaultValue){
5393             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5394             return parseFloat(v);
5395         },
5396
5397         /**
5398          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5399          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5400          * @param {String} selector The simple selector to test
5401          * @return {Boolean}
5402          */
5403         is : function(el, ss){
5404             if(typeof el == "string"){
5405                 el = document.getElementById(el);
5406             }
5407             var isArray = (el instanceof Array);
5408             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5409             return isArray ? (result.length == el.length) : (result.length > 0);
5410         },
5411
5412         /**
5413          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5414          * @param {Array} el An array of elements to filter
5415          * @param {String} selector The simple selector to test
5416          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5417          * the selector instead of the ones that match
5418          * @return {Array}
5419          */
5420         filter : function(els, ss, nonMatches){
5421             ss = ss.replace(trimRe, "");
5422             if(!simpleCache[ss]){
5423                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5424             }
5425             var result = simpleCache[ss](els);
5426             return nonMatches ? quickDiff(result, els) : result;
5427         },
5428
5429         /**
5430          * Collection of matching regular expressions and code snippets.
5431          */
5432         matchers : [{
5433                 re: /^\.([\w-]+)/,
5434                 select: 'n = byClassName(n, null, " {1} ");'
5435             }, {
5436                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5437                 select: 'n = byPseudo(n, "{1}", "{2}");'
5438             },{
5439                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5440                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5441             }, {
5442                 re: /^#([\w-]+)/,
5443                 select: 'n = byId(n, null, "{1}");'
5444             },{
5445                 re: /^@([\w-]+)/,
5446                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5447             }
5448         ],
5449
5450         /**
5451          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5452          * 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;.
5453          */
5454         operators : {
5455             "=" : function(a, v){
5456                 return a == v;
5457             },
5458             "!=" : function(a, v){
5459                 return a != v;
5460             },
5461             "^=" : function(a, v){
5462                 return a && a.substr(0, v.length) == v;
5463             },
5464             "$=" : function(a, v){
5465                 return a && a.substr(a.length-v.length) == v;
5466             },
5467             "*=" : function(a, v){
5468                 return a && a.indexOf(v) !== -1;
5469             },
5470             "%=" : function(a, v){
5471                 return (a % v) == 0;
5472             },
5473             "|=" : function(a, v){
5474                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5475             },
5476             "~=" : function(a, v){
5477                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5478             }
5479         },
5480
5481         /**
5482          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5483          * and the argument (if any) supplied in the selector.
5484          */
5485         pseudos : {
5486             "first-child" : function(c){
5487                 var r = [], ri = -1, n;
5488                 for(var i = 0, ci; ci = n = c[i]; i++){
5489                     while((n = n.previousSibling) && n.nodeType != 1);
5490                     if(!n){
5491                         r[++ri] = ci;
5492                     }
5493                 }
5494                 return r;
5495             },
5496
5497             "last-child" : function(c){
5498                 var r = [], ri = -1, n;
5499                 for(var i = 0, ci; ci = n = c[i]; i++){
5500                     while((n = n.nextSibling) && n.nodeType != 1);
5501                     if(!n){
5502                         r[++ri] = ci;
5503                     }
5504                 }
5505                 return r;
5506             },
5507
5508             "nth-child" : function(c, a) {
5509                 var r = [], ri = -1;
5510                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5511                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5512                 for(var i = 0, n; n = c[i]; i++){
5513                     var pn = n.parentNode;
5514                     if (batch != pn._batch) {
5515                         var j = 0;
5516                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5517                             if(cn.nodeType == 1){
5518                                cn.nodeIndex = ++j;
5519                             }
5520                         }
5521                         pn._batch = batch;
5522                     }
5523                     if (f == 1) {
5524                         if (l == 0 || n.nodeIndex == l){
5525                             r[++ri] = n;
5526                         }
5527                     } else if ((n.nodeIndex + l) % f == 0){
5528                         r[++ri] = n;
5529                     }
5530                 }
5531
5532                 return r;
5533             },
5534
5535             "only-child" : function(c){
5536                 var r = [], ri = -1;;
5537                 for(var i = 0, ci; ci = c[i]; i++){
5538                     if(!prev(ci) && !next(ci)){
5539                         r[++ri] = ci;
5540                     }
5541                 }
5542                 return r;
5543             },
5544
5545             "empty" : function(c){
5546                 var r = [], ri = -1;
5547                 for(var i = 0, ci; ci = c[i]; i++){
5548                     var cns = ci.childNodes, j = 0, cn, empty = true;
5549                     while(cn = cns[j]){
5550                         ++j;
5551                         if(cn.nodeType == 1 || cn.nodeType == 3){
5552                             empty = false;
5553                             break;
5554                         }
5555                     }
5556                     if(empty){
5557                         r[++ri] = ci;
5558                     }
5559                 }
5560                 return r;
5561             },
5562
5563             "contains" : function(c, v){
5564                 var r = [], ri = -1;
5565                 for(var i = 0, ci; ci = c[i]; i++){
5566                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5567                         r[++ri] = ci;
5568                     }
5569                 }
5570                 return r;
5571             },
5572
5573             "nodeValue" : function(c, v){
5574                 var r = [], ri = -1;
5575                 for(var i = 0, ci; ci = c[i]; i++){
5576                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5577                         r[++ri] = ci;
5578                     }
5579                 }
5580                 return r;
5581             },
5582
5583             "checked" : function(c){
5584                 var r = [], ri = -1;
5585                 for(var i = 0, ci; ci = c[i]; i++){
5586                     if(ci.checked == true){
5587                         r[++ri] = ci;
5588                     }
5589                 }
5590                 return r;
5591             },
5592
5593             "not" : function(c, ss){
5594                 return Roo.DomQuery.filter(c, ss, true);
5595             },
5596
5597             "odd" : function(c){
5598                 return this["nth-child"](c, "odd");
5599             },
5600
5601             "even" : function(c){
5602                 return this["nth-child"](c, "even");
5603             },
5604
5605             "nth" : function(c, a){
5606                 return c[a-1] || [];
5607             },
5608
5609             "first" : function(c){
5610                 return c[0] || [];
5611             },
5612
5613             "last" : function(c){
5614                 return c[c.length-1] || [];
5615             },
5616
5617             "has" : function(c, ss){
5618                 var s = Roo.DomQuery.select;
5619                 var r = [], ri = -1;
5620                 for(var i = 0, ci; ci = c[i]; i++){
5621                     if(s(ss, ci).length > 0){
5622                         r[++ri] = ci;
5623                     }
5624                 }
5625                 return r;
5626             },
5627
5628             "next" : function(c, ss){
5629                 var is = Roo.DomQuery.is;
5630                 var r = [], ri = -1;
5631                 for(var i = 0, ci; ci = c[i]; i++){
5632                     var n = next(ci);
5633                     if(n && is(n, ss)){
5634                         r[++ri] = ci;
5635                     }
5636                 }
5637                 return r;
5638             },
5639
5640             "prev" : function(c, ss){
5641                 var is = Roo.DomQuery.is;
5642                 var r = [], ri = -1;
5643                 for(var i = 0, ci; ci = c[i]; i++){
5644                     var n = prev(ci);
5645                     if(n && is(n, ss)){
5646                         r[++ri] = ci;
5647                     }
5648                 }
5649                 return r;
5650             }
5651         }
5652     };
5653 }();
5654
5655 /**
5656  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5657  * @param {String} path The selector/xpath query
5658  * @param {Node} root (optional) The start of the query (defaults to document).
5659  * @return {Array}
5660  * @member Roo
5661  * @method query
5662  */
5663 Roo.query = Roo.DomQuery.select;
5664 /*
5665  * Based on:
5666  * Ext JS Library 1.1.1
5667  * Copyright(c) 2006-2007, Ext JS, LLC.
5668  *
5669  * Originally Released Under LGPL - original licence link has changed is not relivant.
5670  *
5671  * Fork - LGPL
5672  * <script type="text/javascript">
5673  */
5674
5675 /**
5676  * @class Roo.util.Observable
5677  * Base class that provides a common interface for publishing events. Subclasses are expected to
5678  * to have a property "events" with all the events defined.<br>
5679  * For example:
5680  * <pre><code>
5681  Employee = function(name){
5682     this.name = name;
5683     this.addEvents({
5684         "fired" : true,
5685         "quit" : true
5686     });
5687  }
5688  Roo.extend(Employee, Roo.util.Observable);
5689 </code></pre>
5690  * @param {Object} config properties to use (incuding events / listeners)
5691  */
5692
5693 Roo.util.Observable = function(cfg){
5694     
5695     cfg = cfg|| {};
5696     this.addEvents(cfg.events || {});
5697     if (cfg.events) {
5698         delete cfg.events; // make sure
5699     }
5700      
5701     Roo.apply(this, cfg);
5702     
5703     if(this.listeners){
5704         this.on(this.listeners);
5705         delete this.listeners;
5706     }
5707 };
5708 Roo.util.Observable.prototype = {
5709     /** 
5710  * @cfg {Object} listeners  list of events and functions to call for this object, 
5711  * For example :
5712  * <pre><code>
5713     listeners :  { 
5714        'click' : function(e) {
5715            ..... 
5716         } ,
5717         .... 
5718     } 
5719   </code></pre>
5720  */
5721     
5722     
5723     /**
5724      * Fires the specified event with the passed parameters (minus the event name).
5725      * @param {String} eventName
5726      * @param {Object...} args Variable number of parameters are passed to handlers
5727      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5728      */
5729     fireEvent : function(){
5730         var ce = this.events[arguments[0].toLowerCase()];
5731         if(typeof ce == "object"){
5732             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5733         }else{
5734             return true;
5735         }
5736     },
5737
5738     // private
5739     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5740
5741     /**
5742      * Appends an event handler to this component
5743      * @param {String}   eventName The type of event to listen for
5744      * @param {Function} handler The method the event invokes
5745      * @param {Object}   scope (optional) The scope in which to execute the handler
5746      * function. The handler function's "this" context.
5747      * @param {Object}   options (optional) An object containing handler configuration
5748      * properties. This may contain any of the following properties:<ul>
5749      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5750      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5751      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5752      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5753      * by the specified number of milliseconds. If the event fires again within that time, the original
5754      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5755      * </ul><br>
5756      * <p>
5757      * <b>Combining Options</b><br>
5758      * Using the options argument, it is possible to combine different types of listeners:<br>
5759      * <br>
5760      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5761                 <pre><code>
5762                 el.on('click', this.onClick, this, {
5763                         single: true,
5764                 delay: 100,
5765                 forumId: 4
5766                 });
5767                 </code></pre>
5768      * <p>
5769      * <b>Attaching multiple handlers in 1 call</b><br>
5770      * The method also allows for a single argument to be passed which is a config object containing properties
5771      * which specify multiple handlers.
5772      * <pre><code>
5773                 el.on({
5774                         'click': {
5775                         fn: this.onClick,
5776                         scope: this,
5777                         delay: 100
5778                 }, 
5779                 'mouseover': {
5780                         fn: this.onMouseOver,
5781                         scope: this
5782                 },
5783                 'mouseout': {
5784                         fn: this.onMouseOut,
5785                         scope: this
5786                 }
5787                 });
5788                 </code></pre>
5789      * <p>
5790      * Or a shorthand syntax which passes the same scope object to all handlers:
5791         <pre><code>
5792                 el.on({
5793                         'click': this.onClick,
5794                 'mouseover': this.onMouseOver,
5795                 'mouseout': this.onMouseOut,
5796                 scope: this
5797                 });
5798                 </code></pre>
5799      */
5800     addListener : function(eventName, fn, scope, o){
5801         if(typeof eventName == "object"){
5802             o = eventName;
5803             for(var e in o){
5804                 if(this.filterOptRe.test(e)){
5805                     continue;
5806                 }
5807                 if(typeof o[e] == "function"){
5808                     // shared options
5809                     this.addListener(e, o[e], o.scope,  o);
5810                 }else{
5811                     // individual options
5812                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5813                 }
5814             }
5815             return;
5816         }
5817         o = (!o || typeof o == "boolean") ? {} : o;
5818         eventName = eventName.toLowerCase();
5819         var ce = this.events[eventName] || true;
5820         if(typeof ce == "boolean"){
5821             ce = new Roo.util.Event(this, eventName);
5822             this.events[eventName] = ce;
5823         }
5824         ce.addListener(fn, scope, o);
5825     },
5826
5827     /**
5828      * Removes a listener
5829      * @param {String}   eventName     The type of event to listen for
5830      * @param {Function} handler        The handler to remove
5831      * @param {Object}   scope  (optional) The scope (this object) for the handler
5832      */
5833     removeListener : function(eventName, fn, scope){
5834         var ce = this.events[eventName.toLowerCase()];
5835         if(typeof ce == "object"){
5836             ce.removeListener(fn, scope);
5837         }
5838     },
5839
5840     /**
5841      * Removes all listeners for this object
5842      */
5843     purgeListeners : function(){
5844         for(var evt in this.events){
5845             if(typeof this.events[evt] == "object"){
5846                  this.events[evt].clearListeners();
5847             }
5848         }
5849     },
5850
5851     relayEvents : function(o, events){
5852         var createHandler = function(ename){
5853             return function(){
5854                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5855             };
5856         };
5857         for(var i = 0, len = events.length; i < len; i++){
5858             var ename = events[i];
5859             if(!this.events[ename]){ this.events[ename] = true; };
5860             o.on(ename, createHandler(ename), this);
5861         }
5862     },
5863
5864     /**
5865      * Used to define events on this Observable
5866      * @param {Object} object The object with the events defined
5867      */
5868     addEvents : function(o){
5869         if(!this.events){
5870             this.events = {};
5871         }
5872         Roo.applyIf(this.events, o);
5873     },
5874
5875     /**
5876      * Checks to see if this object has any listeners for a specified event
5877      * @param {String} eventName The name of the event to check for
5878      * @return {Boolean} True if the event is being listened for, else false
5879      */
5880     hasListener : function(eventName){
5881         var e = this.events[eventName];
5882         return typeof e == "object" && e.listeners.length > 0;
5883     }
5884 };
5885 /**
5886  * Appends an event handler to this element (shorthand for addListener)
5887  * @param {String}   eventName     The type of event to listen for
5888  * @param {Function} handler        The method the event invokes
5889  * @param {Object}   scope (optional) The scope in which to execute the handler
5890  * function. The handler function's "this" context.
5891  * @param {Object}   options  (optional)
5892  * @method
5893  */
5894 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5895 /**
5896  * Removes a listener (shorthand for removeListener)
5897  * @param {String}   eventName     The type of event to listen for
5898  * @param {Function} handler        The handler to remove
5899  * @param {Object}   scope  (optional) The scope (this object) for the handler
5900  * @method
5901  */
5902 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5903
5904 /**
5905  * Starts capture on the specified Observable. All events will be passed
5906  * to the supplied function with the event name + standard signature of the event
5907  * <b>before</b> the event is fired. If the supplied function returns false,
5908  * the event will not fire.
5909  * @param {Observable} o The Observable to capture
5910  * @param {Function} fn The function to call
5911  * @param {Object} scope (optional) The scope (this object) for the fn
5912  * @static
5913  */
5914 Roo.util.Observable.capture = function(o, fn, scope){
5915     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5916 };
5917
5918 /**
5919  * Removes <b>all</b> added captures from the Observable.
5920  * @param {Observable} o The Observable to release
5921  * @static
5922  */
5923 Roo.util.Observable.releaseCapture = function(o){
5924     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5925 };
5926
5927 (function(){
5928
5929     var createBuffered = function(h, o, scope){
5930         var task = new Roo.util.DelayedTask();
5931         return function(){
5932             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5933         };
5934     };
5935
5936     var createSingle = function(h, e, fn, scope){
5937         return function(){
5938             e.removeListener(fn, scope);
5939             return h.apply(scope, arguments);
5940         };
5941     };
5942
5943     var createDelayed = function(h, o, scope){
5944         return function(){
5945             var args = Array.prototype.slice.call(arguments, 0);
5946             setTimeout(function(){
5947                 h.apply(scope, args);
5948             }, o.delay || 10);
5949         };
5950     };
5951
5952     Roo.util.Event = function(obj, name){
5953         this.name = name;
5954         this.obj = obj;
5955         this.listeners = [];
5956     };
5957
5958     Roo.util.Event.prototype = {
5959         addListener : function(fn, scope, options){
5960             var o = options || {};
5961             scope = scope || this.obj;
5962             if(!this.isListening(fn, scope)){
5963                 var l = {fn: fn, scope: scope, options: o};
5964                 var h = fn;
5965                 if(o.delay){
5966                     h = createDelayed(h, o, scope);
5967                 }
5968                 if(o.single){
5969                     h = createSingle(h, this, fn, scope);
5970                 }
5971                 if(o.buffer){
5972                     h = createBuffered(h, o, scope);
5973                 }
5974                 l.fireFn = h;
5975                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5976                     this.listeners.push(l);
5977                 }else{
5978                     this.listeners = this.listeners.slice(0);
5979                     this.listeners.push(l);
5980                 }
5981             }
5982         },
5983
5984         findListener : function(fn, scope){
5985             scope = scope || this.obj;
5986             var ls = this.listeners;
5987             for(var i = 0, len = ls.length; i < len; i++){
5988                 var l = ls[i];
5989                 if(l.fn == fn && l.scope == scope){
5990                     return i;
5991                 }
5992             }
5993             return -1;
5994         },
5995
5996         isListening : function(fn, scope){
5997             return this.findListener(fn, scope) != -1;
5998         },
5999
6000         removeListener : function(fn, scope){
6001             var index;
6002             if((index = this.findListener(fn, scope)) != -1){
6003                 if(!this.firing){
6004                     this.listeners.splice(index, 1);
6005                 }else{
6006                     this.listeners = this.listeners.slice(0);
6007                     this.listeners.splice(index, 1);
6008                 }
6009                 return true;
6010             }
6011             return false;
6012         },
6013
6014         clearListeners : function(){
6015             this.listeners = [];
6016         },
6017
6018         fire : function(){
6019             var ls = this.listeners, scope, len = ls.length;
6020             if(len > 0){
6021                 this.firing = true;
6022                 var args = Array.prototype.slice.call(arguments, 0);
6023                 for(var i = 0; i < len; i++){
6024                     var l = ls[i];
6025                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6026                         this.firing = false;
6027                         return false;
6028                     }
6029                 }
6030                 this.firing = false;
6031             }
6032             return true;
6033         }
6034     };
6035 })();/*
6036  * Based on:
6037  * Ext JS Library 1.1.1
6038  * Copyright(c) 2006-2007, Ext JS, LLC.
6039  *
6040  * Originally Released Under LGPL - original licence link has changed is not relivant.
6041  *
6042  * Fork - LGPL
6043  * <script type="text/javascript">
6044  */
6045
6046 /**
6047  * @class Roo.EventManager
6048  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6049  * several useful events directly.
6050  * See {@link Roo.EventObject} for more details on normalized event objects.
6051  * @singleton
6052  */
6053 Roo.EventManager = function(){
6054     var docReadyEvent, docReadyProcId, docReadyState = false;
6055     var resizeEvent, resizeTask, textEvent, textSize;
6056     var E = Roo.lib.Event;
6057     var D = Roo.lib.Dom;
6058
6059     
6060     
6061
6062     var fireDocReady = function(){
6063         if(!docReadyState){
6064             docReadyState = true;
6065             Roo.isReady = true;
6066             if(docReadyProcId){
6067                 clearInterval(docReadyProcId);
6068             }
6069             if(Roo.isGecko || Roo.isOpera) {
6070                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6071             }
6072             if(Roo.isIE){
6073                 var defer = document.getElementById("ie-deferred-loader");
6074                 if(defer){
6075                     defer.onreadystatechange = null;
6076                     defer.parentNode.removeChild(defer);
6077                 }
6078             }
6079             if(docReadyEvent){
6080                 docReadyEvent.fire();
6081                 docReadyEvent.clearListeners();
6082             }
6083         }
6084     };
6085     
6086     var initDocReady = function(){
6087         docReadyEvent = new Roo.util.Event();
6088         if(Roo.isGecko || Roo.isOpera) {
6089             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6090         }else if(Roo.isIE){
6091             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6092             var defer = document.getElementById("ie-deferred-loader");
6093             defer.onreadystatechange = function(){
6094                 if(this.readyState == "complete"){
6095                     fireDocReady();
6096                 }
6097             };
6098         }else if(Roo.isSafari){ 
6099             docReadyProcId = setInterval(function(){
6100                 var rs = document.readyState;
6101                 if(rs == "complete") {
6102                     fireDocReady();     
6103                  }
6104             }, 10);
6105         }
6106         // no matter what, make sure it fires on load
6107         E.on(window, "load", fireDocReady);
6108     };
6109
6110     var createBuffered = function(h, o){
6111         var task = new Roo.util.DelayedTask(h);
6112         return function(e){
6113             // create new event object impl so new events don't wipe out properties
6114             e = new Roo.EventObjectImpl(e);
6115             task.delay(o.buffer, h, null, [e]);
6116         };
6117     };
6118
6119     var createSingle = function(h, el, ename, fn){
6120         return function(e){
6121             Roo.EventManager.removeListener(el, ename, fn);
6122             h(e);
6123         };
6124     };
6125
6126     var createDelayed = function(h, o){
6127         return function(e){
6128             // create new event object impl so new events don't wipe out properties
6129             e = new Roo.EventObjectImpl(e);
6130             setTimeout(function(){
6131                 h(e);
6132             }, o.delay || 10);
6133         };
6134     };
6135     var transitionEndVal = false;
6136     
6137     var transitionEnd = function()
6138     {
6139         if (transitionEndVal) {
6140             return transitionEndVal;
6141         }
6142         var el = document.createElement('div');
6143
6144         var transEndEventNames = {
6145             WebkitTransition : 'webkitTransitionEnd',
6146             MozTransition    : 'transitionend',
6147             OTransition      : 'oTransitionEnd otransitionend',
6148             transition       : 'transitionend'
6149         };
6150     
6151         for (var name in transEndEventNames) {
6152             if (el.style[name] !== undefined) {
6153                 transitionEndVal = transEndEventNames[name];
6154                 return  transitionEndVal ;
6155             }
6156         }
6157     }
6158     
6159
6160     var listen = function(element, ename, opt, fn, scope){
6161         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6162         fn = fn || o.fn; scope = scope || o.scope;
6163         var el = Roo.getDom(element);
6164         
6165         
6166         if(!el){
6167             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6168         }
6169         
6170         if (ename == 'transitionend') {
6171             ename = transitionEnd();
6172         }
6173         var h = function(e){
6174             e = Roo.EventObject.setEvent(e);
6175             var t;
6176             if(o.delegate){
6177                 t = e.getTarget(o.delegate, el);
6178                 if(!t){
6179                     return;
6180                 }
6181             }else{
6182                 t = e.target;
6183             }
6184             if(o.stopEvent === true){
6185                 e.stopEvent();
6186             }
6187             if(o.preventDefault === true){
6188                e.preventDefault();
6189             }
6190             if(o.stopPropagation === true){
6191                 e.stopPropagation();
6192             }
6193
6194             if(o.normalized === false){
6195                 e = e.browserEvent;
6196             }
6197
6198             fn.call(scope || el, e, t, o);
6199         };
6200         if(o.delay){
6201             h = createDelayed(h, o);
6202         }
6203         if(o.single){
6204             h = createSingle(h, el, ename, fn);
6205         }
6206         if(o.buffer){
6207             h = createBuffered(h, o);
6208         }
6209         fn._handlers = fn._handlers || [];
6210         
6211         
6212         fn._handlers.push([Roo.id(el), ename, h]);
6213         
6214         
6215          
6216         E.on(el, ename, h);
6217         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6218             el.addEventListener("DOMMouseScroll", h, false);
6219             E.on(window, 'unload', function(){
6220                 el.removeEventListener("DOMMouseScroll", h, false);
6221             });
6222         }
6223         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6224             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6225         }
6226         return h;
6227     };
6228
6229     var stopListening = function(el, ename, fn){
6230         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6231         if(hds){
6232             for(var i = 0, len = hds.length; i < len; i++){
6233                 var h = hds[i];
6234                 if(h[0] == id && h[1] == ename){
6235                     hd = h[2];
6236                     hds.splice(i, 1);
6237                     break;
6238                 }
6239             }
6240         }
6241         E.un(el, ename, hd);
6242         el = Roo.getDom(el);
6243         if(ename == "mousewheel" && el.addEventListener){
6244             el.removeEventListener("DOMMouseScroll", hd, false);
6245         }
6246         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6247             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6248         }
6249     };
6250
6251     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6252     
6253     var pub = {
6254         
6255         
6256         /** 
6257          * Fix for doc tools
6258          * @scope Roo.EventManager
6259          */
6260         
6261         
6262         /** 
6263          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6264          * object with a Roo.EventObject
6265          * @param {Function} fn        The method the event invokes
6266          * @param {Object}   scope    An object that becomes the scope of the handler
6267          * @param {boolean}  override If true, the obj passed in becomes
6268          *                             the execution scope of the listener
6269          * @return {Function} The wrapped function
6270          * @deprecated
6271          */
6272         wrap : function(fn, scope, override){
6273             return function(e){
6274                 Roo.EventObject.setEvent(e);
6275                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6276             };
6277         },
6278         
6279         /**
6280      * Appends an event handler to an element (shorthand for addListener)
6281      * @param {String/HTMLElement}   element        The html element or id to assign the
6282      * @param {String}   eventName The type of event to listen for
6283      * @param {Function} handler The method the event invokes
6284      * @param {Object}   scope (optional) The scope in which to execute the handler
6285      * function. The handler function's "this" context.
6286      * @param {Object}   options (optional) An object containing handler configuration
6287      * properties. This may contain any of the following properties:<ul>
6288      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6289      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6290      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6291      * <li>preventDefault {Boolean} True to prevent the default action</li>
6292      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6293      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6294      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6295      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6296      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6297      * by the specified number of milliseconds. If the event fires again within that time, the original
6298      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6299      * </ul><br>
6300      * <p>
6301      * <b>Combining Options</b><br>
6302      * Using the options argument, it is possible to combine different types of listeners:<br>
6303      * <br>
6304      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6305      * Code:<pre><code>
6306 el.on('click', this.onClick, this, {
6307     single: true,
6308     delay: 100,
6309     stopEvent : true,
6310     forumId: 4
6311 });</code></pre>
6312      * <p>
6313      * <b>Attaching multiple handlers in 1 call</b><br>
6314       * The method also allows for a single argument to be passed which is a config object containing properties
6315      * which specify multiple handlers.
6316      * <p>
6317      * Code:<pre><code>
6318 el.on({
6319     'click' : {
6320         fn: this.onClick
6321         scope: this,
6322         delay: 100
6323     },
6324     'mouseover' : {
6325         fn: this.onMouseOver
6326         scope: this
6327     },
6328     'mouseout' : {
6329         fn: this.onMouseOut
6330         scope: this
6331     }
6332 });</code></pre>
6333      * <p>
6334      * Or a shorthand syntax:<br>
6335      * Code:<pre><code>
6336 el.on({
6337     'click' : this.onClick,
6338     'mouseover' : this.onMouseOver,
6339     'mouseout' : this.onMouseOut
6340     scope: this
6341 });</code></pre>
6342      */
6343         addListener : function(element, eventName, fn, scope, options){
6344             if(typeof eventName == "object"){
6345                 var o = eventName;
6346                 for(var e in o){
6347                     if(propRe.test(e)){
6348                         continue;
6349                     }
6350                     if(typeof o[e] == "function"){
6351                         // shared options
6352                         listen(element, e, o, o[e], o.scope);
6353                     }else{
6354                         // individual options
6355                         listen(element, e, o[e]);
6356                     }
6357                 }
6358                 return;
6359             }
6360             return listen(element, eventName, options, fn, scope);
6361         },
6362         
6363         /**
6364          * Removes an event handler
6365          *
6366          * @param {String/HTMLElement}   element        The id or html element to remove the 
6367          *                             event from
6368          * @param {String}   eventName     The type of event
6369          * @param {Function} fn
6370          * @return {Boolean} True if a listener was actually removed
6371          */
6372         removeListener : function(element, eventName, fn){
6373             return stopListening(element, eventName, fn);
6374         },
6375         
6376         /**
6377          * Fires when the document is ready (before onload and before images are loaded). Can be 
6378          * accessed shorthanded Roo.onReady().
6379          * @param {Function} fn        The method the event invokes
6380          * @param {Object}   scope    An  object that becomes the scope of the handler
6381          * @param {boolean}  options
6382          */
6383         onDocumentReady : function(fn, scope, options){
6384             if(docReadyState){ // if it already fired
6385                 docReadyEvent.addListener(fn, scope, options);
6386                 docReadyEvent.fire();
6387                 docReadyEvent.clearListeners();
6388                 return;
6389             }
6390             if(!docReadyEvent){
6391                 initDocReady();
6392             }
6393             docReadyEvent.addListener(fn, scope, options);
6394         },
6395         
6396         /**
6397          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6398          * @param {Function} fn        The method the event invokes
6399          * @param {Object}   scope    An object that becomes the scope of the handler
6400          * @param {boolean}  options
6401          */
6402         onWindowResize : function(fn, scope, options){
6403             if(!resizeEvent){
6404                 resizeEvent = new Roo.util.Event();
6405                 resizeTask = new Roo.util.DelayedTask(function(){
6406                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6407                 });
6408                 E.on(window, "resize", function(){
6409                     if(Roo.isIE){
6410                         resizeTask.delay(50);
6411                     }else{
6412                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6413                     }
6414                 });
6415             }
6416             resizeEvent.addListener(fn, scope, options);
6417         },
6418
6419         /**
6420          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6421          * @param {Function} fn        The method the event invokes
6422          * @param {Object}   scope    An object that becomes the scope of the handler
6423          * @param {boolean}  options
6424          */
6425         onTextResize : function(fn, scope, options){
6426             if(!textEvent){
6427                 textEvent = new Roo.util.Event();
6428                 var textEl = new Roo.Element(document.createElement('div'));
6429                 textEl.dom.className = 'x-text-resize';
6430                 textEl.dom.innerHTML = 'X';
6431                 textEl.appendTo(document.body);
6432                 textSize = textEl.dom.offsetHeight;
6433                 setInterval(function(){
6434                     if(textEl.dom.offsetHeight != textSize){
6435                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6436                     }
6437                 }, this.textResizeInterval);
6438             }
6439             textEvent.addListener(fn, scope, options);
6440         },
6441
6442         /**
6443          * Removes the passed window resize listener.
6444          * @param {Function} fn        The method the event invokes
6445          * @param {Object}   scope    The scope of handler
6446          */
6447         removeResizeListener : function(fn, scope){
6448             if(resizeEvent){
6449                 resizeEvent.removeListener(fn, scope);
6450             }
6451         },
6452
6453         // private
6454         fireResize : function(){
6455             if(resizeEvent){
6456                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6457             }   
6458         },
6459         /**
6460          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6461          */
6462         ieDeferSrc : false,
6463         /**
6464          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6465          */
6466         textResizeInterval : 50
6467     };
6468     
6469     /**
6470      * Fix for doc tools
6471      * @scopeAlias pub=Roo.EventManager
6472      */
6473     
6474      /**
6475      * Appends an event handler to an element (shorthand for addListener)
6476      * @param {String/HTMLElement}   element        The html element or id to assign the
6477      * @param {String}   eventName The type of event to listen for
6478      * @param {Function} handler The method the event invokes
6479      * @param {Object}   scope (optional) The scope in which to execute the handler
6480      * function. The handler function's "this" context.
6481      * @param {Object}   options (optional) An object containing handler configuration
6482      * properties. This may contain any of the following properties:<ul>
6483      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6484      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6485      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6486      * <li>preventDefault {Boolean} True to prevent the default action</li>
6487      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6488      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6489      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6490      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6491      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6492      * by the specified number of milliseconds. If the event fires again within that time, the original
6493      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6494      * </ul><br>
6495      * <p>
6496      * <b>Combining Options</b><br>
6497      * Using the options argument, it is possible to combine different types of listeners:<br>
6498      * <br>
6499      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6500      * Code:<pre><code>
6501 el.on('click', this.onClick, this, {
6502     single: true,
6503     delay: 100,
6504     stopEvent : true,
6505     forumId: 4
6506 });</code></pre>
6507      * <p>
6508      * <b>Attaching multiple handlers in 1 call</b><br>
6509       * The method also allows for a single argument to be passed which is a config object containing properties
6510      * which specify multiple handlers.
6511      * <p>
6512      * Code:<pre><code>
6513 el.on({
6514     'click' : {
6515         fn: this.onClick
6516         scope: this,
6517         delay: 100
6518     },
6519     'mouseover' : {
6520         fn: this.onMouseOver
6521         scope: this
6522     },
6523     'mouseout' : {
6524         fn: this.onMouseOut
6525         scope: this
6526     }
6527 });</code></pre>
6528      * <p>
6529      * Or a shorthand syntax:<br>
6530      * Code:<pre><code>
6531 el.on({
6532     'click' : this.onClick,
6533     'mouseover' : this.onMouseOver,
6534     'mouseout' : this.onMouseOut
6535     scope: this
6536 });</code></pre>
6537      */
6538     pub.on = pub.addListener;
6539     pub.un = pub.removeListener;
6540
6541     pub.stoppedMouseDownEvent = new Roo.util.Event();
6542     return pub;
6543 }();
6544 /**
6545   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6546   * @param {Function} fn        The method the event invokes
6547   * @param {Object}   scope    An  object that becomes the scope of the handler
6548   * @param {boolean}  override If true, the obj passed in becomes
6549   *                             the execution scope of the listener
6550   * @member Roo
6551   * @method onReady
6552  */
6553 Roo.onReady = Roo.EventManager.onDocumentReady;
6554
6555 Roo.onReady(function(){
6556     var bd = Roo.get(document.body);
6557     if(!bd){ return; }
6558
6559     var cls = [
6560             Roo.isIE ? "roo-ie"
6561             : Roo.isGecko ? "roo-gecko"
6562             : Roo.isOpera ? "roo-opera"
6563             : Roo.isSafari ? "roo-safari" : ""];
6564
6565     if(Roo.isMac){
6566         cls.push("roo-mac");
6567     }
6568     if(Roo.isLinux){
6569         cls.push("roo-linux");
6570     }
6571     if(Roo.isBorderBox){
6572         cls.push('roo-border-box');
6573     }
6574     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6575         var p = bd.dom.parentNode;
6576         if(p){
6577             p.className += ' roo-strict';
6578         }
6579     }
6580     bd.addClass(cls.join(' '));
6581 });
6582
6583 /**
6584  * @class Roo.EventObject
6585  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6586  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6587  * Example:
6588  * <pre><code>
6589  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6590     e.preventDefault();
6591     var target = e.getTarget();
6592     ...
6593  }
6594  var myDiv = Roo.get("myDiv");
6595  myDiv.on("click", handleClick);
6596  //or
6597  Roo.EventManager.on("myDiv", 'click', handleClick);
6598  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6599  </code></pre>
6600  * @singleton
6601  */
6602 Roo.EventObject = function(){
6603     
6604     var E = Roo.lib.Event;
6605     
6606     // safari keypress events for special keys return bad keycodes
6607     var safariKeys = {
6608         63234 : 37, // left
6609         63235 : 39, // right
6610         63232 : 38, // up
6611         63233 : 40, // down
6612         63276 : 33, // page up
6613         63277 : 34, // page down
6614         63272 : 46, // delete
6615         63273 : 36, // home
6616         63275 : 35  // end
6617     };
6618
6619     // normalize button clicks
6620     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6621                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6622
6623     Roo.EventObjectImpl = function(e){
6624         if(e){
6625             this.setEvent(e.browserEvent || e);
6626         }
6627     };
6628     Roo.EventObjectImpl.prototype = {
6629         /**
6630          * Used to fix doc tools.
6631          * @scope Roo.EventObject.prototype
6632          */
6633             
6634
6635         
6636         
6637         /** The normal browser event */
6638         browserEvent : null,
6639         /** The button pressed in a mouse event */
6640         button : -1,
6641         /** True if the shift key was down during the event */
6642         shiftKey : false,
6643         /** True if the control key was down during the event */
6644         ctrlKey : false,
6645         /** True if the alt key was down during the event */
6646         altKey : false,
6647
6648         /** Key constant 
6649         * @type Number */
6650         BACKSPACE : 8,
6651         /** Key constant 
6652         * @type Number */
6653         TAB : 9,
6654         /** Key constant 
6655         * @type Number */
6656         RETURN : 13,
6657         /** Key constant 
6658         * @type Number */
6659         ENTER : 13,
6660         /** Key constant 
6661         * @type Number */
6662         SHIFT : 16,
6663         /** Key constant 
6664         * @type Number */
6665         CONTROL : 17,
6666         /** Key constant 
6667         * @type Number */
6668         ESC : 27,
6669         /** Key constant 
6670         * @type Number */
6671         SPACE : 32,
6672         /** Key constant 
6673         * @type Number */
6674         PAGEUP : 33,
6675         /** Key constant 
6676         * @type Number */
6677         PAGEDOWN : 34,
6678         /** Key constant 
6679         * @type Number */
6680         END : 35,
6681         /** Key constant 
6682         * @type Number */
6683         HOME : 36,
6684         /** Key constant 
6685         * @type Number */
6686         LEFT : 37,
6687         /** Key constant 
6688         * @type Number */
6689         UP : 38,
6690         /** Key constant 
6691         * @type Number */
6692         RIGHT : 39,
6693         /** Key constant 
6694         * @type Number */
6695         DOWN : 40,
6696         /** Key constant 
6697         * @type Number */
6698         DELETE : 46,
6699         /** Key constant 
6700         * @type Number */
6701         F5 : 116,
6702
6703            /** @private */
6704         setEvent : function(e){
6705             if(e == this || (e && e.browserEvent)){ // already wrapped
6706                 return e;
6707             }
6708             this.browserEvent = e;
6709             if(e){
6710                 // normalize buttons
6711                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6712                 if(e.type == 'click' && this.button == -1){
6713                     this.button = 0;
6714                 }
6715                 this.type = e.type;
6716                 this.shiftKey = e.shiftKey;
6717                 // mac metaKey behaves like ctrlKey
6718                 this.ctrlKey = e.ctrlKey || e.metaKey;
6719                 this.altKey = e.altKey;
6720                 // in getKey these will be normalized for the mac
6721                 this.keyCode = e.keyCode;
6722                 // keyup warnings on firefox.
6723                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6724                 // cache the target for the delayed and or buffered events
6725                 this.target = E.getTarget(e);
6726                 // same for XY
6727                 this.xy = E.getXY(e);
6728             }else{
6729                 this.button = -1;
6730                 this.shiftKey = false;
6731                 this.ctrlKey = false;
6732                 this.altKey = false;
6733                 this.keyCode = 0;
6734                 this.charCode =0;
6735                 this.target = null;
6736                 this.xy = [0, 0];
6737             }
6738             return this;
6739         },
6740
6741         /**
6742          * Stop the event (preventDefault and stopPropagation)
6743          */
6744         stopEvent : function(){
6745             if(this.browserEvent){
6746                 if(this.browserEvent.type == 'mousedown'){
6747                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6748                 }
6749                 E.stopEvent(this.browserEvent);
6750             }
6751         },
6752
6753         /**
6754          * Prevents the browsers default handling of the event.
6755          */
6756         preventDefault : function(){
6757             if(this.browserEvent){
6758                 E.preventDefault(this.browserEvent);
6759             }
6760         },
6761
6762         /** @private */
6763         isNavKeyPress : function(){
6764             var k = this.keyCode;
6765             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6766             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6767         },
6768
6769         isSpecialKey : function(){
6770             var k = this.keyCode;
6771             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6772             (k == 16) || (k == 17) ||
6773             (k >= 18 && k <= 20) ||
6774             (k >= 33 && k <= 35) ||
6775             (k >= 36 && k <= 39) ||
6776             (k >= 44 && k <= 45);
6777         },
6778         /**
6779          * Cancels bubbling of the event.
6780          */
6781         stopPropagation : function(){
6782             if(this.browserEvent){
6783                 if(this.type == 'mousedown'){
6784                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6785                 }
6786                 E.stopPropagation(this.browserEvent);
6787             }
6788         },
6789
6790         /**
6791          * Gets the key code for the event.
6792          * @return {Number}
6793          */
6794         getCharCode : function(){
6795             return this.charCode || this.keyCode;
6796         },
6797
6798         /**
6799          * Returns a normalized keyCode for the event.
6800          * @return {Number} The key code
6801          */
6802         getKey : function(){
6803             var k = this.keyCode || this.charCode;
6804             return Roo.isSafari ? (safariKeys[k] || k) : k;
6805         },
6806
6807         /**
6808          * Gets the x coordinate of the event.
6809          * @return {Number}
6810          */
6811         getPageX : function(){
6812             return this.xy[0];
6813         },
6814
6815         /**
6816          * Gets the y coordinate of the event.
6817          * @return {Number}
6818          */
6819         getPageY : function(){
6820             return this.xy[1];
6821         },
6822
6823         /**
6824          * Gets the time of the event.
6825          * @return {Number}
6826          */
6827         getTime : function(){
6828             if(this.browserEvent){
6829                 return E.getTime(this.browserEvent);
6830             }
6831             return null;
6832         },
6833
6834         /**
6835          * Gets the page coordinates of the event.
6836          * @return {Array} The xy values like [x, y]
6837          */
6838         getXY : function(){
6839             return this.xy;
6840         },
6841
6842         /**
6843          * Gets the target for the event.
6844          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6845          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6846                 search as a number or element (defaults to 10 || document.body)
6847          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6848          * @return {HTMLelement}
6849          */
6850         getTarget : function(selector, maxDepth, returnEl){
6851             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6852         },
6853         /**
6854          * Gets the related target.
6855          * @return {HTMLElement}
6856          */
6857         getRelatedTarget : function(){
6858             if(this.browserEvent){
6859                 return E.getRelatedTarget(this.browserEvent);
6860             }
6861             return null;
6862         },
6863
6864         /**
6865          * Normalizes mouse wheel delta across browsers
6866          * @return {Number} The delta
6867          */
6868         getWheelDelta : function(){
6869             var e = this.browserEvent;
6870             var delta = 0;
6871             if(e.wheelDelta){ /* IE/Opera. */
6872                 delta = e.wheelDelta/120;
6873             }else if(e.detail){ /* Mozilla case. */
6874                 delta = -e.detail/3;
6875             }
6876             return delta;
6877         },
6878
6879         /**
6880          * Returns true if the control, meta, shift or alt key was pressed during this event.
6881          * @return {Boolean}
6882          */
6883         hasModifier : function(){
6884             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6885         },
6886
6887         /**
6888          * Returns true if the target of this event equals el or is a child of el
6889          * @param {String/HTMLElement/Element} el
6890          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6891          * @return {Boolean}
6892          */
6893         within : function(el, related){
6894             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6895             return t && Roo.fly(el).contains(t);
6896         },
6897
6898         getPoint : function(){
6899             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6900         }
6901     };
6902
6903     return new Roo.EventObjectImpl();
6904 }();
6905             
6906     /*
6907  * Based on:
6908  * Ext JS Library 1.1.1
6909  * Copyright(c) 2006-2007, Ext JS, LLC.
6910  *
6911  * Originally Released Under LGPL - original licence link has changed is not relivant.
6912  *
6913  * Fork - LGPL
6914  * <script type="text/javascript">
6915  */
6916
6917  
6918 // was in Composite Element!??!?!
6919  
6920 (function(){
6921     var D = Roo.lib.Dom;
6922     var E = Roo.lib.Event;
6923     var A = Roo.lib.Anim;
6924
6925     // local style camelizing for speed
6926     var propCache = {};
6927     var camelRe = /(-[a-z])/gi;
6928     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6929     var view = document.defaultView;
6930
6931 /**
6932  * @class Roo.Element
6933  * Represents an Element in the DOM.<br><br>
6934  * Usage:<br>
6935 <pre><code>
6936 var el = Roo.get("my-div");
6937
6938 // or with getEl
6939 var el = getEl("my-div");
6940
6941 // or with a DOM element
6942 var el = Roo.get(myDivElement);
6943 </code></pre>
6944  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6945  * each call instead of constructing a new one.<br><br>
6946  * <b>Animations</b><br />
6947  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6948  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6949 <pre>
6950 Option    Default   Description
6951 --------- --------  ---------------------------------------------
6952 duration  .35       The duration of the animation in seconds
6953 easing    easeOut   The YUI easing method
6954 callback  none      A function to execute when the anim completes
6955 scope     this      The scope (this) of the callback function
6956 </pre>
6957 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6958 * manipulate the animation. Here's an example:
6959 <pre><code>
6960 var el = Roo.get("my-div");
6961
6962 // no animation
6963 el.setWidth(100);
6964
6965 // default animation
6966 el.setWidth(100, true);
6967
6968 // animation with some options set
6969 el.setWidth(100, {
6970     duration: 1,
6971     callback: this.foo,
6972     scope: this
6973 });
6974
6975 // using the "anim" property to get the Anim object
6976 var opt = {
6977     duration: 1,
6978     callback: this.foo,
6979     scope: this
6980 };
6981 el.setWidth(100, opt);
6982 ...
6983 if(opt.anim.isAnimated()){
6984     opt.anim.stop();
6985 }
6986 </code></pre>
6987 * <b> Composite (Collections of) Elements</b><br />
6988  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6989  * @constructor Create a new Element directly.
6990  * @param {String/HTMLElement} element
6991  * @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).
6992  */
6993     Roo.Element = function(element, forceNew){
6994         var dom = typeof element == "string" ?
6995                 document.getElementById(element) : element;
6996         if(!dom){ // invalid id/element
6997             return null;
6998         }
6999         var id = dom.id;
7000         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7001             return Roo.Element.cache[id];
7002         }
7003
7004         /**
7005          * The DOM element
7006          * @type HTMLElement
7007          */
7008         this.dom = dom;
7009
7010         /**
7011          * The DOM element ID
7012          * @type String
7013          */
7014         this.id = id || Roo.id(dom);
7015     };
7016
7017     var El = Roo.Element;
7018
7019     El.prototype = {
7020         /**
7021          * The element's default display mode  (defaults to "")
7022          * @type String
7023          */
7024         originalDisplay : "",
7025
7026         visibilityMode : 1,
7027         /**
7028          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7029          * @type String
7030          */
7031         defaultUnit : "px",
7032         /**
7033          * Sets the element's visibility mode. When setVisible() is called it
7034          * will use this to determine whether to set the visibility or the display property.
7035          * @param visMode Element.VISIBILITY or Element.DISPLAY
7036          * @return {Roo.Element} this
7037          */
7038         setVisibilityMode : function(visMode){
7039             this.visibilityMode = visMode;
7040             return this;
7041         },
7042         /**
7043          * Convenience method for setVisibilityMode(Element.DISPLAY)
7044          * @param {String} display (optional) What to set display to when visible
7045          * @return {Roo.Element} this
7046          */
7047         enableDisplayMode : function(display){
7048             this.setVisibilityMode(El.DISPLAY);
7049             if(typeof display != "undefined") this.originalDisplay = display;
7050             return this;
7051         },
7052
7053         /**
7054          * 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)
7055          * @param {String} selector The simple selector to test
7056          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7057                 search as a number or element (defaults to 10 || document.body)
7058          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7059          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7060          */
7061         findParent : function(simpleSelector, maxDepth, returnEl){
7062             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7063             maxDepth = maxDepth || 50;
7064             if(typeof maxDepth != "number"){
7065                 stopEl = Roo.getDom(maxDepth);
7066                 maxDepth = 10;
7067             }
7068             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7069                 if(dq.is(p, simpleSelector)){
7070                     return returnEl ? Roo.get(p) : p;
7071                 }
7072                 depth++;
7073                 p = p.parentNode;
7074             }
7075             return null;
7076         },
7077
7078
7079         /**
7080          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7081          * @param {String} selector The simple selector to test
7082          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7083                 search as a number or element (defaults to 10 || document.body)
7084          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7085          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7086          */
7087         findParentNode : function(simpleSelector, maxDepth, returnEl){
7088             var p = Roo.fly(this.dom.parentNode, '_internal');
7089             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7090         },
7091
7092         /**
7093          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7094          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7095          * @param {String} selector The simple selector to test
7096          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7097                 search as a number or element (defaults to 10 || document.body)
7098          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7099          */
7100         up : function(simpleSelector, maxDepth){
7101             return this.findParentNode(simpleSelector, maxDepth, true);
7102         },
7103
7104
7105
7106         /**
7107          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7108          * @param {String} selector The simple selector to test
7109          * @return {Boolean} True if this element matches the selector, else false
7110          */
7111         is : function(simpleSelector){
7112             return Roo.DomQuery.is(this.dom, simpleSelector);
7113         },
7114
7115         /**
7116          * Perform animation on this element.
7117          * @param {Object} args The YUI animation control args
7118          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7119          * @param {Function} onComplete (optional) Function to call when animation completes
7120          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7121          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7122          * @return {Roo.Element} this
7123          */
7124         animate : function(args, duration, onComplete, easing, animType){
7125             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7126             return this;
7127         },
7128
7129         /*
7130          * @private Internal animation call
7131          */
7132         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7133             animType = animType || 'run';
7134             opt = opt || {};
7135             var anim = Roo.lib.Anim[animType](
7136                 this.dom, args,
7137                 (opt.duration || defaultDur) || .35,
7138                 (opt.easing || defaultEase) || 'easeOut',
7139                 function(){
7140                     Roo.callback(cb, this);
7141                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7142                 },
7143                 this
7144             );
7145             opt.anim = anim;
7146             return anim;
7147         },
7148
7149         // private legacy anim prep
7150         preanim : function(a, i){
7151             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7152         },
7153
7154         /**
7155          * Removes worthless text nodes
7156          * @param {Boolean} forceReclean (optional) By default the element
7157          * keeps track if it has been cleaned already so
7158          * you can call this over and over. However, if you update the element and
7159          * need to force a reclean, you can pass true.
7160          */
7161         clean : function(forceReclean){
7162             if(this.isCleaned && forceReclean !== true){
7163                 return this;
7164             }
7165             var ns = /\S/;
7166             var d = this.dom, n = d.firstChild, ni = -1;
7167             while(n){
7168                 var nx = n.nextSibling;
7169                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7170                     d.removeChild(n);
7171                 }else{
7172                     n.nodeIndex = ++ni;
7173                 }
7174                 n = nx;
7175             }
7176             this.isCleaned = true;
7177             return this;
7178         },
7179
7180         // private
7181         calcOffsetsTo : function(el){
7182             el = Roo.get(el);
7183             var d = el.dom;
7184             var restorePos = false;
7185             if(el.getStyle('position') == 'static'){
7186                 el.position('relative');
7187                 restorePos = true;
7188             }
7189             var x = 0, y =0;
7190             var op = this.dom;
7191             while(op && op != d && op.tagName != 'HTML'){
7192                 x+= op.offsetLeft;
7193                 y+= op.offsetTop;
7194                 op = op.offsetParent;
7195             }
7196             if(restorePos){
7197                 el.position('static');
7198             }
7199             return [x, y];
7200         },
7201
7202         /**
7203          * Scrolls this element into view within the passed container.
7204          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7205          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7206          * @return {Roo.Element} this
7207          */
7208         scrollIntoView : function(container, hscroll){
7209             var c = Roo.getDom(container) || document.body;
7210             var el = this.dom;
7211
7212             var o = this.calcOffsetsTo(c),
7213                 l = o[0],
7214                 t = o[1],
7215                 b = t+el.offsetHeight,
7216                 r = l+el.offsetWidth;
7217
7218             var ch = c.clientHeight;
7219             var ct = parseInt(c.scrollTop, 10);
7220             var cl = parseInt(c.scrollLeft, 10);
7221             var cb = ct + ch;
7222             var cr = cl + c.clientWidth;
7223
7224             if(t < ct){
7225                 c.scrollTop = t;
7226             }else if(b > cb){
7227                 c.scrollTop = b-ch;
7228             }
7229
7230             if(hscroll !== false){
7231                 if(l < cl){
7232                     c.scrollLeft = l;
7233                 }else if(r > cr){
7234                     c.scrollLeft = r-c.clientWidth;
7235                 }
7236             }
7237             return this;
7238         },
7239
7240         // private
7241         scrollChildIntoView : function(child, hscroll){
7242             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7243         },
7244
7245         /**
7246          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7247          * the new height may not be available immediately.
7248          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7249          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7250          * @param {Function} onComplete (optional) Function to call when animation completes
7251          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7252          * @return {Roo.Element} this
7253          */
7254         autoHeight : function(animate, duration, onComplete, easing){
7255             var oldHeight = this.getHeight();
7256             this.clip();
7257             this.setHeight(1); // force clipping
7258             setTimeout(function(){
7259                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7260                 if(!animate){
7261                     this.setHeight(height);
7262                     this.unclip();
7263                     if(typeof onComplete == "function"){
7264                         onComplete();
7265                     }
7266                 }else{
7267                     this.setHeight(oldHeight); // restore original height
7268                     this.setHeight(height, animate, duration, function(){
7269                         this.unclip();
7270                         if(typeof onComplete == "function") onComplete();
7271                     }.createDelegate(this), easing);
7272                 }
7273             }.createDelegate(this), 0);
7274             return this;
7275         },
7276
7277         /**
7278          * Returns true if this element is an ancestor of the passed element
7279          * @param {HTMLElement/String} el The element to check
7280          * @return {Boolean} True if this element is an ancestor of el, else false
7281          */
7282         contains : function(el){
7283             if(!el){return false;}
7284             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7285         },
7286
7287         /**
7288          * Checks whether the element is currently visible using both visibility and display properties.
7289          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7290          * @return {Boolean} True if the element is currently visible, else false
7291          */
7292         isVisible : function(deep) {
7293             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7294             if(deep !== true || !vis){
7295                 return vis;
7296             }
7297             var p = this.dom.parentNode;
7298             while(p && p.tagName.toLowerCase() != "body"){
7299                 if(!Roo.fly(p, '_isVisible').isVisible()){
7300                     return false;
7301                 }
7302                 p = p.parentNode;
7303             }
7304             return true;
7305         },
7306
7307         /**
7308          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7309          * @param {String} selector The CSS selector
7310          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7311          * @return {CompositeElement/CompositeElementLite} The composite element
7312          */
7313         select : function(selector, unique){
7314             return El.select(selector, unique, this.dom);
7315         },
7316
7317         /**
7318          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7319          * @param {String} selector The CSS selector
7320          * @return {Array} An array of the matched nodes
7321          */
7322         query : function(selector, unique){
7323             return Roo.DomQuery.select(selector, this.dom);
7324         },
7325
7326         /**
7327          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7328          * @param {String} selector The CSS selector
7329          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7330          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7331          */
7332         child : function(selector, returnDom){
7333             var n = Roo.DomQuery.selectNode(selector, this.dom);
7334             return returnDom ? n : Roo.get(n);
7335         },
7336
7337         /**
7338          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7339          * @param {String} selector The CSS selector
7340          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7341          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7342          */
7343         down : function(selector, returnDom){
7344             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7345             return returnDom ? n : Roo.get(n);
7346         },
7347
7348         /**
7349          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7350          * @param {String} group The group the DD object is member of
7351          * @param {Object} config The DD config object
7352          * @param {Object} overrides An object containing methods to override/implement on the DD object
7353          * @return {Roo.dd.DD} The DD object
7354          */
7355         initDD : function(group, config, overrides){
7356             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7357             return Roo.apply(dd, overrides);
7358         },
7359
7360         /**
7361          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7362          * @param {String} group The group the DDProxy object is member of
7363          * @param {Object} config The DDProxy config object
7364          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7365          * @return {Roo.dd.DDProxy} The DDProxy object
7366          */
7367         initDDProxy : function(group, config, overrides){
7368             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7369             return Roo.apply(dd, overrides);
7370         },
7371
7372         /**
7373          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7374          * @param {String} group The group the DDTarget object is member of
7375          * @param {Object} config The DDTarget config object
7376          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7377          * @return {Roo.dd.DDTarget} The DDTarget object
7378          */
7379         initDDTarget : function(group, config, overrides){
7380             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7381             return Roo.apply(dd, overrides);
7382         },
7383
7384         /**
7385          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7386          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7387          * @param {Boolean} visible Whether the element is visible
7388          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7389          * @return {Roo.Element} this
7390          */
7391          setVisible : function(visible, animate){
7392             if(!animate || !A){
7393                 if(this.visibilityMode == El.DISPLAY){
7394                     this.setDisplayed(visible);
7395                 }else{
7396                     this.fixDisplay();
7397                     this.dom.style.visibility = visible ? "visible" : "hidden";
7398                 }
7399             }else{
7400                 // closure for composites
7401                 var dom = this.dom;
7402                 var visMode = this.visibilityMode;
7403                 if(visible){
7404                     this.setOpacity(.01);
7405                     this.setVisible(true);
7406                 }
7407                 this.anim({opacity: { to: (visible?1:0) }},
7408                       this.preanim(arguments, 1),
7409                       null, .35, 'easeIn', function(){
7410                          if(!visible){
7411                              if(visMode == El.DISPLAY){
7412                                  dom.style.display = "none";
7413                              }else{
7414                                  dom.style.visibility = "hidden";
7415                              }
7416                              Roo.get(dom).setOpacity(1);
7417                          }
7418                      });
7419             }
7420             return this;
7421         },
7422
7423         /**
7424          * Returns true if display is not "none"
7425          * @return {Boolean}
7426          */
7427         isDisplayed : function() {
7428             return this.getStyle("display") != "none";
7429         },
7430
7431         /**
7432          * Toggles the element's visibility or display, depending on visibility mode.
7433          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7434          * @return {Roo.Element} this
7435          */
7436         toggle : function(animate){
7437             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7438             return this;
7439         },
7440
7441         /**
7442          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7443          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7444          * @return {Roo.Element} this
7445          */
7446         setDisplayed : function(value) {
7447             if(typeof value == "boolean"){
7448                value = value ? this.originalDisplay : "none";
7449             }
7450             this.setStyle("display", value);
7451             return this;
7452         },
7453
7454         /**
7455          * Tries to focus the element. Any exceptions are caught and ignored.
7456          * @return {Roo.Element} this
7457          */
7458         focus : function() {
7459             try{
7460                 this.dom.focus();
7461             }catch(e){}
7462             return this;
7463         },
7464
7465         /**
7466          * Tries to blur the element. Any exceptions are caught and ignored.
7467          * @return {Roo.Element} this
7468          */
7469         blur : function() {
7470             try{
7471                 this.dom.blur();
7472             }catch(e){}
7473             return this;
7474         },
7475
7476         /**
7477          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7478          * @param {String/Array} className The CSS class to add, or an array of classes
7479          * @return {Roo.Element} this
7480          */
7481         addClass : function(className){
7482             if(className instanceof Array){
7483                 for(var i = 0, len = className.length; i < len; i++) {
7484                     this.addClass(className[i]);
7485                 }
7486             }else{
7487                 if(className && !this.hasClass(className)){
7488                     this.dom.className = this.dom.className + " " + className;
7489                 }
7490             }
7491             return this;
7492         },
7493
7494         /**
7495          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7496          * @param {String/Array} className The CSS class to add, or an array of classes
7497          * @return {Roo.Element} this
7498          */
7499         radioClass : function(className){
7500             var siblings = this.dom.parentNode.childNodes;
7501             for(var i = 0; i < siblings.length; i++) {
7502                 var s = siblings[i];
7503                 if(s.nodeType == 1){
7504                     Roo.get(s).removeClass(className);
7505                 }
7506             }
7507             this.addClass(className);
7508             return this;
7509         },
7510
7511         /**
7512          * Removes one or more CSS classes from the element.
7513          * @param {String/Array} className The CSS class to remove, or an array of classes
7514          * @return {Roo.Element} this
7515          */
7516         removeClass : function(className){
7517             if(!className || !this.dom.className){
7518                 return this;
7519             }
7520             if(className instanceof Array){
7521                 for(var i = 0, len = className.length; i < len; i++) {
7522                     this.removeClass(className[i]);
7523                 }
7524             }else{
7525                 if(this.hasClass(className)){
7526                     var re = this.classReCache[className];
7527                     if (!re) {
7528                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7529                        this.classReCache[className] = re;
7530                     }
7531                     this.dom.className =
7532                         this.dom.className.replace(re, " ");
7533                 }
7534             }
7535             return this;
7536         },
7537
7538         // private
7539         classReCache: {},
7540
7541         /**
7542          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7543          * @param {String} className The CSS class to toggle
7544          * @return {Roo.Element} this
7545          */
7546         toggleClass : function(className){
7547             if(this.hasClass(className)){
7548                 this.removeClass(className);
7549             }else{
7550                 this.addClass(className);
7551             }
7552             return this;
7553         },
7554
7555         /**
7556          * Checks if the specified CSS class exists on this element's DOM node.
7557          * @param {String} className The CSS class to check for
7558          * @return {Boolean} True if the class exists, else false
7559          */
7560         hasClass : function(className){
7561             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7562         },
7563
7564         /**
7565          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7566          * @param {String} oldClassName The CSS class to replace
7567          * @param {String} newClassName The replacement CSS class
7568          * @return {Roo.Element} this
7569          */
7570         replaceClass : function(oldClassName, newClassName){
7571             this.removeClass(oldClassName);
7572             this.addClass(newClassName);
7573             return this;
7574         },
7575
7576         /**
7577          * Returns an object with properties matching the styles requested.
7578          * For example, el.getStyles('color', 'font-size', 'width') might return
7579          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7580          * @param {String} style1 A style name
7581          * @param {String} style2 A style name
7582          * @param {String} etc.
7583          * @return {Object} The style object
7584          */
7585         getStyles : function(){
7586             var a = arguments, len = a.length, r = {};
7587             for(var i = 0; i < len; i++){
7588                 r[a[i]] = this.getStyle(a[i]);
7589             }
7590             return r;
7591         },
7592
7593         /**
7594          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7595          * @param {String} property The style property whose value is returned.
7596          * @return {String} The current value of the style property for this element.
7597          */
7598         getStyle : function(){
7599             return view && view.getComputedStyle ?
7600                 function(prop){
7601                     var el = this.dom, v, cs, camel;
7602                     if(prop == 'float'){
7603                         prop = "cssFloat";
7604                     }
7605                     if(el.style && (v = el.style[prop])){
7606                         return v;
7607                     }
7608                     if(cs = view.getComputedStyle(el, "")){
7609                         if(!(camel = propCache[prop])){
7610                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7611                         }
7612                         return cs[camel];
7613                     }
7614                     return null;
7615                 } :
7616                 function(prop){
7617                     var el = this.dom, v, cs, camel;
7618                     if(prop == 'opacity'){
7619                         if(typeof el.style.filter == 'string'){
7620                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7621                             if(m){
7622                                 var fv = parseFloat(m[1]);
7623                                 if(!isNaN(fv)){
7624                                     return fv ? fv / 100 : 0;
7625                                 }
7626                             }
7627                         }
7628                         return 1;
7629                     }else if(prop == 'float'){
7630                         prop = "styleFloat";
7631                     }
7632                     if(!(camel = propCache[prop])){
7633                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7634                     }
7635                     if(v = el.style[camel]){
7636                         return v;
7637                     }
7638                     if(cs = el.currentStyle){
7639                         return cs[camel];
7640                     }
7641                     return null;
7642                 };
7643         }(),
7644
7645         /**
7646          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7647          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7648          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7649          * @return {Roo.Element} this
7650          */
7651         setStyle : function(prop, value){
7652             if(typeof prop == "string"){
7653                 
7654                 if (prop == 'float') {
7655                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7656                     return this;
7657                 }
7658                 
7659                 var camel;
7660                 if(!(camel = propCache[prop])){
7661                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7662                 }
7663                 
7664                 if(camel == 'opacity') {
7665                     this.setOpacity(value);
7666                 }else{
7667                     this.dom.style[camel] = value;
7668                 }
7669             }else{
7670                 for(var style in prop){
7671                     if(typeof prop[style] != "function"){
7672                        this.setStyle(style, prop[style]);
7673                     }
7674                 }
7675             }
7676             return this;
7677         },
7678
7679         /**
7680          * More flexible version of {@link #setStyle} for setting style properties.
7681          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7682          * a function which returns such a specification.
7683          * @return {Roo.Element} this
7684          */
7685         applyStyles : function(style){
7686             Roo.DomHelper.applyStyles(this.dom, style);
7687             return this;
7688         },
7689
7690         /**
7691           * 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).
7692           * @return {Number} The X position of the element
7693           */
7694         getX : function(){
7695             return D.getX(this.dom);
7696         },
7697
7698         /**
7699           * 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).
7700           * @return {Number} The Y position of the element
7701           */
7702         getY : function(){
7703             return D.getY(this.dom);
7704         },
7705
7706         /**
7707           * 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).
7708           * @return {Array} The XY position of the element
7709           */
7710         getXY : function(){
7711             return D.getXY(this.dom);
7712         },
7713
7714         /**
7715          * 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).
7716          * @param {Number} The X position of the element
7717          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7718          * @return {Roo.Element} this
7719          */
7720         setX : function(x, animate){
7721             if(!animate || !A){
7722                 D.setX(this.dom, x);
7723             }else{
7724                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7725             }
7726             return this;
7727         },
7728
7729         /**
7730          * 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).
7731          * @param {Number} The Y position of the element
7732          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7733          * @return {Roo.Element} this
7734          */
7735         setY : function(y, animate){
7736             if(!animate || !A){
7737                 D.setY(this.dom, y);
7738             }else{
7739                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7740             }
7741             return this;
7742         },
7743
7744         /**
7745          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7746          * @param {String} left The left CSS property value
7747          * @return {Roo.Element} this
7748          */
7749         setLeft : function(left){
7750             this.setStyle("left", this.addUnits(left));
7751             return this;
7752         },
7753
7754         /**
7755          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7756          * @param {String} top The top CSS property value
7757          * @return {Roo.Element} this
7758          */
7759         setTop : function(top){
7760             this.setStyle("top", this.addUnits(top));
7761             return this;
7762         },
7763
7764         /**
7765          * Sets the element's CSS right style.
7766          * @param {String} right The right CSS property value
7767          * @return {Roo.Element} this
7768          */
7769         setRight : function(right){
7770             this.setStyle("right", this.addUnits(right));
7771             return this;
7772         },
7773
7774         /**
7775          * Sets the element's CSS bottom style.
7776          * @param {String} bottom The bottom CSS property value
7777          * @return {Roo.Element} this
7778          */
7779         setBottom : function(bottom){
7780             this.setStyle("bottom", this.addUnits(bottom));
7781             return this;
7782         },
7783
7784         /**
7785          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7786          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7787          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7788          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7789          * @return {Roo.Element} this
7790          */
7791         setXY : function(pos, animate){
7792             if(!animate || !A){
7793                 D.setXY(this.dom, pos);
7794             }else{
7795                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7796             }
7797             return this;
7798         },
7799
7800         /**
7801          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7802          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7803          * @param {Number} x X value for new position (coordinates are page-based)
7804          * @param {Number} y Y value for new position (coordinates are page-based)
7805          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7806          * @return {Roo.Element} this
7807          */
7808         setLocation : function(x, y, animate){
7809             this.setXY([x, y], this.preanim(arguments, 2));
7810             return this;
7811         },
7812
7813         /**
7814          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7815          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7816          * @param {Number} x X value for new position (coordinates are page-based)
7817          * @param {Number} y Y value for new position (coordinates are page-based)
7818          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7819          * @return {Roo.Element} this
7820          */
7821         moveTo : function(x, y, animate){
7822             this.setXY([x, y], this.preanim(arguments, 2));
7823             return this;
7824         },
7825
7826         /**
7827          * Returns the region of the given element.
7828          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7829          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7830          */
7831         getRegion : function(){
7832             return D.getRegion(this.dom);
7833         },
7834
7835         /**
7836          * Returns the offset height of the element
7837          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7838          * @return {Number} The element's height
7839          */
7840         getHeight : function(contentHeight){
7841             var h = this.dom.offsetHeight || 0;
7842             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7843         },
7844
7845         /**
7846          * Returns the offset width of the element
7847          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7848          * @return {Number} The element's width
7849          */
7850         getWidth : function(contentWidth){
7851             var w = this.dom.offsetWidth || 0;
7852             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7853         },
7854
7855         /**
7856          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7857          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7858          * if a height has not been set using CSS.
7859          * @return {Number}
7860          */
7861         getComputedHeight : function(){
7862             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7863             if(!h){
7864                 h = parseInt(this.getStyle('height'), 10) || 0;
7865                 if(!this.isBorderBox()){
7866                     h += this.getFrameWidth('tb');
7867                 }
7868             }
7869             return h;
7870         },
7871
7872         /**
7873          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7874          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7875          * if a width has not been set using CSS.
7876          * @return {Number}
7877          */
7878         getComputedWidth : function(){
7879             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7880             if(!w){
7881                 w = parseInt(this.getStyle('width'), 10) || 0;
7882                 if(!this.isBorderBox()){
7883                     w += this.getFrameWidth('lr');
7884                 }
7885             }
7886             return w;
7887         },
7888
7889         /**
7890          * Returns the size of the element.
7891          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7892          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7893          */
7894         getSize : function(contentSize){
7895             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7896         },
7897
7898         /**
7899          * Returns the width and height of the viewport.
7900          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7901          */
7902         getViewSize : function(){
7903             var d = this.dom, doc = document, aw = 0, ah = 0;
7904             if(d == doc || d == doc.body){
7905                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7906             }else{
7907                 return {
7908                     width : d.clientWidth,
7909                     height: d.clientHeight
7910                 };
7911             }
7912         },
7913
7914         /**
7915          * Returns the value of the "value" attribute
7916          * @param {Boolean} asNumber true to parse the value as a number
7917          * @return {String/Number}
7918          */
7919         getValue : function(asNumber){
7920             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7921         },
7922
7923         // private
7924         adjustWidth : function(width){
7925             if(typeof width == "number"){
7926                 if(this.autoBoxAdjust && !this.isBorderBox()){
7927                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7928                 }
7929                 if(width < 0){
7930                     width = 0;
7931                 }
7932             }
7933             return width;
7934         },
7935
7936         // private
7937         adjustHeight : function(height){
7938             if(typeof height == "number"){
7939                if(this.autoBoxAdjust && !this.isBorderBox()){
7940                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7941                }
7942                if(height < 0){
7943                    height = 0;
7944                }
7945             }
7946             return height;
7947         },
7948
7949         /**
7950          * Set the width of the element
7951          * @param {Number} width The new width
7952          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7953          * @return {Roo.Element} this
7954          */
7955         setWidth : function(width, animate){
7956             width = this.adjustWidth(width);
7957             if(!animate || !A){
7958                 this.dom.style.width = this.addUnits(width);
7959             }else{
7960                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7961             }
7962             return this;
7963         },
7964
7965         /**
7966          * Set the height of the element
7967          * @param {Number} height The new height
7968          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7969          * @return {Roo.Element} this
7970          */
7971          setHeight : function(height, animate){
7972             height = this.adjustHeight(height);
7973             if(!animate || !A){
7974                 this.dom.style.height = this.addUnits(height);
7975             }else{
7976                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7977             }
7978             return this;
7979         },
7980
7981         /**
7982          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7983          * @param {Number} width The new width
7984          * @param {Number} height The new height
7985          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7986          * @return {Roo.Element} this
7987          */
7988          setSize : function(width, height, animate){
7989             if(typeof width == "object"){ // in case of object from getSize()
7990                 height = width.height; width = width.width;
7991             }
7992             width = this.adjustWidth(width); height = this.adjustHeight(height);
7993             if(!animate || !A){
7994                 this.dom.style.width = this.addUnits(width);
7995                 this.dom.style.height = this.addUnits(height);
7996             }else{
7997                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7998             }
7999             return this;
8000         },
8001
8002         /**
8003          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8004          * @param {Number} x X value for new position (coordinates are page-based)
8005          * @param {Number} y Y value for new position (coordinates are page-based)
8006          * @param {Number} width The new width
8007          * @param {Number} height The new height
8008          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8009          * @return {Roo.Element} this
8010          */
8011         setBounds : function(x, y, width, height, animate){
8012             if(!animate || !A){
8013                 this.setSize(width, height);
8014                 this.setLocation(x, y);
8015             }else{
8016                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8017                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8018                               this.preanim(arguments, 4), 'motion');
8019             }
8020             return this;
8021         },
8022
8023         /**
8024          * 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.
8025          * @param {Roo.lib.Region} region The region to fill
8026          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8027          * @return {Roo.Element} this
8028          */
8029         setRegion : function(region, animate){
8030             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8031             return this;
8032         },
8033
8034         /**
8035          * Appends an event handler
8036          *
8037          * @param {String}   eventName     The type of event to append
8038          * @param {Function} fn        The method the event invokes
8039          * @param {Object} scope       (optional) The scope (this object) of the fn
8040          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8041          */
8042         addListener : function(eventName, fn, scope, options){
8043             if (this.dom) {
8044                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8045             }
8046         },
8047
8048         /**
8049          * Removes an event handler from this element
8050          * @param {String} eventName the type of event to remove
8051          * @param {Function} fn the method the event invokes
8052          * @return {Roo.Element} this
8053          */
8054         removeListener : function(eventName, fn){
8055             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8056             return this;
8057         },
8058
8059         /**
8060          * Removes all previous added listeners from this element
8061          * @return {Roo.Element} this
8062          */
8063         removeAllListeners : function(){
8064             E.purgeElement(this.dom);
8065             return this;
8066         },
8067
8068         relayEvent : function(eventName, observable){
8069             this.on(eventName, function(e){
8070                 observable.fireEvent(eventName, e);
8071             });
8072         },
8073
8074         /**
8075          * Set the opacity of the element
8076          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8077          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8078          * @return {Roo.Element} this
8079          */
8080          setOpacity : function(opacity, animate){
8081             if(!animate || !A){
8082                 var s = this.dom.style;
8083                 if(Roo.isIE){
8084                     s.zoom = 1;
8085                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8086                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8087                 }else{
8088                     s.opacity = opacity;
8089                 }
8090             }else{
8091                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8092             }
8093             return this;
8094         },
8095
8096         /**
8097          * Gets the left X coordinate
8098          * @param {Boolean} local True to get the local css position instead of page coordinate
8099          * @return {Number}
8100          */
8101         getLeft : function(local){
8102             if(!local){
8103                 return this.getX();
8104             }else{
8105                 return parseInt(this.getStyle("left"), 10) || 0;
8106             }
8107         },
8108
8109         /**
8110          * Gets the right X coordinate of the element (element X position + element width)
8111          * @param {Boolean} local True to get the local css position instead of page coordinate
8112          * @return {Number}
8113          */
8114         getRight : function(local){
8115             if(!local){
8116                 return this.getX() + this.getWidth();
8117             }else{
8118                 return (this.getLeft(true) + this.getWidth()) || 0;
8119             }
8120         },
8121
8122         /**
8123          * Gets the top Y coordinate
8124          * @param {Boolean} local True to get the local css position instead of page coordinate
8125          * @return {Number}
8126          */
8127         getTop : function(local) {
8128             if(!local){
8129                 return this.getY();
8130             }else{
8131                 return parseInt(this.getStyle("top"), 10) || 0;
8132             }
8133         },
8134
8135         /**
8136          * Gets the bottom Y coordinate of the element (element Y position + element height)
8137          * @param {Boolean} local True to get the local css position instead of page coordinate
8138          * @return {Number}
8139          */
8140         getBottom : function(local){
8141             if(!local){
8142                 return this.getY() + this.getHeight();
8143             }else{
8144                 return (this.getTop(true) + this.getHeight()) || 0;
8145             }
8146         },
8147
8148         /**
8149         * Initializes positioning on this element. If a desired position is not passed, it will make the
8150         * the element positioned relative IF it is not already positioned.
8151         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8152         * @param {Number} zIndex (optional) The zIndex to apply
8153         * @param {Number} x (optional) Set the page X position
8154         * @param {Number} y (optional) Set the page Y position
8155         */
8156         position : function(pos, zIndex, x, y){
8157             if(!pos){
8158                if(this.getStyle('position') == 'static'){
8159                    this.setStyle('position', 'relative');
8160                }
8161             }else{
8162                 this.setStyle("position", pos);
8163             }
8164             if(zIndex){
8165                 this.setStyle("z-index", zIndex);
8166             }
8167             if(x !== undefined && y !== undefined){
8168                 this.setXY([x, y]);
8169             }else if(x !== undefined){
8170                 this.setX(x);
8171             }else if(y !== undefined){
8172                 this.setY(y);
8173             }
8174         },
8175
8176         /**
8177         * Clear positioning back to the default when the document was loaded
8178         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8179         * @return {Roo.Element} this
8180          */
8181         clearPositioning : function(value){
8182             value = value ||'';
8183             this.setStyle({
8184                 "left": value,
8185                 "right": value,
8186                 "top": value,
8187                 "bottom": value,
8188                 "z-index": "",
8189                 "position" : "static"
8190             });
8191             return this;
8192         },
8193
8194         /**
8195         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8196         * snapshot before performing an update and then restoring the element.
8197         * @return {Object}
8198         */
8199         getPositioning : function(){
8200             var l = this.getStyle("left");
8201             var t = this.getStyle("top");
8202             return {
8203                 "position" : this.getStyle("position"),
8204                 "left" : l,
8205                 "right" : l ? "" : this.getStyle("right"),
8206                 "top" : t,
8207                 "bottom" : t ? "" : this.getStyle("bottom"),
8208                 "z-index" : this.getStyle("z-index")
8209             };
8210         },
8211
8212         /**
8213          * Gets the width of the border(s) for the specified side(s)
8214          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8215          * passing lr would get the border (l)eft width + the border (r)ight width.
8216          * @return {Number} The width of the sides passed added together
8217          */
8218         getBorderWidth : function(side){
8219             return this.addStyles(side, El.borders);
8220         },
8221
8222         /**
8223          * Gets the width of the padding(s) for the specified side(s)
8224          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8225          * passing lr would get the padding (l)eft + the padding (r)ight.
8226          * @return {Number} The padding of the sides passed added together
8227          */
8228         getPadding : function(side){
8229             return this.addStyles(side, El.paddings);
8230         },
8231
8232         /**
8233         * Set positioning with an object returned by getPositioning().
8234         * @param {Object} posCfg
8235         * @return {Roo.Element} this
8236          */
8237         setPositioning : function(pc){
8238             this.applyStyles(pc);
8239             if(pc.right == "auto"){
8240                 this.dom.style.right = "";
8241             }
8242             if(pc.bottom == "auto"){
8243                 this.dom.style.bottom = "";
8244             }
8245             return this;
8246         },
8247
8248         // private
8249         fixDisplay : function(){
8250             if(this.getStyle("display") == "none"){
8251                 this.setStyle("visibility", "hidden");
8252                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8253                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8254                     this.setStyle("display", "block");
8255                 }
8256             }
8257         },
8258
8259         /**
8260          * Quick set left and top adding default units
8261          * @param {String} left The left CSS property value
8262          * @param {String} top The top CSS property value
8263          * @return {Roo.Element} this
8264          */
8265          setLeftTop : function(left, top){
8266             this.dom.style.left = this.addUnits(left);
8267             this.dom.style.top = this.addUnits(top);
8268             return this;
8269         },
8270
8271         /**
8272          * Move this element relative to its current position.
8273          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8274          * @param {Number} distance How far to move the element in pixels
8275          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8276          * @return {Roo.Element} this
8277          */
8278          move : function(direction, distance, animate){
8279             var xy = this.getXY();
8280             direction = direction.toLowerCase();
8281             switch(direction){
8282                 case "l":
8283                 case "left":
8284                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8285                     break;
8286                case "r":
8287                case "right":
8288                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8289                     break;
8290                case "t":
8291                case "top":
8292                case "up":
8293                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8294                     break;
8295                case "b":
8296                case "bottom":
8297                case "down":
8298                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8299                     break;
8300             }
8301             return this;
8302         },
8303
8304         /**
8305          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8306          * @return {Roo.Element} this
8307          */
8308         clip : function(){
8309             if(!this.isClipped){
8310                this.isClipped = true;
8311                this.originalClip = {
8312                    "o": this.getStyle("overflow"),
8313                    "x": this.getStyle("overflow-x"),
8314                    "y": this.getStyle("overflow-y")
8315                };
8316                this.setStyle("overflow", "hidden");
8317                this.setStyle("overflow-x", "hidden");
8318                this.setStyle("overflow-y", "hidden");
8319             }
8320             return this;
8321         },
8322
8323         /**
8324          *  Return clipping (overflow) to original clipping before clip() was called
8325          * @return {Roo.Element} this
8326          */
8327         unclip : function(){
8328             if(this.isClipped){
8329                 this.isClipped = false;
8330                 var o = this.originalClip;
8331                 if(o.o){this.setStyle("overflow", o.o);}
8332                 if(o.x){this.setStyle("overflow-x", o.x);}
8333                 if(o.y){this.setStyle("overflow-y", o.y);}
8334             }
8335             return this;
8336         },
8337
8338
8339         /**
8340          * Gets the x,y coordinates specified by the anchor position on the element.
8341          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8342          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8343          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8344          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8345          * @return {Array} [x, y] An array containing the element's x and y coordinates
8346          */
8347         getAnchorXY : function(anchor, local, s){
8348             //Passing a different size is useful for pre-calculating anchors,
8349             //especially for anchored animations that change the el size.
8350
8351             var w, h, vp = false;
8352             if(!s){
8353                 var d = this.dom;
8354                 if(d == document.body || d == document){
8355                     vp = true;
8356                     w = D.getViewWidth(); h = D.getViewHeight();
8357                 }else{
8358                     w = this.getWidth(); h = this.getHeight();
8359                 }
8360             }else{
8361                 w = s.width;  h = s.height;
8362             }
8363             var x = 0, y = 0, r = Math.round;
8364             switch((anchor || "tl").toLowerCase()){
8365                 case "c":
8366                     x = r(w*.5);
8367                     y = r(h*.5);
8368                 break;
8369                 case "t":
8370                     x = r(w*.5);
8371                     y = 0;
8372                 break;
8373                 case "l":
8374                     x = 0;
8375                     y = r(h*.5);
8376                 break;
8377                 case "r":
8378                     x = w;
8379                     y = r(h*.5);
8380                 break;
8381                 case "b":
8382                     x = r(w*.5);
8383                     y = h;
8384                 break;
8385                 case "tl":
8386                     x = 0;
8387                     y = 0;
8388                 break;
8389                 case "bl":
8390                     x = 0;
8391                     y = h;
8392                 break;
8393                 case "br":
8394                     x = w;
8395                     y = h;
8396                 break;
8397                 case "tr":
8398                     x = w;
8399                     y = 0;
8400                 break;
8401             }
8402             if(local === true){
8403                 return [x, y];
8404             }
8405             if(vp){
8406                 var sc = this.getScroll();
8407                 return [x + sc.left, y + sc.top];
8408             }
8409             //Add the element's offset xy
8410             var o = this.getXY();
8411             return [x+o[0], y+o[1]];
8412         },
8413
8414         /**
8415          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8416          * supported position values.
8417          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8418          * @param {String} position The position to align to.
8419          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8420          * @return {Array} [x, y]
8421          */
8422         getAlignToXY : function(el, p, o){
8423             el = Roo.get(el);
8424             var d = this.dom;
8425             if(!el.dom){
8426                 throw "Element.alignTo with an element that doesn't exist";
8427             }
8428             var c = false; //constrain to viewport
8429             var p1 = "", p2 = "";
8430             o = o || [0,0];
8431
8432             if(!p){
8433                 p = "tl-bl";
8434             }else if(p == "?"){
8435                 p = "tl-bl?";
8436             }else if(p.indexOf("-") == -1){
8437                 p = "tl-" + p;
8438             }
8439             p = p.toLowerCase();
8440             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8441             if(!m){
8442                throw "Element.alignTo with an invalid alignment " + p;
8443             }
8444             p1 = m[1]; p2 = m[2]; c = !!m[3];
8445
8446             //Subtract the aligned el's internal xy from the target's offset xy
8447             //plus custom offset to get the aligned el's new offset xy
8448             var a1 = this.getAnchorXY(p1, true);
8449             var a2 = el.getAnchorXY(p2, false);
8450             var x = a2[0] - a1[0] + o[0];
8451             var y = a2[1] - a1[1] + o[1];
8452             if(c){
8453                 //constrain the aligned el to viewport if necessary
8454                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8455                 // 5px of margin for ie
8456                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8457
8458                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8459                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8460                 //otherwise swap the aligned el to the opposite border of the target.
8461                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8462                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8463                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8464                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8465
8466                var doc = document;
8467                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8468                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8469
8470                if((x+w) > dw + scrollX){
8471                     x = swapX ? r.left-w : dw+scrollX-w;
8472                 }
8473                if(x < scrollX){
8474                    x = swapX ? r.right : scrollX;
8475                }
8476                if((y+h) > dh + scrollY){
8477                     y = swapY ? r.top-h : dh+scrollY-h;
8478                 }
8479                if (y < scrollY){
8480                    y = swapY ? r.bottom : scrollY;
8481                }
8482             }
8483             return [x,y];
8484         },
8485
8486         // private
8487         getConstrainToXY : function(){
8488             var os = {top:0, left:0, bottom:0, right: 0};
8489
8490             return function(el, local, offsets, proposedXY){
8491                 el = Roo.get(el);
8492                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8493
8494                 var vw, vh, vx = 0, vy = 0;
8495                 if(el.dom == document.body || el.dom == document){
8496                     vw = Roo.lib.Dom.getViewWidth();
8497                     vh = Roo.lib.Dom.getViewHeight();
8498                 }else{
8499                     vw = el.dom.clientWidth;
8500                     vh = el.dom.clientHeight;
8501                     if(!local){
8502                         var vxy = el.getXY();
8503                         vx = vxy[0];
8504                         vy = vxy[1];
8505                     }
8506                 }
8507
8508                 var s = el.getScroll();
8509
8510                 vx += offsets.left + s.left;
8511                 vy += offsets.top + s.top;
8512
8513                 vw -= offsets.right;
8514                 vh -= offsets.bottom;
8515
8516                 var vr = vx+vw;
8517                 var vb = vy+vh;
8518
8519                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8520                 var x = xy[0], y = xy[1];
8521                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8522
8523                 // only move it if it needs it
8524                 var moved = false;
8525
8526                 // first validate right/bottom
8527                 if((x + w) > vr){
8528                     x = vr - w;
8529                     moved = true;
8530                 }
8531                 if((y + h) > vb){
8532                     y = vb - h;
8533                     moved = true;
8534                 }
8535                 // then make sure top/left isn't negative
8536                 if(x < vx){
8537                     x = vx;
8538                     moved = true;
8539                 }
8540                 if(y < vy){
8541                     y = vy;
8542                     moved = true;
8543                 }
8544                 return moved ? [x, y] : false;
8545             };
8546         }(),
8547
8548         // private
8549         adjustForConstraints : function(xy, parent, offsets){
8550             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8551         },
8552
8553         /**
8554          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8555          * document it aligns it to the viewport.
8556          * The position parameter is optional, and can be specified in any one of the following formats:
8557          * <ul>
8558          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8559          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8560          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8561          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8562          *   <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
8563          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8564          * </ul>
8565          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8566          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8567          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8568          * that specified in order to enforce the viewport constraints.
8569          * Following are all of the supported anchor positions:
8570     <pre>
8571     Value  Description
8572     -----  -----------------------------
8573     tl     The top left corner (default)
8574     t      The center of the top edge
8575     tr     The top right corner
8576     l      The center of the left edge
8577     c      In the center of the element
8578     r      The center of the right edge
8579     bl     The bottom left corner
8580     b      The center of the bottom edge
8581     br     The bottom right corner
8582     </pre>
8583     Example Usage:
8584     <pre><code>
8585     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8586     el.alignTo("other-el");
8587
8588     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8589     el.alignTo("other-el", "tr?");
8590
8591     // align the bottom right corner of el with the center left edge of other-el
8592     el.alignTo("other-el", "br-l?");
8593
8594     // align the center of el with the bottom left corner of other-el and
8595     // adjust the x position by -6 pixels (and the y position by 0)
8596     el.alignTo("other-el", "c-bl", [-6, 0]);
8597     </code></pre>
8598          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8599          * @param {String} position The position to align to.
8600          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8601          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8602          * @return {Roo.Element} this
8603          */
8604         alignTo : function(element, position, offsets, animate){
8605             var xy = this.getAlignToXY(element, position, offsets);
8606             this.setXY(xy, this.preanim(arguments, 3));
8607             return this;
8608         },
8609
8610         /**
8611          * Anchors an element to another element and realigns it when the window is resized.
8612          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8613          * @param {String} position The position to align to.
8614          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8615          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8616          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8617          * is a number, it is used as the buffer delay (defaults to 50ms).
8618          * @param {Function} callback The function to call after the animation finishes
8619          * @return {Roo.Element} this
8620          */
8621         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8622             var action = function(){
8623                 this.alignTo(el, alignment, offsets, animate);
8624                 Roo.callback(callback, this);
8625             };
8626             Roo.EventManager.onWindowResize(action, this);
8627             var tm = typeof monitorScroll;
8628             if(tm != 'undefined'){
8629                 Roo.EventManager.on(window, 'scroll', action, this,
8630                     {buffer: tm == 'number' ? monitorScroll : 50});
8631             }
8632             action.call(this); // align immediately
8633             return this;
8634         },
8635         /**
8636          * Clears any opacity settings from this element. Required in some cases for IE.
8637          * @return {Roo.Element} this
8638          */
8639         clearOpacity : function(){
8640             if (window.ActiveXObject) {
8641                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8642                     this.dom.style.filter = "";
8643                 }
8644             } else {
8645                 this.dom.style.opacity = "";
8646                 this.dom.style["-moz-opacity"] = "";
8647                 this.dom.style["-khtml-opacity"] = "";
8648             }
8649             return this;
8650         },
8651
8652         /**
8653          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8654          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8655          * @return {Roo.Element} this
8656          */
8657         hide : function(animate){
8658             this.setVisible(false, this.preanim(arguments, 0));
8659             return this;
8660         },
8661
8662         /**
8663         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8664         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8665          * @return {Roo.Element} this
8666          */
8667         show : function(animate){
8668             this.setVisible(true, this.preanim(arguments, 0));
8669             return this;
8670         },
8671
8672         /**
8673          * @private Test if size has a unit, otherwise appends the default
8674          */
8675         addUnits : function(size){
8676             return Roo.Element.addUnits(size, this.defaultUnit);
8677         },
8678
8679         /**
8680          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8681          * @return {Roo.Element} this
8682          */
8683         beginMeasure : function(){
8684             var el = this.dom;
8685             if(el.offsetWidth || el.offsetHeight){
8686                 return this; // offsets work already
8687             }
8688             var changed = [];
8689             var p = this.dom, b = document.body; // start with this element
8690             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8691                 var pe = Roo.get(p);
8692                 if(pe.getStyle('display') == 'none'){
8693                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8694                     p.style.visibility = "hidden";
8695                     p.style.display = "block";
8696                 }
8697                 p = p.parentNode;
8698             }
8699             this._measureChanged = changed;
8700             return this;
8701
8702         },
8703
8704         /**
8705          * Restores displays to before beginMeasure was called
8706          * @return {Roo.Element} this
8707          */
8708         endMeasure : function(){
8709             var changed = this._measureChanged;
8710             if(changed){
8711                 for(var i = 0, len = changed.length; i < len; i++) {
8712                     var r = changed[i];
8713                     r.el.style.visibility = r.visibility;
8714                     r.el.style.display = "none";
8715                 }
8716                 this._measureChanged = null;
8717             }
8718             return this;
8719         },
8720
8721         /**
8722         * Update the innerHTML of this element, optionally searching for and processing scripts
8723         * @param {String} html The new HTML
8724         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8725         * @param {Function} callback For async script loading you can be noticed when the update completes
8726         * @return {Roo.Element} this
8727          */
8728         update : function(html, loadScripts, callback){
8729             if(typeof html == "undefined"){
8730                 html = "";
8731             }
8732             if(loadScripts !== true){
8733                 this.dom.innerHTML = html;
8734                 if(typeof callback == "function"){
8735                     callback();
8736                 }
8737                 return this;
8738             }
8739             var id = Roo.id();
8740             var dom = this.dom;
8741
8742             html += '<span id="' + id + '"></span>';
8743
8744             E.onAvailable(id, function(){
8745                 var hd = document.getElementsByTagName("head")[0];
8746                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8747                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8748                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8749
8750                 var match;
8751                 while(match = re.exec(html)){
8752                     var attrs = match[1];
8753                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8754                     if(srcMatch && srcMatch[2]){
8755                        var s = document.createElement("script");
8756                        s.src = srcMatch[2];
8757                        var typeMatch = attrs.match(typeRe);
8758                        if(typeMatch && typeMatch[2]){
8759                            s.type = typeMatch[2];
8760                        }
8761                        hd.appendChild(s);
8762                     }else if(match[2] && match[2].length > 0){
8763                         if(window.execScript) {
8764                            window.execScript(match[2]);
8765                         } else {
8766                             /**
8767                              * eval:var:id
8768                              * eval:var:dom
8769                              * eval:var:html
8770                              * 
8771                              */
8772                            window.eval(match[2]);
8773                         }
8774                     }
8775                 }
8776                 var el = document.getElementById(id);
8777                 if(el){el.parentNode.removeChild(el);}
8778                 if(typeof callback == "function"){
8779                     callback();
8780                 }
8781             });
8782             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8783             return this;
8784         },
8785
8786         /**
8787          * Direct access to the UpdateManager update() method (takes the same parameters).
8788          * @param {String/Function} url The url for this request or a function to call to get the url
8789          * @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}
8790          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8791          * @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.
8792          * @return {Roo.Element} this
8793          */
8794         load : function(){
8795             var um = this.getUpdateManager();
8796             um.update.apply(um, arguments);
8797             return this;
8798         },
8799
8800         /**
8801         * Gets this element's UpdateManager
8802         * @return {Roo.UpdateManager} The UpdateManager
8803         */
8804         getUpdateManager : function(){
8805             if(!this.updateManager){
8806                 this.updateManager = new Roo.UpdateManager(this);
8807             }
8808             return this.updateManager;
8809         },
8810
8811         /**
8812          * Disables text selection for this element (normalized across browsers)
8813          * @return {Roo.Element} this
8814          */
8815         unselectable : function(){
8816             this.dom.unselectable = "on";
8817             this.swallowEvent("selectstart", true);
8818             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8819             this.addClass("x-unselectable");
8820             return this;
8821         },
8822
8823         /**
8824         * Calculates the x, y to center this element on the screen
8825         * @return {Array} The x, y values [x, y]
8826         */
8827         getCenterXY : function(){
8828             return this.getAlignToXY(document, 'c-c');
8829         },
8830
8831         /**
8832         * Centers the Element in either the viewport, or another Element.
8833         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8834         */
8835         center : function(centerIn){
8836             this.alignTo(centerIn || document, 'c-c');
8837             return this;
8838         },
8839
8840         /**
8841          * Tests various css rules/browsers to determine if this element uses a border box
8842          * @return {Boolean}
8843          */
8844         isBorderBox : function(){
8845             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8846         },
8847
8848         /**
8849          * Return a box {x, y, width, height} that can be used to set another elements
8850          * size/location to match this element.
8851          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8852          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8853          * @return {Object} box An object in the format {x, y, width, height}
8854          */
8855         getBox : function(contentBox, local){
8856             var xy;
8857             if(!local){
8858                 xy = this.getXY();
8859             }else{
8860                 var left = parseInt(this.getStyle("left"), 10) || 0;
8861                 var top = parseInt(this.getStyle("top"), 10) || 0;
8862                 xy = [left, top];
8863             }
8864             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8865             if(!contentBox){
8866                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8867             }else{
8868                 var l = this.getBorderWidth("l")+this.getPadding("l");
8869                 var r = this.getBorderWidth("r")+this.getPadding("r");
8870                 var t = this.getBorderWidth("t")+this.getPadding("t");
8871                 var b = this.getBorderWidth("b")+this.getPadding("b");
8872                 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)};
8873             }
8874             bx.right = bx.x + bx.width;
8875             bx.bottom = bx.y + bx.height;
8876             return bx;
8877         },
8878
8879         /**
8880          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8881          for more information about the sides.
8882          * @param {String} sides
8883          * @return {Number}
8884          */
8885         getFrameWidth : function(sides, onlyContentBox){
8886             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8887         },
8888
8889         /**
8890          * 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.
8891          * @param {Object} box The box to fill {x, y, width, height}
8892          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8893          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8894          * @return {Roo.Element} this
8895          */
8896         setBox : function(box, adjust, animate){
8897             var w = box.width, h = box.height;
8898             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8899                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8900                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8901             }
8902             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8903             return this;
8904         },
8905
8906         /**
8907          * Forces the browser to repaint this element
8908          * @return {Roo.Element} this
8909          */
8910          repaint : function(){
8911             var dom = this.dom;
8912             this.addClass("x-repaint");
8913             setTimeout(function(){
8914                 Roo.get(dom).removeClass("x-repaint");
8915             }, 1);
8916             return this;
8917         },
8918
8919         /**
8920          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8921          * then it returns the calculated width of the sides (see getPadding)
8922          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8923          * @return {Object/Number}
8924          */
8925         getMargins : function(side){
8926             if(!side){
8927                 return {
8928                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8929                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8930                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8931                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8932                 };
8933             }else{
8934                 return this.addStyles(side, El.margins);
8935              }
8936         },
8937
8938         // private
8939         addStyles : function(sides, styles){
8940             var val = 0, v, w;
8941             for(var i = 0, len = sides.length; i < len; i++){
8942                 v = this.getStyle(styles[sides.charAt(i)]);
8943                 if(v){
8944                      w = parseInt(v, 10);
8945                      if(w){ val += w; }
8946                 }
8947             }
8948             return val;
8949         },
8950
8951         /**
8952          * Creates a proxy element of this element
8953          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8954          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8955          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8956          * @return {Roo.Element} The new proxy element
8957          */
8958         createProxy : function(config, renderTo, matchBox){
8959             if(renderTo){
8960                 renderTo = Roo.getDom(renderTo);
8961             }else{
8962                 renderTo = document.body;
8963             }
8964             config = typeof config == "object" ?
8965                 config : {tag : "div", cls: config};
8966             var proxy = Roo.DomHelper.append(renderTo, config, true);
8967             if(matchBox){
8968                proxy.setBox(this.getBox());
8969             }
8970             return proxy;
8971         },
8972
8973         /**
8974          * Puts a mask over this element to disable user interaction. Requires core.css.
8975          * This method can only be applied to elements which accept child nodes.
8976          * @param {String} msg (optional) A message to display in the mask
8977          * @param {String} msgCls (optional) A css class to apply to the msg element
8978          * @return {Element} The mask  element
8979          */
8980         mask : function(msg, msgCls)
8981         {
8982             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8983                 this.setStyle("position", "relative");
8984             }
8985             if(!this._mask){
8986                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8987             }
8988             this.addClass("x-masked");
8989             this._mask.setDisplayed(true);
8990             
8991             // we wander
8992             var z = 0;
8993             var dom = this.dom
8994             while (dom && dom.style) {
8995                 if (!isNaN(parseInt(dom.style.zIndex))) {
8996                     z = Math.max(z, parseInt(dom.style.zIndex));
8997                 }
8998                 dom = dom.parentNode;
8999             }
9000             // if we are masking the body - then it hides everything..
9001             if (this.dom == document.body) {
9002                 z = 1000000;
9003                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9004                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9005             }
9006            
9007             if(typeof msg == 'string'){
9008                 if(!this._maskMsg){
9009                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9010                 }
9011                 var mm = this._maskMsg;
9012                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9013                 if (mm.dom.firstChild) { // weird IE issue?
9014                     mm.dom.firstChild.innerHTML = msg;
9015                 }
9016                 mm.setDisplayed(true);
9017                 mm.center(this);
9018                 mm.setStyle('z-index', z + 102);
9019             }
9020             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9021                 this._mask.setHeight(this.getHeight());
9022             }
9023             this._mask.setStyle('z-index', z + 100);
9024             
9025             return this._mask;
9026         },
9027
9028         /**
9029          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9030          * it is cached for reuse.
9031          */
9032         unmask : function(removeEl){
9033             if(this._mask){
9034                 if(removeEl === true){
9035                     this._mask.remove();
9036                     delete this._mask;
9037                     if(this._maskMsg){
9038                         this._maskMsg.remove();
9039                         delete this._maskMsg;
9040                     }
9041                 }else{
9042                     this._mask.setDisplayed(false);
9043                     if(this._maskMsg){
9044                         this._maskMsg.setDisplayed(false);
9045                     }
9046                 }
9047             }
9048             this.removeClass("x-masked");
9049         },
9050
9051         /**
9052          * Returns true if this element is masked
9053          * @return {Boolean}
9054          */
9055         isMasked : function(){
9056             return this._mask && this._mask.isVisible();
9057         },
9058
9059         /**
9060          * Creates an iframe shim for this element to keep selects and other windowed objects from
9061          * showing through.
9062          * @return {Roo.Element} The new shim element
9063          */
9064         createShim : function(){
9065             var el = document.createElement('iframe');
9066             el.frameBorder = 'no';
9067             el.className = 'roo-shim';
9068             if(Roo.isIE && Roo.isSecure){
9069                 el.src = Roo.SSL_SECURE_URL;
9070             }
9071             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9072             shim.autoBoxAdjust = false;
9073             return shim;
9074         },
9075
9076         /**
9077          * Removes this element from the DOM and deletes it from the cache
9078          */
9079         remove : function(){
9080             if(this.dom.parentNode){
9081                 this.dom.parentNode.removeChild(this.dom);
9082             }
9083             delete El.cache[this.dom.id];
9084         },
9085
9086         /**
9087          * Sets up event handlers to add and remove a css class when the mouse is over this element
9088          * @param {String} className
9089          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9090          * mouseout events for children elements
9091          * @return {Roo.Element} this
9092          */
9093         addClassOnOver : function(className, preventFlicker){
9094             this.on("mouseover", function(){
9095                 Roo.fly(this, '_internal').addClass(className);
9096             }, this.dom);
9097             var removeFn = function(e){
9098                 if(preventFlicker !== true || !e.within(this, true)){
9099                     Roo.fly(this, '_internal').removeClass(className);
9100                 }
9101             };
9102             this.on("mouseout", removeFn, this.dom);
9103             return this;
9104         },
9105
9106         /**
9107          * Sets up event handlers to add and remove a css class when this element has the focus
9108          * @param {String} className
9109          * @return {Roo.Element} this
9110          */
9111         addClassOnFocus : function(className){
9112             this.on("focus", function(){
9113                 Roo.fly(this, '_internal').addClass(className);
9114             }, this.dom);
9115             this.on("blur", function(){
9116                 Roo.fly(this, '_internal').removeClass(className);
9117             }, this.dom);
9118             return this;
9119         },
9120         /**
9121          * 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)
9122          * @param {String} className
9123          * @return {Roo.Element} this
9124          */
9125         addClassOnClick : function(className){
9126             var dom = this.dom;
9127             this.on("mousedown", function(){
9128                 Roo.fly(dom, '_internal').addClass(className);
9129                 var d = Roo.get(document);
9130                 var fn = function(){
9131                     Roo.fly(dom, '_internal').removeClass(className);
9132                     d.removeListener("mouseup", fn);
9133                 };
9134                 d.on("mouseup", fn);
9135             });
9136             return this;
9137         },
9138
9139         /**
9140          * Stops the specified event from bubbling and optionally prevents the default action
9141          * @param {String} eventName
9142          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9143          * @return {Roo.Element} this
9144          */
9145         swallowEvent : function(eventName, preventDefault){
9146             var fn = function(e){
9147                 e.stopPropagation();
9148                 if(preventDefault){
9149                     e.preventDefault();
9150                 }
9151             };
9152             if(eventName instanceof Array){
9153                 for(var i = 0, len = eventName.length; i < len; i++){
9154                      this.on(eventName[i], fn);
9155                 }
9156                 return this;
9157             }
9158             this.on(eventName, fn);
9159             return this;
9160         },
9161
9162         /**
9163          * @private
9164          */
9165       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9166
9167         /**
9168          * Sizes this element to its parent element's dimensions performing
9169          * neccessary box adjustments.
9170          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9171          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9172          * @return {Roo.Element} this
9173          */
9174         fitToParent : function(monitorResize, targetParent) {
9175           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9176           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9177           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9178             return;
9179           }
9180           var p = Roo.get(targetParent || this.dom.parentNode);
9181           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9182           if (monitorResize === true) {
9183             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9184             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9185           }
9186           return this;
9187         },
9188
9189         /**
9190          * Gets the next sibling, skipping text nodes
9191          * @return {HTMLElement} The next sibling or null
9192          */
9193         getNextSibling : function(){
9194             var n = this.dom.nextSibling;
9195             while(n && n.nodeType != 1){
9196                 n = n.nextSibling;
9197             }
9198             return n;
9199         },
9200
9201         /**
9202          * Gets the previous sibling, skipping text nodes
9203          * @return {HTMLElement} The previous sibling or null
9204          */
9205         getPrevSibling : function(){
9206             var n = this.dom.previousSibling;
9207             while(n && n.nodeType != 1){
9208                 n = n.previousSibling;
9209             }
9210             return n;
9211         },
9212
9213
9214         /**
9215          * Appends the passed element(s) to this element
9216          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9217          * @return {Roo.Element} this
9218          */
9219         appendChild: function(el){
9220             el = Roo.get(el);
9221             el.appendTo(this);
9222             return this;
9223         },
9224
9225         /**
9226          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9227          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9228          * automatically generated with the specified attributes.
9229          * @param {HTMLElement} insertBefore (optional) a child element of this element
9230          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9231          * @return {Roo.Element} The new child element
9232          */
9233         createChild: function(config, insertBefore, returnDom){
9234             config = config || {tag:'div'};
9235             if(insertBefore){
9236                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9237             }
9238             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9239         },
9240
9241         /**
9242          * Appends this element to the passed element
9243          * @param {String/HTMLElement/Element} el The new parent element
9244          * @return {Roo.Element} this
9245          */
9246         appendTo: function(el){
9247             el = Roo.getDom(el);
9248             el.appendChild(this.dom);
9249             return this;
9250         },
9251
9252         /**
9253          * Inserts this element before the passed element in the DOM
9254          * @param {String/HTMLElement/Element} el The element to insert before
9255          * @return {Roo.Element} this
9256          */
9257         insertBefore: function(el){
9258             el = Roo.getDom(el);
9259             el.parentNode.insertBefore(this.dom, el);
9260             return this;
9261         },
9262
9263         /**
9264          * Inserts this element after the passed element in the DOM
9265          * @param {String/HTMLElement/Element} el The element to insert after
9266          * @return {Roo.Element} this
9267          */
9268         insertAfter: function(el){
9269             el = Roo.getDom(el);
9270             el.parentNode.insertBefore(this.dom, el.nextSibling);
9271             return this;
9272         },
9273
9274         /**
9275          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9276          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9277          * @return {Roo.Element} The new child
9278          */
9279         insertFirst: function(el, returnDom){
9280             el = el || {};
9281             if(typeof el == 'object' && !el.nodeType){ // dh config
9282                 return this.createChild(el, this.dom.firstChild, returnDom);
9283             }else{
9284                 el = Roo.getDom(el);
9285                 this.dom.insertBefore(el, this.dom.firstChild);
9286                 return !returnDom ? Roo.get(el) : el;
9287             }
9288         },
9289
9290         /**
9291          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9292          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9293          * @param {String} where (optional) 'before' or 'after' defaults to before
9294          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9295          * @return {Roo.Element} the inserted Element
9296          */
9297         insertSibling: function(el, where, returnDom){
9298             where = where ? where.toLowerCase() : 'before';
9299             el = el || {};
9300             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9301
9302             if(typeof el == 'object' && !el.nodeType){ // dh config
9303                 if(where == 'after' && !this.dom.nextSibling){
9304                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9305                 }else{
9306                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9307                 }
9308
9309             }else{
9310                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9311                             where == 'before' ? this.dom : this.dom.nextSibling);
9312                 if(!returnDom){
9313                     rt = Roo.get(rt);
9314                 }
9315             }
9316             return rt;
9317         },
9318
9319         /**
9320          * Creates and wraps this element with another element
9321          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9322          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9323          * @return {HTMLElement/Element} The newly created wrapper element
9324          */
9325         wrap: function(config, returnDom){
9326             if(!config){
9327                 config = {tag: "div"};
9328             }
9329             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9330             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9331             return newEl;
9332         },
9333
9334         /**
9335          * Replaces the passed element with this element
9336          * @param {String/HTMLElement/Element} el The element to replace
9337          * @return {Roo.Element} this
9338          */
9339         replace: function(el){
9340             el = Roo.get(el);
9341             this.insertBefore(el);
9342             el.remove();
9343             return this;
9344         },
9345
9346         /**
9347          * Inserts an html fragment into this element
9348          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9349          * @param {String} html The HTML fragment
9350          * @param {Boolean} returnEl True to return an Roo.Element
9351          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9352          */
9353         insertHtml : function(where, html, returnEl){
9354             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9355             return returnEl ? Roo.get(el) : el;
9356         },
9357
9358         /**
9359          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9360          * @param {Object} o The object with the attributes
9361          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9362          * @return {Roo.Element} this
9363          */
9364         set : function(o, useSet){
9365             var el = this.dom;
9366             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9367             for(var attr in o){
9368                 if(attr == "style" || typeof o[attr] == "function") continue;
9369                 if(attr=="cls"){
9370                     el.className = o["cls"];
9371                 }else{
9372                     if(useSet) el.setAttribute(attr, o[attr]);
9373                     else el[attr] = o[attr];
9374                 }
9375             }
9376             if(o.style){
9377                 Roo.DomHelper.applyStyles(el, o.style);
9378             }
9379             return this;
9380         },
9381
9382         /**
9383          * Convenience method for constructing a KeyMap
9384          * @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:
9385          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9386          * @param {Function} fn The function to call
9387          * @param {Object} scope (optional) The scope of the function
9388          * @return {Roo.KeyMap} The KeyMap created
9389          */
9390         addKeyListener : function(key, fn, scope){
9391             var config;
9392             if(typeof key != "object" || key instanceof Array){
9393                 config = {
9394                     key: key,
9395                     fn: fn,
9396                     scope: scope
9397                 };
9398             }else{
9399                 config = {
9400                     key : key.key,
9401                     shift : key.shift,
9402                     ctrl : key.ctrl,
9403                     alt : key.alt,
9404                     fn: fn,
9405                     scope: scope
9406                 };
9407             }
9408             return new Roo.KeyMap(this, config);
9409         },
9410
9411         /**
9412          * Creates a KeyMap for this element
9413          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9414          * @return {Roo.KeyMap} The KeyMap created
9415          */
9416         addKeyMap : function(config){
9417             return new Roo.KeyMap(this, config);
9418         },
9419
9420         /**
9421          * Returns true if this element is scrollable.
9422          * @return {Boolean}
9423          */
9424          isScrollable : function(){
9425             var dom = this.dom;
9426             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9427         },
9428
9429         /**
9430          * 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().
9431          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9432          * @param {Number} value The new scroll value
9433          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9434          * @return {Element} this
9435          */
9436
9437         scrollTo : function(side, value, animate){
9438             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9439             if(!animate || !A){
9440                 this.dom[prop] = value;
9441             }else{
9442                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9443                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9444             }
9445             return this;
9446         },
9447
9448         /**
9449          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9450          * within this element's scrollable range.
9451          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9452          * @param {Number} distance How far to scroll the element in pixels
9453          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9454          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9455          * was scrolled as far as it could go.
9456          */
9457          scroll : function(direction, distance, animate){
9458              if(!this.isScrollable()){
9459                  return;
9460              }
9461              var el = this.dom;
9462              var l = el.scrollLeft, t = el.scrollTop;
9463              var w = el.scrollWidth, h = el.scrollHeight;
9464              var cw = el.clientWidth, ch = el.clientHeight;
9465              direction = direction.toLowerCase();
9466              var scrolled = false;
9467              var a = this.preanim(arguments, 2);
9468              switch(direction){
9469                  case "l":
9470                  case "left":
9471                      if(w - l > cw){
9472                          var v = Math.min(l + distance, w-cw);
9473                          this.scrollTo("left", v, a);
9474                          scrolled = true;
9475                      }
9476                      break;
9477                 case "r":
9478                 case "right":
9479                      if(l > 0){
9480                          var v = Math.max(l - distance, 0);
9481                          this.scrollTo("left", v, a);
9482                          scrolled = true;
9483                      }
9484                      break;
9485                 case "t":
9486                 case "top":
9487                 case "up":
9488                      if(t > 0){
9489                          var v = Math.max(t - distance, 0);
9490                          this.scrollTo("top", v, a);
9491                          scrolled = true;
9492                      }
9493                      break;
9494                 case "b":
9495                 case "bottom":
9496                 case "down":
9497                      if(h - t > ch){
9498                          var v = Math.min(t + distance, h-ch);
9499                          this.scrollTo("top", v, a);
9500                          scrolled = true;
9501                      }
9502                      break;
9503              }
9504              return scrolled;
9505         },
9506
9507         /**
9508          * Translates the passed page coordinates into left/top css values for this element
9509          * @param {Number/Array} x The page x or an array containing [x, y]
9510          * @param {Number} y The page y
9511          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9512          */
9513         translatePoints : function(x, y){
9514             if(typeof x == 'object' || x instanceof Array){
9515                 y = x[1]; x = x[0];
9516             }
9517             var p = this.getStyle('position');
9518             var o = this.getXY();
9519
9520             var l = parseInt(this.getStyle('left'), 10);
9521             var t = parseInt(this.getStyle('top'), 10);
9522
9523             if(isNaN(l)){
9524                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9525             }
9526             if(isNaN(t)){
9527                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9528             }
9529
9530             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9531         },
9532
9533         /**
9534          * Returns the current scroll position of the element.
9535          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9536          */
9537         getScroll : function(){
9538             var d = this.dom, doc = document;
9539             if(d == doc || d == doc.body){
9540                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9541                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9542                 return {left: l, top: t};
9543             }else{
9544                 return {left: d.scrollLeft, top: d.scrollTop};
9545             }
9546         },
9547
9548         /**
9549          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9550          * are convert to standard 6 digit hex color.
9551          * @param {String} attr The css attribute
9552          * @param {String} defaultValue The default value to use when a valid color isn't found
9553          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9554          * YUI color anims.
9555          */
9556         getColor : function(attr, defaultValue, prefix){
9557             var v = this.getStyle(attr);
9558             if(!v || v == "transparent" || v == "inherit") {
9559                 return defaultValue;
9560             }
9561             var color = typeof prefix == "undefined" ? "#" : prefix;
9562             if(v.substr(0, 4) == "rgb("){
9563                 var rvs = v.slice(4, v.length -1).split(",");
9564                 for(var i = 0; i < 3; i++){
9565                     var h = parseInt(rvs[i]).toString(16);
9566                     if(h < 16){
9567                         h = "0" + h;
9568                     }
9569                     color += h;
9570                 }
9571             } else {
9572                 if(v.substr(0, 1) == "#"){
9573                     if(v.length == 4) {
9574                         for(var i = 1; i < 4; i++){
9575                             var c = v.charAt(i);
9576                             color +=  c + c;
9577                         }
9578                     }else if(v.length == 7){
9579                         color += v.substr(1);
9580                     }
9581                 }
9582             }
9583             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9584         },
9585
9586         /**
9587          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9588          * gradient background, rounded corners and a 4-way shadow.
9589          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9590          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9591          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9592          * @return {Roo.Element} this
9593          */
9594         boxWrap : function(cls){
9595             cls = cls || 'x-box';
9596             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9597             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9598             return el;
9599         },
9600
9601         /**
9602          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9603          * @param {String} namespace The namespace in which to look for the attribute
9604          * @param {String} name The attribute name
9605          * @return {String} The attribute value
9606          */
9607         getAttributeNS : Roo.isIE ? function(ns, name){
9608             var d = this.dom;
9609             var type = typeof d[ns+":"+name];
9610             if(type != 'undefined' && type != 'unknown'){
9611                 return d[ns+":"+name];
9612             }
9613             return d[name];
9614         } : function(ns, name){
9615             var d = this.dom;
9616             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9617         },
9618         
9619         
9620         /**
9621          * Sets or Returns the value the dom attribute value
9622          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9623          * @param {String} value (optional) The value to set the attribute to
9624          * @return {String} The attribute value
9625          */
9626         attr : function(name){
9627             if (arguments.length > 1) {
9628                 this.dom.setAttribute(name, arguments[1]);
9629                 return arguments[1];
9630             }
9631             if (typeof(name) == 'object') {
9632                 for(var i in name) {
9633                     this.attr(i, name[i]);
9634                 }
9635                 return name;
9636             }
9637             
9638             
9639             if (!this.dom.hasAttribute(name)) {
9640                 return undefined;
9641             }
9642             return this.dom.getAttribute(name);
9643         }
9644         
9645         
9646         
9647     };
9648
9649     var ep = El.prototype;
9650
9651     /**
9652      * Appends an event handler (Shorthand for addListener)
9653      * @param {String}   eventName     The type of event to append
9654      * @param {Function} fn        The method the event invokes
9655      * @param {Object} scope       (optional) The scope (this object) of the fn
9656      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9657      * @method
9658      */
9659     ep.on = ep.addListener;
9660         // backwards compat
9661     ep.mon = ep.addListener;
9662
9663     /**
9664      * Removes an event handler from this element (shorthand for removeListener)
9665      * @param {String} eventName the type of event to remove
9666      * @param {Function} fn the method the event invokes
9667      * @return {Roo.Element} this
9668      * @method
9669      */
9670     ep.un = ep.removeListener;
9671
9672     /**
9673      * true to automatically adjust width and height settings for box-model issues (default to true)
9674      */
9675     ep.autoBoxAdjust = true;
9676
9677     // private
9678     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9679
9680     // private
9681     El.addUnits = function(v, defaultUnit){
9682         if(v === "" || v == "auto"){
9683             return v;
9684         }
9685         if(v === undefined){
9686             return '';
9687         }
9688         if(typeof v == "number" || !El.unitPattern.test(v)){
9689             return v + (defaultUnit || 'px');
9690         }
9691         return v;
9692     };
9693
9694     // special markup used throughout Roo when box wrapping elements
9695     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>';
9696     /**
9697      * Visibility mode constant - Use visibility to hide element
9698      * @static
9699      * @type Number
9700      */
9701     El.VISIBILITY = 1;
9702     /**
9703      * Visibility mode constant - Use display to hide element
9704      * @static
9705      * @type Number
9706      */
9707     El.DISPLAY = 2;
9708
9709     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9710     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9711     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9712
9713
9714
9715     /**
9716      * @private
9717      */
9718     El.cache = {};
9719
9720     var docEl;
9721
9722     /**
9723      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9724      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9725      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9726      * @return {Element} The Element object
9727      * @static
9728      */
9729     El.get = function(el){
9730         var ex, elm, id;
9731         if(!el){ return null; }
9732         if(typeof el == "string"){ // element id
9733             if(!(elm = document.getElementById(el))){
9734                 return null;
9735             }
9736             if(ex = El.cache[el]){
9737                 ex.dom = elm;
9738             }else{
9739                 ex = El.cache[el] = new El(elm);
9740             }
9741             return ex;
9742         }else if(el.tagName){ // dom element
9743             if(!(id = el.id)){
9744                 id = Roo.id(el);
9745             }
9746             if(ex = El.cache[id]){
9747                 ex.dom = el;
9748             }else{
9749                 ex = El.cache[id] = new El(el);
9750             }
9751             return ex;
9752         }else if(el instanceof El){
9753             if(el != docEl){
9754                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9755                                                               // catch case where it hasn't been appended
9756                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9757             }
9758             return el;
9759         }else if(el.isComposite){
9760             return el;
9761         }else if(el instanceof Array){
9762             return El.select(el);
9763         }else if(el == document){
9764             // create a bogus element object representing the document object
9765             if(!docEl){
9766                 var f = function(){};
9767                 f.prototype = El.prototype;
9768                 docEl = new f();
9769                 docEl.dom = document;
9770             }
9771             return docEl;
9772         }
9773         return null;
9774     };
9775
9776     // private
9777     El.uncache = function(el){
9778         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9779             if(a[i]){
9780                 delete El.cache[a[i].id || a[i]];
9781             }
9782         }
9783     };
9784
9785     // private
9786     // Garbage collection - uncache elements/purge listeners on orphaned elements
9787     // so we don't hold a reference and cause the browser to retain them
9788     El.garbageCollect = function(){
9789         if(!Roo.enableGarbageCollector){
9790             clearInterval(El.collectorThread);
9791             return;
9792         }
9793         for(var eid in El.cache){
9794             var el = El.cache[eid], d = el.dom;
9795             // -------------------------------------------------------
9796             // Determining what is garbage:
9797             // -------------------------------------------------------
9798             // !d
9799             // dom node is null, definitely garbage
9800             // -------------------------------------------------------
9801             // !d.parentNode
9802             // no parentNode == direct orphan, definitely garbage
9803             // -------------------------------------------------------
9804             // !d.offsetParent && !document.getElementById(eid)
9805             // display none elements have no offsetParent so we will
9806             // also try to look it up by it's id. However, check
9807             // offsetParent first so we don't do unneeded lookups.
9808             // This enables collection of elements that are not orphans
9809             // directly, but somewhere up the line they have an orphan
9810             // parent.
9811             // -------------------------------------------------------
9812             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9813                 delete El.cache[eid];
9814                 if(d && Roo.enableListenerCollection){
9815                     E.purgeElement(d);
9816                 }
9817             }
9818         }
9819     }
9820     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9821
9822
9823     // dom is optional
9824     El.Flyweight = function(dom){
9825         this.dom = dom;
9826     };
9827     El.Flyweight.prototype = El.prototype;
9828
9829     El._flyweights = {};
9830     /**
9831      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9832      * the dom node can be overwritten by other code.
9833      * @param {String/HTMLElement} el The dom node or id
9834      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9835      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9836      * @static
9837      * @return {Element} The shared Element object
9838      */
9839     El.fly = function(el, named){
9840         named = named || '_global';
9841         el = Roo.getDom(el);
9842         if(!el){
9843             return null;
9844         }
9845         if(!El._flyweights[named]){
9846             El._flyweights[named] = new El.Flyweight();
9847         }
9848         El._flyweights[named].dom = el;
9849         return El._flyweights[named];
9850     };
9851
9852     /**
9853      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9854      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9855      * Shorthand of {@link Roo.Element#get}
9856      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9857      * @return {Element} The Element object
9858      * @member Roo
9859      * @method get
9860      */
9861     Roo.get = El.get;
9862     /**
9863      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9864      * the dom node can be overwritten by other code.
9865      * Shorthand of {@link Roo.Element#fly}
9866      * @param {String/HTMLElement} el The dom node or id
9867      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9868      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9869      * @static
9870      * @return {Element} The shared Element object
9871      * @member Roo
9872      * @method fly
9873      */
9874     Roo.fly = El.fly;
9875
9876     // speedy lookup for elements never to box adjust
9877     var noBoxAdjust = Roo.isStrict ? {
9878         select:1
9879     } : {
9880         input:1, select:1, textarea:1
9881     };
9882     if(Roo.isIE || Roo.isGecko){
9883         noBoxAdjust['button'] = 1;
9884     }
9885
9886
9887     Roo.EventManager.on(window, 'unload', function(){
9888         delete El.cache;
9889         delete El._flyweights;
9890     });
9891 })();
9892
9893
9894
9895
9896 if(Roo.DomQuery){
9897     Roo.Element.selectorFunction = Roo.DomQuery.select;
9898 }
9899
9900 Roo.Element.select = function(selector, unique, root){
9901     var els;
9902     if(typeof selector == "string"){
9903         els = Roo.Element.selectorFunction(selector, root);
9904     }else if(selector.length !== undefined){
9905         els = selector;
9906     }else{
9907         throw "Invalid selector";
9908     }
9909     if(unique === true){
9910         return new Roo.CompositeElement(els);
9911     }else{
9912         return new Roo.CompositeElementLite(els);
9913     }
9914 };
9915 /**
9916  * Selects elements based on the passed CSS selector to enable working on them as 1.
9917  * @param {String/Array} selector The CSS selector or an array of elements
9918  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9919  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9920  * @return {CompositeElementLite/CompositeElement}
9921  * @member Roo
9922  * @method select
9923  */
9924 Roo.select = Roo.Element.select;
9925
9926
9927
9928
9929
9930
9931
9932
9933
9934
9935
9936
9937
9938
9939 /*
9940  * Based on:
9941  * Ext JS Library 1.1.1
9942  * Copyright(c) 2006-2007, Ext JS, LLC.
9943  *
9944  * Originally Released Under LGPL - original licence link has changed is not relivant.
9945  *
9946  * Fork - LGPL
9947  * <script type="text/javascript">
9948  */
9949
9950
9951
9952 //Notifies Element that fx methods are available
9953 Roo.enableFx = true;
9954
9955 /**
9956  * @class Roo.Fx
9957  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9958  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9959  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9960  * Element effects to work.</p><br/>
9961  *
9962  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9963  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9964  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9965  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9966  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9967  * expected results and should be done with care.</p><br/>
9968  *
9969  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9970  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9971 <pre>
9972 Value  Description
9973 -----  -----------------------------
9974 tl     The top left corner
9975 t      The center of the top edge
9976 tr     The top right corner
9977 l      The center of the left edge
9978 r      The center of the right edge
9979 bl     The bottom left corner
9980 b      The center of the bottom edge
9981 br     The bottom right corner
9982 </pre>
9983  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9984  * below are common options that can be passed to any Fx method.</b>
9985  * @cfg {Function} callback A function called when the effect is finished
9986  * @cfg {Object} scope The scope of the effect function
9987  * @cfg {String} easing A valid Easing value for the effect
9988  * @cfg {String} afterCls A css class to apply after the effect
9989  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9990  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9991  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9992  * effects that end with the element being visually hidden, ignored otherwise)
9993  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9994  * a function which returns such a specification that will be applied to the Element after the effect finishes
9995  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9996  * @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
9997  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9998  */
9999 Roo.Fx = {
10000         /**
10001          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10002          * origin for the slide effect.  This function automatically handles wrapping the element with
10003          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10004          * Usage:
10005          *<pre><code>
10006 // default: slide the element in from the top
10007 el.slideIn();
10008
10009 // custom: slide the element in from the right with a 2-second duration
10010 el.slideIn('r', { duration: 2 });
10011
10012 // common config options shown with default values
10013 el.slideIn('t', {
10014     easing: 'easeOut',
10015     duration: .5
10016 });
10017 </code></pre>
10018          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10019          * @param {Object} options (optional) Object literal with any of the Fx config options
10020          * @return {Roo.Element} The Element
10021          */
10022     slideIn : function(anchor, o){
10023         var el = this.getFxEl();
10024         o = o || {};
10025
10026         el.queueFx(o, function(){
10027
10028             anchor = anchor || "t";
10029
10030             // fix display to visibility
10031             this.fixDisplay();
10032
10033             // restore values after effect
10034             var r = this.getFxRestore();
10035             var b = this.getBox();
10036             // fixed size for slide
10037             this.setSize(b);
10038
10039             // wrap if needed
10040             var wrap = this.fxWrap(r.pos, o, "hidden");
10041
10042             var st = this.dom.style;
10043             st.visibility = "visible";
10044             st.position = "absolute";
10045
10046             // clear out temp styles after slide and unwrap
10047             var after = function(){
10048                 el.fxUnwrap(wrap, r.pos, o);
10049                 st.width = r.width;
10050                 st.height = r.height;
10051                 el.afterFx(o);
10052             };
10053             // time to calc the positions
10054             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10055
10056             switch(anchor.toLowerCase()){
10057                 case "t":
10058                     wrap.setSize(b.width, 0);
10059                     st.left = st.bottom = "0";
10060                     a = {height: bh};
10061                 break;
10062                 case "l":
10063                     wrap.setSize(0, b.height);
10064                     st.right = st.top = "0";
10065                     a = {width: bw};
10066                 break;
10067                 case "r":
10068                     wrap.setSize(0, b.height);
10069                     wrap.setX(b.right);
10070                     st.left = st.top = "0";
10071                     a = {width: bw, points: pt};
10072                 break;
10073                 case "b":
10074                     wrap.setSize(b.width, 0);
10075                     wrap.setY(b.bottom);
10076                     st.left = st.top = "0";
10077                     a = {height: bh, points: pt};
10078                 break;
10079                 case "tl":
10080                     wrap.setSize(0, 0);
10081                     st.right = st.bottom = "0";
10082                     a = {width: bw, height: bh};
10083                 break;
10084                 case "bl":
10085                     wrap.setSize(0, 0);
10086                     wrap.setY(b.y+b.height);
10087                     st.right = st.top = "0";
10088                     a = {width: bw, height: bh, points: pt};
10089                 break;
10090                 case "br":
10091                     wrap.setSize(0, 0);
10092                     wrap.setXY([b.right, b.bottom]);
10093                     st.left = st.top = "0";
10094                     a = {width: bw, height: bh, points: pt};
10095                 break;
10096                 case "tr":
10097                     wrap.setSize(0, 0);
10098                     wrap.setX(b.x+b.width);
10099                     st.left = st.bottom = "0";
10100                     a = {width: bw, height: bh, points: pt};
10101                 break;
10102             }
10103             this.dom.style.visibility = "visible";
10104             wrap.show();
10105
10106             arguments.callee.anim = wrap.fxanim(a,
10107                 o,
10108                 'motion',
10109                 .5,
10110                 'easeOut', after);
10111         });
10112         return this;
10113     },
10114     
10115         /**
10116          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10117          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10118          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10119          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10120          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10121          * Usage:
10122          *<pre><code>
10123 // default: slide the element out to the top
10124 el.slideOut();
10125
10126 // custom: slide the element out to the right with a 2-second duration
10127 el.slideOut('r', { duration: 2 });
10128
10129 // common config options shown with default values
10130 el.slideOut('t', {
10131     easing: 'easeOut',
10132     duration: .5,
10133     remove: false,
10134     useDisplay: false
10135 });
10136 </code></pre>
10137          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10138          * @param {Object} options (optional) Object literal with any of the Fx config options
10139          * @return {Roo.Element} The Element
10140          */
10141     slideOut : function(anchor, o){
10142         var el = this.getFxEl();
10143         o = o || {};
10144
10145         el.queueFx(o, function(){
10146
10147             anchor = anchor || "t";
10148
10149             // restore values after effect
10150             var r = this.getFxRestore();
10151             
10152             var b = this.getBox();
10153             // fixed size for slide
10154             this.setSize(b);
10155
10156             // wrap if needed
10157             var wrap = this.fxWrap(r.pos, o, "visible");
10158
10159             var st = this.dom.style;
10160             st.visibility = "visible";
10161             st.position = "absolute";
10162
10163             wrap.setSize(b);
10164
10165             var after = function(){
10166                 if(o.useDisplay){
10167                     el.setDisplayed(false);
10168                 }else{
10169                     el.hide();
10170                 }
10171
10172                 el.fxUnwrap(wrap, r.pos, o);
10173
10174                 st.width = r.width;
10175                 st.height = r.height;
10176
10177                 el.afterFx(o);
10178             };
10179
10180             var a, zero = {to: 0};
10181             switch(anchor.toLowerCase()){
10182                 case "t":
10183                     st.left = st.bottom = "0";
10184                     a = {height: zero};
10185                 break;
10186                 case "l":
10187                     st.right = st.top = "0";
10188                     a = {width: zero};
10189                 break;
10190                 case "r":
10191                     st.left = st.top = "0";
10192                     a = {width: zero, points: {to:[b.right, b.y]}};
10193                 break;
10194                 case "b":
10195                     st.left = st.top = "0";
10196                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10197                 break;
10198                 case "tl":
10199                     st.right = st.bottom = "0";
10200                     a = {width: zero, height: zero};
10201                 break;
10202                 case "bl":
10203                     st.right = st.top = "0";
10204                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10205                 break;
10206                 case "br":
10207                     st.left = st.top = "0";
10208                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10209                 break;
10210                 case "tr":
10211                     st.left = st.bottom = "0";
10212                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10213                 break;
10214             }
10215
10216             arguments.callee.anim = wrap.fxanim(a,
10217                 o,
10218                 'motion',
10219                 .5,
10220                 "easeOut", after);
10221         });
10222         return this;
10223     },
10224
10225         /**
10226          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10227          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10228          * The element must be removed from the DOM using the 'remove' config option if desired.
10229          * Usage:
10230          *<pre><code>
10231 // default
10232 el.puff();
10233
10234 // common config options shown with default values
10235 el.puff({
10236     easing: 'easeOut',
10237     duration: .5,
10238     remove: false,
10239     useDisplay: false
10240 });
10241 </code></pre>
10242          * @param {Object} options (optional) Object literal with any of the Fx config options
10243          * @return {Roo.Element} The Element
10244          */
10245     puff : function(o){
10246         var el = this.getFxEl();
10247         o = o || {};
10248
10249         el.queueFx(o, function(){
10250             this.clearOpacity();
10251             this.show();
10252
10253             // restore values after effect
10254             var r = this.getFxRestore();
10255             var st = this.dom.style;
10256
10257             var after = function(){
10258                 if(o.useDisplay){
10259                     el.setDisplayed(false);
10260                 }else{
10261                     el.hide();
10262                 }
10263
10264                 el.clearOpacity();
10265
10266                 el.setPositioning(r.pos);
10267                 st.width = r.width;
10268                 st.height = r.height;
10269                 st.fontSize = '';
10270                 el.afterFx(o);
10271             };
10272
10273             var width = this.getWidth();
10274             var height = this.getHeight();
10275
10276             arguments.callee.anim = this.fxanim({
10277                     width : {to: this.adjustWidth(width * 2)},
10278                     height : {to: this.adjustHeight(height * 2)},
10279                     points : {by: [-(width * .5), -(height * .5)]},
10280                     opacity : {to: 0},
10281                     fontSize: {to:200, unit: "%"}
10282                 },
10283                 o,
10284                 'motion',
10285                 .5,
10286                 "easeOut", after);
10287         });
10288         return this;
10289     },
10290
10291         /**
10292          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10293          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10294          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10295          * Usage:
10296          *<pre><code>
10297 // default
10298 el.switchOff();
10299
10300 // all config options shown with default values
10301 el.switchOff({
10302     easing: 'easeIn',
10303     duration: .3,
10304     remove: false,
10305     useDisplay: false
10306 });
10307 </code></pre>
10308          * @param {Object} options (optional) Object literal with any of the Fx config options
10309          * @return {Roo.Element} The Element
10310          */
10311     switchOff : function(o){
10312         var el = this.getFxEl();
10313         o = o || {};
10314
10315         el.queueFx(o, function(){
10316             this.clearOpacity();
10317             this.clip();
10318
10319             // restore values after effect
10320             var r = this.getFxRestore();
10321             var st = this.dom.style;
10322
10323             var after = function(){
10324                 if(o.useDisplay){
10325                     el.setDisplayed(false);
10326                 }else{
10327                     el.hide();
10328                 }
10329
10330                 el.clearOpacity();
10331                 el.setPositioning(r.pos);
10332                 st.width = r.width;
10333                 st.height = r.height;
10334
10335                 el.afterFx(o);
10336             };
10337
10338             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10339                 this.clearOpacity();
10340                 (function(){
10341                     this.fxanim({
10342                         height:{to:1},
10343                         points:{by:[0, this.getHeight() * .5]}
10344                     }, o, 'motion', 0.3, 'easeIn', after);
10345                 }).defer(100, this);
10346             });
10347         });
10348         return this;
10349     },
10350
10351     /**
10352      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10353      * changed using the "attr" config option) and then fading back to the original color. If no original
10354      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10355      * Usage:
10356 <pre><code>
10357 // default: highlight background to yellow
10358 el.highlight();
10359
10360 // custom: highlight foreground text to blue for 2 seconds
10361 el.highlight("0000ff", { attr: 'color', duration: 2 });
10362
10363 // common config options shown with default values
10364 el.highlight("ffff9c", {
10365     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10366     endColor: (current color) or "ffffff",
10367     easing: 'easeIn',
10368     duration: 1
10369 });
10370 </code></pre>
10371      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10372      * @param {Object} options (optional) Object literal with any of the Fx config options
10373      * @return {Roo.Element} The Element
10374      */ 
10375     highlight : function(color, o){
10376         var el = this.getFxEl();
10377         o = o || {};
10378
10379         el.queueFx(o, function(){
10380             color = color || "ffff9c";
10381             attr = o.attr || "backgroundColor";
10382
10383             this.clearOpacity();
10384             this.show();
10385
10386             var origColor = this.getColor(attr);
10387             var restoreColor = this.dom.style[attr];
10388             endColor = (o.endColor || origColor) || "ffffff";
10389
10390             var after = function(){
10391                 el.dom.style[attr] = restoreColor;
10392                 el.afterFx(o);
10393             };
10394
10395             var a = {};
10396             a[attr] = {from: color, to: endColor};
10397             arguments.callee.anim = this.fxanim(a,
10398                 o,
10399                 'color',
10400                 1,
10401                 'easeIn', after);
10402         });
10403         return this;
10404     },
10405
10406    /**
10407     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10408     * Usage:
10409 <pre><code>
10410 // default: a single light blue ripple
10411 el.frame();
10412
10413 // custom: 3 red ripples lasting 3 seconds total
10414 el.frame("ff0000", 3, { duration: 3 });
10415
10416 // common config options shown with default values
10417 el.frame("C3DAF9", 1, {
10418     duration: 1 //duration of entire animation (not each individual ripple)
10419     // Note: Easing is not configurable and will be ignored if included
10420 });
10421 </code></pre>
10422     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10423     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10424     * @param {Object} options (optional) Object literal with any of the Fx config options
10425     * @return {Roo.Element} The Element
10426     */
10427     frame : function(color, count, o){
10428         var el = this.getFxEl();
10429         o = o || {};
10430
10431         el.queueFx(o, function(){
10432             color = color || "#C3DAF9";
10433             if(color.length == 6){
10434                 color = "#" + color;
10435             }
10436             count = count || 1;
10437             duration = o.duration || 1;
10438             this.show();
10439
10440             var b = this.getBox();
10441             var animFn = function(){
10442                 var proxy = this.createProxy({
10443
10444                      style:{
10445                         visbility:"hidden",
10446                         position:"absolute",
10447                         "z-index":"35000", // yee haw
10448                         border:"0px solid " + color
10449                      }
10450                   });
10451                 var scale = Roo.isBorderBox ? 2 : 1;
10452                 proxy.animate({
10453                     top:{from:b.y, to:b.y - 20},
10454                     left:{from:b.x, to:b.x - 20},
10455                     borderWidth:{from:0, to:10},
10456                     opacity:{from:1, to:0},
10457                     height:{from:b.height, to:(b.height + (20*scale))},
10458                     width:{from:b.width, to:(b.width + (20*scale))}
10459                 }, duration, function(){
10460                     proxy.remove();
10461                 });
10462                 if(--count > 0){
10463                      animFn.defer((duration/2)*1000, this);
10464                 }else{
10465                     el.afterFx(o);
10466                 }
10467             };
10468             animFn.call(this);
10469         });
10470         return this;
10471     },
10472
10473    /**
10474     * Creates a pause before any subsequent queued effects begin.  If there are
10475     * no effects queued after the pause it will have no effect.
10476     * Usage:
10477 <pre><code>
10478 el.pause(1);
10479 </code></pre>
10480     * @param {Number} seconds The length of time to pause (in seconds)
10481     * @return {Roo.Element} The Element
10482     */
10483     pause : function(seconds){
10484         var el = this.getFxEl();
10485         var o = {};
10486
10487         el.queueFx(o, function(){
10488             setTimeout(function(){
10489                 el.afterFx(o);
10490             }, seconds * 1000);
10491         });
10492         return this;
10493     },
10494
10495    /**
10496     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10497     * using the "endOpacity" config option.
10498     * Usage:
10499 <pre><code>
10500 // default: fade in from opacity 0 to 100%
10501 el.fadeIn();
10502
10503 // custom: fade in from opacity 0 to 75% over 2 seconds
10504 el.fadeIn({ endOpacity: .75, duration: 2});
10505
10506 // common config options shown with default values
10507 el.fadeIn({
10508     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10509     easing: 'easeOut',
10510     duration: .5
10511 });
10512 </code></pre>
10513     * @param {Object} options (optional) Object literal with any of the Fx config options
10514     * @return {Roo.Element} The Element
10515     */
10516     fadeIn : function(o){
10517         var el = this.getFxEl();
10518         o = o || {};
10519         el.queueFx(o, function(){
10520             this.setOpacity(0);
10521             this.fixDisplay();
10522             this.dom.style.visibility = 'visible';
10523             var to = o.endOpacity || 1;
10524             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10525                 o, null, .5, "easeOut", function(){
10526                 if(to == 1){
10527                     this.clearOpacity();
10528                 }
10529                 el.afterFx(o);
10530             });
10531         });
10532         return this;
10533     },
10534
10535    /**
10536     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10537     * using the "endOpacity" config option.
10538     * Usage:
10539 <pre><code>
10540 // default: fade out from the element's current opacity to 0
10541 el.fadeOut();
10542
10543 // custom: fade out from the element's current opacity to 25% over 2 seconds
10544 el.fadeOut({ endOpacity: .25, duration: 2});
10545
10546 // common config options shown with default values
10547 el.fadeOut({
10548     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10549     easing: 'easeOut',
10550     duration: .5
10551     remove: false,
10552     useDisplay: false
10553 });
10554 </code></pre>
10555     * @param {Object} options (optional) Object literal with any of the Fx config options
10556     * @return {Roo.Element} The Element
10557     */
10558     fadeOut : function(o){
10559         var el = this.getFxEl();
10560         o = o || {};
10561         el.queueFx(o, function(){
10562             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10563                 o, null, .5, "easeOut", function(){
10564                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10565                      this.dom.style.display = "none";
10566                 }else{
10567                      this.dom.style.visibility = "hidden";
10568                 }
10569                 this.clearOpacity();
10570                 el.afterFx(o);
10571             });
10572         });
10573         return this;
10574     },
10575
10576    /**
10577     * Animates the transition of an element's dimensions from a starting height/width
10578     * to an ending height/width.
10579     * Usage:
10580 <pre><code>
10581 // change height and width to 100x100 pixels
10582 el.scale(100, 100);
10583
10584 // common config options shown with default values.  The height and width will default to
10585 // the element's existing values if passed as null.
10586 el.scale(
10587     [element's width],
10588     [element's height], {
10589     easing: 'easeOut',
10590     duration: .35
10591 });
10592 </code></pre>
10593     * @param {Number} width  The new width (pass undefined to keep the original width)
10594     * @param {Number} height  The new height (pass undefined to keep the original height)
10595     * @param {Object} options (optional) Object literal with any of the Fx config options
10596     * @return {Roo.Element} The Element
10597     */
10598     scale : function(w, h, o){
10599         this.shift(Roo.apply({}, o, {
10600             width: w,
10601             height: h
10602         }));
10603         return this;
10604     },
10605
10606    /**
10607     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10608     * Any of these properties not specified in the config object will not be changed.  This effect 
10609     * requires that at least one new dimension, position or opacity setting must be passed in on
10610     * the config object in order for the function to have any effect.
10611     * Usage:
10612 <pre><code>
10613 // slide the element horizontally to x position 200 while changing the height and opacity
10614 el.shift({ x: 200, height: 50, opacity: .8 });
10615
10616 // common config options shown with default values.
10617 el.shift({
10618     width: [element's width],
10619     height: [element's height],
10620     x: [element's x position],
10621     y: [element's y position],
10622     opacity: [element's opacity],
10623     easing: 'easeOut',
10624     duration: .35
10625 });
10626 </code></pre>
10627     * @param {Object} options  Object literal with any of the Fx config options
10628     * @return {Roo.Element} The Element
10629     */
10630     shift : function(o){
10631         var el = this.getFxEl();
10632         o = o || {};
10633         el.queueFx(o, function(){
10634             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10635             if(w !== undefined){
10636                 a.width = {to: this.adjustWidth(w)};
10637             }
10638             if(h !== undefined){
10639                 a.height = {to: this.adjustHeight(h)};
10640             }
10641             if(x !== undefined || y !== undefined){
10642                 a.points = {to: [
10643                     x !== undefined ? x : this.getX(),
10644                     y !== undefined ? y : this.getY()
10645                 ]};
10646             }
10647             if(op !== undefined){
10648                 a.opacity = {to: op};
10649             }
10650             if(o.xy !== undefined){
10651                 a.points = {to: o.xy};
10652             }
10653             arguments.callee.anim = this.fxanim(a,
10654                 o, 'motion', .35, "easeOut", function(){
10655                 el.afterFx(o);
10656             });
10657         });
10658         return this;
10659     },
10660
10661         /**
10662          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10663          * ending point of the effect.
10664          * Usage:
10665          *<pre><code>
10666 // default: slide the element downward while fading out
10667 el.ghost();
10668
10669 // custom: slide the element out to the right with a 2-second duration
10670 el.ghost('r', { duration: 2 });
10671
10672 // common config options shown with default values
10673 el.ghost('b', {
10674     easing: 'easeOut',
10675     duration: .5
10676     remove: false,
10677     useDisplay: false
10678 });
10679 </code></pre>
10680          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10681          * @param {Object} options (optional) Object literal with any of the Fx config options
10682          * @return {Roo.Element} The Element
10683          */
10684     ghost : function(anchor, o){
10685         var el = this.getFxEl();
10686         o = o || {};
10687
10688         el.queueFx(o, function(){
10689             anchor = anchor || "b";
10690
10691             // restore values after effect
10692             var r = this.getFxRestore();
10693             var w = this.getWidth(),
10694                 h = this.getHeight();
10695
10696             var st = this.dom.style;
10697
10698             var after = function(){
10699                 if(o.useDisplay){
10700                     el.setDisplayed(false);
10701                 }else{
10702                     el.hide();
10703                 }
10704
10705                 el.clearOpacity();
10706                 el.setPositioning(r.pos);
10707                 st.width = r.width;
10708                 st.height = r.height;
10709
10710                 el.afterFx(o);
10711             };
10712
10713             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10714             switch(anchor.toLowerCase()){
10715                 case "t":
10716                     pt.by = [0, -h];
10717                 break;
10718                 case "l":
10719                     pt.by = [-w, 0];
10720                 break;
10721                 case "r":
10722                     pt.by = [w, 0];
10723                 break;
10724                 case "b":
10725                     pt.by = [0, h];
10726                 break;
10727                 case "tl":
10728                     pt.by = [-w, -h];
10729                 break;
10730                 case "bl":
10731                     pt.by = [-w, h];
10732                 break;
10733                 case "br":
10734                     pt.by = [w, h];
10735                 break;
10736                 case "tr":
10737                     pt.by = [w, -h];
10738                 break;
10739             }
10740
10741             arguments.callee.anim = this.fxanim(a,
10742                 o,
10743                 'motion',
10744                 .5,
10745                 "easeOut", after);
10746         });
10747         return this;
10748     },
10749
10750         /**
10751          * Ensures that all effects queued after syncFx is called on the element are
10752          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10753          * @return {Roo.Element} The Element
10754          */
10755     syncFx : function(){
10756         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10757             block : false,
10758             concurrent : true,
10759             stopFx : false
10760         });
10761         return this;
10762     },
10763
10764         /**
10765          * Ensures that all effects queued after sequenceFx is called on the element are
10766          * run in sequence.  This is the opposite of {@link #syncFx}.
10767          * @return {Roo.Element} The Element
10768          */
10769     sequenceFx : function(){
10770         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10771             block : false,
10772             concurrent : false,
10773             stopFx : false
10774         });
10775         return this;
10776     },
10777
10778         /* @private */
10779     nextFx : function(){
10780         var ef = this.fxQueue[0];
10781         if(ef){
10782             ef.call(this);
10783         }
10784     },
10785
10786         /**
10787          * Returns true if the element has any effects actively running or queued, else returns false.
10788          * @return {Boolean} True if element has active effects, else false
10789          */
10790     hasActiveFx : function(){
10791         return this.fxQueue && this.fxQueue[0];
10792     },
10793
10794         /**
10795          * Stops any running effects and clears the element's internal effects queue if it contains
10796          * any additional effects that haven't started yet.
10797          * @return {Roo.Element} The Element
10798          */
10799     stopFx : function(){
10800         if(this.hasActiveFx()){
10801             var cur = this.fxQueue[0];
10802             if(cur && cur.anim && cur.anim.isAnimated()){
10803                 this.fxQueue = [cur]; // clear out others
10804                 cur.anim.stop(true);
10805             }
10806         }
10807         return this;
10808     },
10809
10810         /* @private */
10811     beforeFx : function(o){
10812         if(this.hasActiveFx() && !o.concurrent){
10813            if(o.stopFx){
10814                this.stopFx();
10815                return true;
10816            }
10817            return false;
10818         }
10819         return true;
10820     },
10821
10822         /**
10823          * Returns true if the element is currently blocking so that no other effect can be queued
10824          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10825          * used to ensure that an effect initiated by a user action runs to completion prior to the
10826          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10827          * @return {Boolean} True if blocking, else false
10828          */
10829     hasFxBlock : function(){
10830         var q = this.fxQueue;
10831         return q && q[0] && q[0].block;
10832     },
10833
10834         /* @private */
10835     queueFx : function(o, fn){
10836         if(!this.fxQueue){
10837             this.fxQueue = [];
10838         }
10839         if(!this.hasFxBlock()){
10840             Roo.applyIf(o, this.fxDefaults);
10841             if(!o.concurrent){
10842                 var run = this.beforeFx(o);
10843                 fn.block = o.block;
10844                 this.fxQueue.push(fn);
10845                 if(run){
10846                     this.nextFx();
10847                 }
10848             }else{
10849                 fn.call(this);
10850             }
10851         }
10852         return this;
10853     },
10854
10855         /* @private */
10856     fxWrap : function(pos, o, vis){
10857         var wrap;
10858         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10859             var wrapXY;
10860             if(o.fixPosition){
10861                 wrapXY = this.getXY();
10862             }
10863             var div = document.createElement("div");
10864             div.style.visibility = vis;
10865             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10866             wrap.setPositioning(pos);
10867             if(wrap.getStyle("position") == "static"){
10868                 wrap.position("relative");
10869             }
10870             this.clearPositioning('auto');
10871             wrap.clip();
10872             wrap.dom.appendChild(this.dom);
10873             if(wrapXY){
10874                 wrap.setXY(wrapXY);
10875             }
10876         }
10877         return wrap;
10878     },
10879
10880         /* @private */
10881     fxUnwrap : function(wrap, pos, o){
10882         this.clearPositioning();
10883         this.setPositioning(pos);
10884         if(!o.wrap){
10885             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10886             wrap.remove();
10887         }
10888     },
10889
10890         /* @private */
10891     getFxRestore : function(){
10892         var st = this.dom.style;
10893         return {pos: this.getPositioning(), width: st.width, height : st.height};
10894     },
10895
10896         /* @private */
10897     afterFx : function(o){
10898         if(o.afterStyle){
10899             this.applyStyles(o.afterStyle);
10900         }
10901         if(o.afterCls){
10902             this.addClass(o.afterCls);
10903         }
10904         if(o.remove === true){
10905             this.remove();
10906         }
10907         Roo.callback(o.callback, o.scope, [this]);
10908         if(!o.concurrent){
10909             this.fxQueue.shift();
10910             this.nextFx();
10911         }
10912     },
10913
10914         /* @private */
10915     getFxEl : function(){ // support for composite element fx
10916         return Roo.get(this.dom);
10917     },
10918
10919         /* @private */
10920     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10921         animType = animType || 'run';
10922         opt = opt || {};
10923         var anim = Roo.lib.Anim[animType](
10924             this.dom, args,
10925             (opt.duration || defaultDur) || .35,
10926             (opt.easing || defaultEase) || 'easeOut',
10927             function(){
10928                 Roo.callback(cb, this);
10929             },
10930             this
10931         );
10932         opt.anim = anim;
10933         return anim;
10934     }
10935 };
10936
10937 // backwords compat
10938 Roo.Fx.resize = Roo.Fx.scale;
10939
10940 //When included, Roo.Fx is automatically applied to Element so that all basic
10941 //effects are available directly via the Element API
10942 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10943  * Based on:
10944  * Ext JS Library 1.1.1
10945  * Copyright(c) 2006-2007, Ext JS, LLC.
10946  *
10947  * Originally Released Under LGPL - original licence link has changed is not relivant.
10948  *
10949  * Fork - LGPL
10950  * <script type="text/javascript">
10951  */
10952
10953
10954 /**
10955  * @class Roo.CompositeElement
10956  * Standard composite class. Creates a Roo.Element for every element in the collection.
10957  * <br><br>
10958  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10959  * actions will be performed on all the elements in this collection.</b>
10960  * <br><br>
10961  * All methods return <i>this</i> and can be chained.
10962  <pre><code>
10963  var els = Roo.select("#some-el div.some-class", true);
10964  // or select directly from an existing element
10965  var el = Roo.get('some-el');
10966  el.select('div.some-class', true);
10967
10968  els.setWidth(100); // all elements become 100 width
10969  els.hide(true); // all elements fade out and hide
10970  // or
10971  els.setWidth(100).hide(true);
10972  </code></pre>
10973  */
10974 Roo.CompositeElement = function(els){
10975     this.elements = [];
10976     this.addElements(els);
10977 };
10978 Roo.CompositeElement.prototype = {
10979     isComposite: true,
10980     addElements : function(els){
10981         if(!els) return this;
10982         if(typeof els == "string"){
10983             els = Roo.Element.selectorFunction(els);
10984         }
10985         var yels = this.elements;
10986         var index = yels.length-1;
10987         for(var i = 0, len = els.length; i < len; i++) {
10988                 yels[++index] = Roo.get(els[i]);
10989         }
10990         return this;
10991     },
10992
10993     /**
10994     * Clears this composite and adds the elements returned by the passed selector.
10995     * @param {String/Array} els A string CSS selector, an array of elements or an element
10996     * @return {CompositeElement} this
10997     */
10998     fill : function(els){
10999         this.elements = [];
11000         this.add(els);
11001         return this;
11002     },
11003
11004     /**
11005     * Filters this composite to only elements that match the passed selector.
11006     * @param {String} selector A string CSS selector
11007     * @param {Boolean} inverse return inverse filter (not matches)
11008     * @return {CompositeElement} this
11009     */
11010     filter : function(selector, inverse){
11011         var els = [];
11012         inverse = inverse || false;
11013         this.each(function(el){
11014             var match = inverse ? !el.is(selector) : el.is(selector);
11015             if(match){
11016                 els[els.length] = el.dom;
11017             }
11018         });
11019         this.fill(els);
11020         return this;
11021     },
11022
11023     invoke : function(fn, args){
11024         var els = this.elements;
11025         for(var i = 0, len = els.length; i < len; i++) {
11026                 Roo.Element.prototype[fn].apply(els[i], args);
11027         }
11028         return this;
11029     },
11030     /**
11031     * Adds elements to this composite.
11032     * @param {String/Array} els A string CSS selector, an array of elements or an element
11033     * @return {CompositeElement} this
11034     */
11035     add : function(els){
11036         if(typeof els == "string"){
11037             this.addElements(Roo.Element.selectorFunction(els));
11038         }else if(els.length !== undefined){
11039             this.addElements(els);
11040         }else{
11041             this.addElements([els]);
11042         }
11043         return this;
11044     },
11045     /**
11046     * Calls the passed function passing (el, this, index) for each element in this composite.
11047     * @param {Function} fn The function to call
11048     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11049     * @return {CompositeElement} this
11050     */
11051     each : function(fn, scope){
11052         var els = this.elements;
11053         for(var i = 0, len = els.length; i < len; i++){
11054             if(fn.call(scope || els[i], els[i], this, i) === false) {
11055                 break;
11056             }
11057         }
11058         return this;
11059     },
11060
11061     /**
11062      * Returns the Element object at the specified index
11063      * @param {Number} index
11064      * @return {Roo.Element}
11065      */
11066     item : function(index){
11067         return this.elements[index] || null;
11068     },
11069
11070     /**
11071      * Returns the first Element
11072      * @return {Roo.Element}
11073      */
11074     first : function(){
11075         return this.item(0);
11076     },
11077
11078     /**
11079      * Returns the last Element
11080      * @return {Roo.Element}
11081      */
11082     last : function(){
11083         return this.item(this.elements.length-1);
11084     },
11085
11086     /**
11087      * Returns the number of elements in this composite
11088      * @return Number
11089      */
11090     getCount : function(){
11091         return this.elements.length;
11092     },
11093
11094     /**
11095      * Returns true if this composite contains the passed element
11096      * @return Boolean
11097      */
11098     contains : function(el){
11099         return this.indexOf(el) !== -1;
11100     },
11101
11102     /**
11103      * Returns true if this composite contains the passed element
11104      * @return Boolean
11105      */
11106     indexOf : function(el){
11107         return this.elements.indexOf(Roo.get(el));
11108     },
11109
11110
11111     /**
11112     * Removes the specified element(s).
11113     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11114     * or an array of any of those.
11115     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11116     * @return {CompositeElement} this
11117     */
11118     removeElement : function(el, removeDom){
11119         if(el instanceof Array){
11120             for(var i = 0, len = el.length; i < len; i++){
11121                 this.removeElement(el[i]);
11122             }
11123             return this;
11124         }
11125         var index = typeof el == 'number' ? el : this.indexOf(el);
11126         if(index !== -1){
11127             if(removeDom){
11128                 var d = this.elements[index];
11129                 if(d.dom){
11130                     d.remove();
11131                 }else{
11132                     d.parentNode.removeChild(d);
11133                 }
11134             }
11135             this.elements.splice(index, 1);
11136         }
11137         return this;
11138     },
11139
11140     /**
11141     * Replaces the specified element with the passed element.
11142     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11143     * to replace.
11144     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11145     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11146     * @return {CompositeElement} this
11147     */
11148     replaceElement : function(el, replacement, domReplace){
11149         var index = typeof el == 'number' ? el : this.indexOf(el);
11150         if(index !== -1){
11151             if(domReplace){
11152                 this.elements[index].replaceWith(replacement);
11153             }else{
11154                 this.elements.splice(index, 1, Roo.get(replacement))
11155             }
11156         }
11157         return this;
11158     },
11159
11160     /**
11161      * Removes all elements.
11162      */
11163     clear : function(){
11164         this.elements = [];
11165     }
11166 };
11167 (function(){
11168     Roo.CompositeElement.createCall = function(proto, fnName){
11169         if(!proto[fnName]){
11170             proto[fnName] = function(){
11171                 return this.invoke(fnName, arguments);
11172             };
11173         }
11174     };
11175     for(var fnName in Roo.Element.prototype){
11176         if(typeof Roo.Element.prototype[fnName] == "function"){
11177             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11178         }
11179     };
11180 })();
11181 /*
11182  * Based on:
11183  * Ext JS Library 1.1.1
11184  * Copyright(c) 2006-2007, Ext JS, LLC.
11185  *
11186  * Originally Released Under LGPL - original licence link has changed is not relivant.
11187  *
11188  * Fork - LGPL
11189  * <script type="text/javascript">
11190  */
11191
11192 /**
11193  * @class Roo.CompositeElementLite
11194  * @extends Roo.CompositeElement
11195  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11196  <pre><code>
11197  var els = Roo.select("#some-el div.some-class");
11198  // or select directly from an existing element
11199  var el = Roo.get('some-el');
11200  el.select('div.some-class');
11201
11202  els.setWidth(100); // all elements become 100 width
11203  els.hide(true); // all elements fade out and hide
11204  // or
11205  els.setWidth(100).hide(true);
11206  </code></pre><br><br>
11207  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11208  * actions will be performed on all the elements in this collection.</b>
11209  */
11210 Roo.CompositeElementLite = function(els){
11211     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11212     this.el = new Roo.Element.Flyweight();
11213 };
11214 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11215     addElements : function(els){
11216         if(els){
11217             if(els instanceof Array){
11218                 this.elements = this.elements.concat(els);
11219             }else{
11220                 var yels = this.elements;
11221                 var index = yels.length-1;
11222                 for(var i = 0, len = els.length; i < len; i++) {
11223                     yels[++index] = els[i];
11224                 }
11225             }
11226         }
11227         return this;
11228     },
11229     invoke : function(fn, args){
11230         var els = this.elements;
11231         var el = this.el;
11232         for(var i = 0, len = els.length; i < len; i++) {
11233             el.dom = els[i];
11234                 Roo.Element.prototype[fn].apply(el, args);
11235         }
11236         return this;
11237     },
11238     /**
11239      * Returns a flyweight Element of the dom element object at the specified index
11240      * @param {Number} index
11241      * @return {Roo.Element}
11242      */
11243     item : function(index){
11244         if(!this.elements[index]){
11245             return null;
11246         }
11247         this.el.dom = this.elements[index];
11248         return this.el;
11249     },
11250
11251     // fixes scope with flyweight
11252     addListener : function(eventName, handler, scope, opt){
11253         var els = this.elements;
11254         for(var i = 0, len = els.length; i < len; i++) {
11255             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11256         }
11257         return this;
11258     },
11259
11260     /**
11261     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11262     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11263     * a reference to the dom node, use el.dom.</b>
11264     * @param {Function} fn The function to call
11265     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11266     * @return {CompositeElement} this
11267     */
11268     each : function(fn, scope){
11269         var els = this.elements;
11270         var el = this.el;
11271         for(var i = 0, len = els.length; i < len; i++){
11272             el.dom = els[i];
11273                 if(fn.call(scope || el, el, this, i) === false){
11274                 break;
11275             }
11276         }
11277         return this;
11278     },
11279
11280     indexOf : function(el){
11281         return this.elements.indexOf(Roo.getDom(el));
11282     },
11283
11284     replaceElement : function(el, replacement, domReplace){
11285         var index = typeof el == 'number' ? el : this.indexOf(el);
11286         if(index !== -1){
11287             replacement = Roo.getDom(replacement);
11288             if(domReplace){
11289                 var d = this.elements[index];
11290                 d.parentNode.insertBefore(replacement, d);
11291                 d.parentNode.removeChild(d);
11292             }
11293             this.elements.splice(index, 1, replacement);
11294         }
11295         return this;
11296     }
11297 });
11298 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11299
11300 /*
11301  * Based on:
11302  * Ext JS Library 1.1.1
11303  * Copyright(c) 2006-2007, Ext JS, LLC.
11304  *
11305  * Originally Released Under LGPL - original licence link has changed is not relivant.
11306  *
11307  * Fork - LGPL
11308  * <script type="text/javascript">
11309  */
11310
11311  
11312
11313 /**
11314  * @class Roo.data.Connection
11315  * @extends Roo.util.Observable
11316  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11317  * either to a configured URL, or to a URL specified at request time.<br><br>
11318  * <p>
11319  * Requests made by this class are asynchronous, and will return immediately. No data from
11320  * the server will be available to the statement immediately following the {@link #request} call.
11321  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11322  * <p>
11323  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11324  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11325  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11326  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11327  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11328  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11329  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11330  * standard DOM methods.
11331  * @constructor
11332  * @param {Object} config a configuration object.
11333  */
11334 Roo.data.Connection = function(config){
11335     Roo.apply(this, config);
11336     this.addEvents({
11337         /**
11338          * @event beforerequest
11339          * Fires before a network request is made to retrieve a data object.
11340          * @param {Connection} conn This Connection object.
11341          * @param {Object} options The options config object passed to the {@link #request} method.
11342          */
11343         "beforerequest" : true,
11344         /**
11345          * @event requestcomplete
11346          * Fires if the request was successfully completed.
11347          * @param {Connection} conn This Connection object.
11348          * @param {Object} response The XHR object containing the response data.
11349          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11350          * @param {Object} options The options config object passed to the {@link #request} method.
11351          */
11352         "requestcomplete" : true,
11353         /**
11354          * @event requestexception
11355          * Fires if an error HTTP status was returned from the server.
11356          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11357          * @param {Connection} conn This Connection object.
11358          * @param {Object} response The XHR object containing the response data.
11359          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11360          * @param {Object} options The options config object passed to the {@link #request} method.
11361          */
11362         "requestexception" : true
11363     });
11364     Roo.data.Connection.superclass.constructor.call(this);
11365 };
11366
11367 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11368     /**
11369      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11370      */
11371     /**
11372      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11373      * extra parameters to each request made by this object. (defaults to undefined)
11374      */
11375     /**
11376      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11377      *  to each request made by this object. (defaults to undefined)
11378      */
11379     /**
11380      * @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)
11381      */
11382     /**
11383      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11384      */
11385     timeout : 30000,
11386     /**
11387      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11388      * @type Boolean
11389      */
11390     autoAbort:false,
11391
11392     /**
11393      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11394      * @type Boolean
11395      */
11396     disableCaching: true,
11397
11398     /**
11399      * Sends an HTTP request to a remote server.
11400      * @param {Object} options An object which may contain the following properties:<ul>
11401      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11402      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11403      * request, a url encoded string or a function to call to get either.</li>
11404      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11405      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11406      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11407      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11408      * <li>options {Object} The parameter to the request call.</li>
11409      * <li>success {Boolean} True if the request succeeded.</li>
11410      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11411      * </ul></li>
11412      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11413      * The callback is passed the following parameters:<ul>
11414      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11415      * <li>options {Object} The parameter to the request call.</li>
11416      * </ul></li>
11417      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11418      * The callback is passed the following parameters:<ul>
11419      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11420      * <li>options {Object} The parameter to the request call.</li>
11421      * </ul></li>
11422      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11423      * for the callback function. Defaults to the browser window.</li>
11424      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11425      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11426      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11427      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11428      * params for the post data. Any params will be appended to the URL.</li>
11429      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11430      * </ul>
11431      * @return {Number} transactionId
11432      */
11433     request : function(o){
11434         if(this.fireEvent("beforerequest", this, o) !== false){
11435             var p = o.params;
11436
11437             if(typeof p == "function"){
11438                 p = p.call(o.scope||window, o);
11439             }
11440             if(typeof p == "object"){
11441                 p = Roo.urlEncode(o.params);
11442             }
11443             if(this.extraParams){
11444                 var extras = Roo.urlEncode(this.extraParams);
11445                 p = p ? (p + '&' + extras) : extras;
11446             }
11447
11448             var url = o.url || this.url;
11449             if(typeof url == 'function'){
11450                 url = url.call(o.scope||window, o);
11451             }
11452
11453             if(o.form){
11454                 var form = Roo.getDom(o.form);
11455                 url = url || form.action;
11456
11457                 var enctype = form.getAttribute("enctype");
11458                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11459                     return this.doFormUpload(o, p, url);
11460                 }
11461                 var f = Roo.lib.Ajax.serializeForm(form);
11462                 p = p ? (p + '&' + f) : f;
11463             }
11464
11465             var hs = o.headers;
11466             if(this.defaultHeaders){
11467                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11468                 if(!o.headers){
11469                     o.headers = hs;
11470                 }
11471             }
11472
11473             var cb = {
11474                 success: this.handleResponse,
11475                 failure: this.handleFailure,
11476                 scope: this,
11477                 argument: {options: o},
11478                 timeout : o.timeout || this.timeout
11479             };
11480
11481             var method = o.method||this.method||(p ? "POST" : "GET");
11482
11483             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11484                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11485             }
11486
11487             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11488                 if(o.autoAbort){
11489                     this.abort();
11490                 }
11491             }else if(this.autoAbort !== false){
11492                 this.abort();
11493             }
11494
11495             if((method == 'GET' && p) || o.xmlData){
11496                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11497                 p = '';
11498             }
11499             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11500             return this.transId;
11501         }else{
11502             Roo.callback(o.callback, o.scope, [o, null, null]);
11503             return null;
11504         }
11505     },
11506
11507     /**
11508      * Determine whether this object has a request outstanding.
11509      * @param {Number} transactionId (Optional) defaults to the last transaction
11510      * @return {Boolean} True if there is an outstanding request.
11511      */
11512     isLoading : function(transId){
11513         if(transId){
11514             return Roo.lib.Ajax.isCallInProgress(transId);
11515         }else{
11516             return this.transId ? true : false;
11517         }
11518     },
11519
11520     /**
11521      * Aborts any outstanding request.
11522      * @param {Number} transactionId (Optional) defaults to the last transaction
11523      */
11524     abort : function(transId){
11525         if(transId || this.isLoading()){
11526             Roo.lib.Ajax.abort(transId || this.transId);
11527         }
11528     },
11529
11530     // private
11531     handleResponse : function(response){
11532         this.transId = false;
11533         var options = response.argument.options;
11534         response.argument = options ? options.argument : null;
11535         this.fireEvent("requestcomplete", this, response, options);
11536         Roo.callback(options.success, options.scope, [response, options]);
11537         Roo.callback(options.callback, options.scope, [options, true, response]);
11538     },
11539
11540     // private
11541     handleFailure : function(response, e){
11542         this.transId = false;
11543         var options = response.argument.options;
11544         response.argument = options ? options.argument : null;
11545         this.fireEvent("requestexception", this, response, options, e);
11546         Roo.callback(options.failure, options.scope, [response, options]);
11547         Roo.callback(options.callback, options.scope, [options, false, response]);
11548     },
11549
11550     // private
11551     doFormUpload : function(o, ps, url){
11552         var id = Roo.id();
11553         var frame = document.createElement('iframe');
11554         frame.id = id;
11555         frame.name = id;
11556         frame.className = 'x-hidden';
11557         if(Roo.isIE){
11558             frame.src = Roo.SSL_SECURE_URL;
11559         }
11560         document.body.appendChild(frame);
11561
11562         if(Roo.isIE){
11563            document.frames[id].name = id;
11564         }
11565
11566         var form = Roo.getDom(o.form);
11567         form.target = id;
11568         form.method = 'POST';
11569         form.enctype = form.encoding = 'multipart/form-data';
11570         if(url){
11571             form.action = url;
11572         }
11573
11574         var hiddens, hd;
11575         if(ps){ // add dynamic params
11576             hiddens = [];
11577             ps = Roo.urlDecode(ps, false);
11578             for(var k in ps){
11579                 if(ps.hasOwnProperty(k)){
11580                     hd = document.createElement('input');
11581                     hd.type = 'hidden';
11582                     hd.name = k;
11583                     hd.value = ps[k];
11584                     form.appendChild(hd);
11585                     hiddens.push(hd);
11586                 }
11587             }
11588         }
11589
11590         function cb(){
11591             var r = {  // bogus response object
11592                 responseText : '',
11593                 responseXML : null
11594             };
11595
11596             r.argument = o ? o.argument : null;
11597
11598             try { //
11599                 var doc;
11600                 if(Roo.isIE){
11601                     doc = frame.contentWindow.document;
11602                 }else {
11603                     doc = (frame.contentDocument || window.frames[id].document);
11604                 }
11605                 if(doc && doc.body){
11606                     r.responseText = doc.body.innerHTML;
11607                 }
11608                 if(doc && doc.XMLDocument){
11609                     r.responseXML = doc.XMLDocument;
11610                 }else {
11611                     r.responseXML = doc;
11612                 }
11613             }
11614             catch(e) {
11615                 // ignore
11616             }
11617
11618             Roo.EventManager.removeListener(frame, 'load', cb, this);
11619
11620             this.fireEvent("requestcomplete", this, r, o);
11621             Roo.callback(o.success, o.scope, [r, o]);
11622             Roo.callback(o.callback, o.scope, [o, true, r]);
11623
11624             setTimeout(function(){document.body.removeChild(frame);}, 100);
11625         }
11626
11627         Roo.EventManager.on(frame, 'load', cb, this);
11628         form.submit();
11629
11630         if(hiddens){ // remove dynamic params
11631             for(var i = 0, len = hiddens.length; i < len; i++){
11632                 form.removeChild(hiddens[i]);
11633             }
11634         }
11635     }
11636 });
11637 /*
11638  * Based on:
11639  * Ext JS Library 1.1.1
11640  * Copyright(c) 2006-2007, Ext JS, LLC.
11641  *
11642  * Originally Released Under LGPL - original licence link has changed is not relivant.
11643  *
11644  * Fork - LGPL
11645  * <script type="text/javascript">
11646  */
11647  
11648 /**
11649  * Global Ajax request class.
11650  * 
11651  * @class Roo.Ajax
11652  * @extends Roo.data.Connection
11653  * @static
11654  * 
11655  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11656  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11657  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11658  * @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)
11659  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11660  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11661  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11662  */
11663 Roo.Ajax = new Roo.data.Connection({
11664     // fix up the docs
11665     /**
11666      * @scope Roo.Ajax
11667      * @type {Boolear} 
11668      */
11669     autoAbort : false,
11670
11671     /**
11672      * Serialize the passed form into a url encoded string
11673      * @scope Roo.Ajax
11674      * @param {String/HTMLElement} form
11675      * @return {String}
11676      */
11677     serializeForm : function(form){
11678         return Roo.lib.Ajax.serializeForm(form);
11679     }
11680 });/*
11681  * Based on:
11682  * Ext JS Library 1.1.1
11683  * Copyright(c) 2006-2007, Ext JS, LLC.
11684  *
11685  * Originally Released Under LGPL - original licence link has changed is not relivant.
11686  *
11687  * Fork - LGPL
11688  * <script type="text/javascript">
11689  */
11690
11691  
11692 /**
11693  * @class Roo.UpdateManager
11694  * @extends Roo.util.Observable
11695  * Provides AJAX-style update for Element object.<br><br>
11696  * Usage:<br>
11697  * <pre><code>
11698  * // Get it from a Roo.Element object
11699  * var el = Roo.get("foo");
11700  * var mgr = el.getUpdateManager();
11701  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11702  * ...
11703  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11704  * <br>
11705  * // or directly (returns the same UpdateManager instance)
11706  * var mgr = new Roo.UpdateManager("myElementId");
11707  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11708  * mgr.on("update", myFcnNeedsToKnow);
11709  * <br>
11710    // short handed call directly from the element object
11711    Roo.get("foo").load({
11712         url: "bar.php",
11713         scripts:true,
11714         params: "for=bar",
11715         text: "Loading Foo..."
11716    });
11717  * </code></pre>
11718  * @constructor
11719  * Create new UpdateManager directly.
11720  * @param {String/HTMLElement/Roo.Element} el The element to update
11721  * @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).
11722  */
11723 Roo.UpdateManager = function(el, forceNew){
11724     el = Roo.get(el);
11725     if(!forceNew && el.updateManager){
11726         return el.updateManager;
11727     }
11728     /**
11729      * The Element object
11730      * @type Roo.Element
11731      */
11732     this.el = el;
11733     /**
11734      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11735      * @type String
11736      */
11737     this.defaultUrl = null;
11738
11739     this.addEvents({
11740         /**
11741          * @event beforeupdate
11742          * Fired before an update is made, return false from your handler and the update is cancelled.
11743          * @param {Roo.Element} el
11744          * @param {String/Object/Function} url
11745          * @param {String/Object} params
11746          */
11747         "beforeupdate": true,
11748         /**
11749          * @event update
11750          * Fired after successful update is made.
11751          * @param {Roo.Element} el
11752          * @param {Object} oResponseObject The response Object
11753          */
11754         "update": true,
11755         /**
11756          * @event failure
11757          * Fired on update failure.
11758          * @param {Roo.Element} el
11759          * @param {Object} oResponseObject The response Object
11760          */
11761         "failure": true
11762     });
11763     var d = Roo.UpdateManager.defaults;
11764     /**
11765      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11766      * @type String
11767      */
11768     this.sslBlankUrl = d.sslBlankUrl;
11769     /**
11770      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11771      * @type Boolean
11772      */
11773     this.disableCaching = d.disableCaching;
11774     /**
11775      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11776      * @type String
11777      */
11778     this.indicatorText = d.indicatorText;
11779     /**
11780      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11781      * @type String
11782      */
11783     this.showLoadIndicator = d.showLoadIndicator;
11784     /**
11785      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11786      * @type Number
11787      */
11788     this.timeout = d.timeout;
11789
11790     /**
11791      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11792      * @type Boolean
11793      */
11794     this.loadScripts = d.loadScripts;
11795
11796     /**
11797      * Transaction object of current executing transaction
11798      */
11799     this.transaction = null;
11800
11801     /**
11802      * @private
11803      */
11804     this.autoRefreshProcId = null;
11805     /**
11806      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11807      * @type Function
11808      */
11809     this.refreshDelegate = this.refresh.createDelegate(this);
11810     /**
11811      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11812      * @type Function
11813      */
11814     this.updateDelegate = this.update.createDelegate(this);
11815     /**
11816      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11817      * @type Function
11818      */
11819     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11820     /**
11821      * @private
11822      */
11823     this.successDelegate = this.processSuccess.createDelegate(this);
11824     /**
11825      * @private
11826      */
11827     this.failureDelegate = this.processFailure.createDelegate(this);
11828
11829     if(!this.renderer){
11830      /**
11831       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11832       */
11833     this.renderer = new Roo.UpdateManager.BasicRenderer();
11834     }
11835     
11836     Roo.UpdateManager.superclass.constructor.call(this);
11837 };
11838
11839 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11840     /**
11841      * Get the Element this UpdateManager is bound to
11842      * @return {Roo.Element} The element
11843      */
11844     getEl : function(){
11845         return this.el;
11846     },
11847     /**
11848      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11849      * @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:
11850 <pre><code>
11851 um.update({<br/>
11852     url: "your-url.php",<br/>
11853     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11854     callback: yourFunction,<br/>
11855     scope: yourObject, //(optional scope)  <br/>
11856     discardUrl: false, <br/>
11857     nocache: false,<br/>
11858     text: "Loading...",<br/>
11859     timeout: 30,<br/>
11860     scripts: false<br/>
11861 });
11862 </code></pre>
11863      * The only required property is url. The optional properties nocache, text and scripts
11864      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11865      * @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}
11866      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11867      * @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.
11868      */
11869     update : function(url, params, callback, discardUrl){
11870         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11871             var method = this.method,
11872                 cfg;
11873             if(typeof url == "object"){ // must be config object
11874                 cfg = url;
11875                 url = cfg.url;
11876                 params = params || cfg.params;
11877                 callback = callback || cfg.callback;
11878                 discardUrl = discardUrl || cfg.discardUrl;
11879                 if(callback && cfg.scope){
11880                     callback = callback.createDelegate(cfg.scope);
11881                 }
11882                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11883                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11884                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11885                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11886                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11887             }
11888             this.showLoading();
11889             if(!discardUrl){
11890                 this.defaultUrl = url;
11891             }
11892             if(typeof url == "function"){
11893                 url = url.call(this);
11894             }
11895
11896             method = method || (params ? "POST" : "GET");
11897             if(method == "GET"){
11898                 url = this.prepareUrl(url);
11899             }
11900
11901             var o = Roo.apply(cfg ||{}, {
11902                 url : url,
11903                 params: params,
11904                 success: this.successDelegate,
11905                 failure: this.failureDelegate,
11906                 callback: undefined,
11907                 timeout: (this.timeout*1000),
11908                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11909             });
11910             Roo.log("updated manager called with timeout of " + o.timeout);
11911             this.transaction = Roo.Ajax.request(o);
11912         }
11913     },
11914
11915     /**
11916      * 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.
11917      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11918      * @param {String/HTMLElement} form The form Id or form element
11919      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11920      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11921      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11922      */
11923     formUpdate : function(form, url, reset, callback){
11924         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11925             if(typeof url == "function"){
11926                 url = url.call(this);
11927             }
11928             form = Roo.getDom(form);
11929             this.transaction = Roo.Ajax.request({
11930                 form: form,
11931                 url:url,
11932                 success: this.successDelegate,
11933                 failure: this.failureDelegate,
11934                 timeout: (this.timeout*1000),
11935                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11936             });
11937             this.showLoading.defer(1, this);
11938         }
11939     },
11940
11941     /**
11942      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11943      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11944      */
11945     refresh : function(callback){
11946         if(this.defaultUrl == null){
11947             return;
11948         }
11949         this.update(this.defaultUrl, null, callback, true);
11950     },
11951
11952     /**
11953      * Set this element to auto refresh.
11954      * @param {Number} interval How often to update (in seconds).
11955      * @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)
11956      * @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}
11957      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11958      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11959      */
11960     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11961         if(refreshNow){
11962             this.update(url || this.defaultUrl, params, callback, true);
11963         }
11964         if(this.autoRefreshProcId){
11965             clearInterval(this.autoRefreshProcId);
11966         }
11967         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11968     },
11969
11970     /**
11971      * Stop auto refresh on this element.
11972      */
11973      stopAutoRefresh : function(){
11974         if(this.autoRefreshProcId){
11975             clearInterval(this.autoRefreshProcId);
11976             delete this.autoRefreshProcId;
11977         }
11978     },
11979
11980     isAutoRefreshing : function(){
11981        return this.autoRefreshProcId ? true : false;
11982     },
11983     /**
11984      * Called to update the element to "Loading" state. Override to perform custom action.
11985      */
11986     showLoading : function(){
11987         if(this.showLoadIndicator){
11988             this.el.update(this.indicatorText);
11989         }
11990     },
11991
11992     /**
11993      * Adds unique parameter to query string if disableCaching = true
11994      * @private
11995      */
11996     prepareUrl : function(url){
11997         if(this.disableCaching){
11998             var append = "_dc=" + (new Date().getTime());
11999             if(url.indexOf("?") !== -1){
12000                 url += "&" + append;
12001             }else{
12002                 url += "?" + append;
12003             }
12004         }
12005         return url;
12006     },
12007
12008     /**
12009      * @private
12010      */
12011     processSuccess : function(response){
12012         this.transaction = null;
12013         if(response.argument.form && response.argument.reset){
12014             try{ // put in try/catch since some older FF releases had problems with this
12015                 response.argument.form.reset();
12016             }catch(e){}
12017         }
12018         if(this.loadScripts){
12019             this.renderer.render(this.el, response, this,
12020                 this.updateComplete.createDelegate(this, [response]));
12021         }else{
12022             this.renderer.render(this.el, response, this);
12023             this.updateComplete(response);
12024         }
12025     },
12026
12027     updateComplete : function(response){
12028         this.fireEvent("update", this.el, response);
12029         if(typeof response.argument.callback == "function"){
12030             response.argument.callback(this.el, true, response);
12031         }
12032     },
12033
12034     /**
12035      * @private
12036      */
12037     processFailure : function(response){
12038         this.transaction = null;
12039         this.fireEvent("failure", this.el, response);
12040         if(typeof response.argument.callback == "function"){
12041             response.argument.callback(this.el, false, response);
12042         }
12043     },
12044
12045     /**
12046      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12047      * @param {Object} renderer The object implementing the render() method
12048      */
12049     setRenderer : function(renderer){
12050         this.renderer = renderer;
12051     },
12052
12053     getRenderer : function(){
12054        return this.renderer;
12055     },
12056
12057     /**
12058      * Set the defaultUrl used for updates
12059      * @param {String/Function} defaultUrl The url or a function to call to get the url
12060      */
12061     setDefaultUrl : function(defaultUrl){
12062         this.defaultUrl = defaultUrl;
12063     },
12064
12065     /**
12066      * Aborts the executing transaction
12067      */
12068     abort : function(){
12069         if(this.transaction){
12070             Roo.Ajax.abort(this.transaction);
12071         }
12072     },
12073
12074     /**
12075      * Returns true if an update is in progress
12076      * @return {Boolean}
12077      */
12078     isUpdating : function(){
12079         if(this.transaction){
12080             return Roo.Ajax.isLoading(this.transaction);
12081         }
12082         return false;
12083     }
12084 });
12085
12086 /**
12087  * @class Roo.UpdateManager.defaults
12088  * @static (not really - but it helps the doc tool)
12089  * The defaults collection enables customizing the default properties of UpdateManager
12090  */
12091    Roo.UpdateManager.defaults = {
12092        /**
12093          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12094          * @type Number
12095          */
12096          timeout : 30,
12097
12098          /**
12099          * True to process scripts by default (Defaults to false).
12100          * @type Boolean
12101          */
12102         loadScripts : false,
12103
12104         /**
12105         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12106         * @type String
12107         */
12108         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12109         /**
12110          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12111          * @type Boolean
12112          */
12113         disableCaching : false,
12114         /**
12115          * Whether to show indicatorText when loading (Defaults to true).
12116          * @type Boolean
12117          */
12118         showLoadIndicator : true,
12119         /**
12120          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12121          * @type String
12122          */
12123         indicatorText : '<div class="loading-indicator">Loading...</div>'
12124    };
12125
12126 /**
12127  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12128  *Usage:
12129  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12130  * @param {String/HTMLElement/Roo.Element} el The element to update
12131  * @param {String} url The url
12132  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12133  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12134  * @static
12135  * @deprecated
12136  * @member Roo.UpdateManager
12137  */
12138 Roo.UpdateManager.updateElement = function(el, url, params, options){
12139     var um = Roo.get(el, true).getUpdateManager();
12140     Roo.apply(um, options);
12141     um.update(url, params, options ? options.callback : null);
12142 };
12143 // alias for backwards compat
12144 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12145 /**
12146  * @class Roo.UpdateManager.BasicRenderer
12147  * Default Content renderer. Updates the elements innerHTML with the responseText.
12148  */
12149 Roo.UpdateManager.BasicRenderer = function(){};
12150
12151 Roo.UpdateManager.BasicRenderer.prototype = {
12152     /**
12153      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12154      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12155      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12156      * @param {Roo.Element} el The element being rendered
12157      * @param {Object} response The YUI Connect response object
12158      * @param {UpdateManager} updateManager The calling update manager
12159      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12160      */
12161      render : function(el, response, updateManager, callback){
12162         el.update(response.responseText, updateManager.loadScripts, callback);
12163     }
12164 };
12165 /*
12166  * Based on:
12167  * Roo JS
12168  * (c)) Alan Knowles
12169  * Licence : LGPL
12170  */
12171
12172
12173 /**
12174  * @class Roo.DomTemplate
12175  * @extends Roo.Template
12176  * An effort at a dom based template engine..
12177  *
12178  * Similar to XTemplate, except it uses dom parsing to create the template..
12179  *
12180  * Supported features:
12181  *
12182  *  Tags:
12183
12184 <pre><code>
12185       {a_variable} - output encoded.
12186       {a_variable.format:("Y-m-d")} - call a method on the variable
12187       {a_variable:raw} - unencoded output
12188       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12189       {a_variable:this.method_on_template(...)} - call a method on the template object.
12190  
12191 </code></pre>
12192  *  The tpl tag:
12193 <pre><code>
12194         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12195         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12196         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12197         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12198   
12199 </code></pre>
12200  *      
12201  */
12202 Roo.DomTemplate = function()
12203 {
12204      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12205      if (this.html) {
12206         this.compile();
12207      }
12208 };
12209
12210
12211 Roo.extend(Roo.DomTemplate, Roo.Template, {
12212     /**
12213      * id counter for sub templates.
12214      */
12215     id : 0,
12216     /**
12217      * flag to indicate if dom parser is inside a pre,
12218      * it will strip whitespace if not.
12219      */
12220     inPre : false,
12221     
12222     /**
12223      * The various sub templates
12224      */
12225     tpls : false,
12226     
12227     
12228     
12229     /**
12230      *
12231      * basic tag replacing syntax
12232      * WORD:WORD()
12233      *
12234      * // you can fake an object call by doing this
12235      *  x.t:(test,tesT) 
12236      * 
12237      */
12238     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12239     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12240     
12241     iterChild : function (node, method) {
12242         
12243         var oldPre = this.inPre;
12244         if (node.tagName == 'PRE') {
12245             this.inPre = true;
12246         }
12247         for( var i = 0; i < node.childNodes.length; i++) {
12248             method.call(this, node.childNodes[i]);
12249         }
12250         this.inPre = oldPre;
12251     },
12252     
12253     
12254     
12255     /**
12256      * compile the template
12257      *
12258      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12259      *
12260      */
12261     compile: function()
12262     {
12263         var s = this.html;
12264         
12265         // covert the html into DOM...
12266         var doc = false;
12267         var div =false;
12268         try {
12269             doc = document.implementation.createHTMLDocument("");
12270             doc.documentElement.innerHTML =   this.html  ;
12271             div = doc.documentElement;
12272         } catch (e) {
12273             // old IE... - nasty -- it causes all sorts of issues.. with
12274             // images getting pulled from server..
12275             div = document.createElement('div');
12276             div.innerHTML = this.html;
12277         }
12278         //doc.documentElement.innerHTML = htmlBody
12279          
12280         
12281         
12282         this.tpls = [];
12283         var _t = this;
12284         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12285         
12286         var tpls = this.tpls;
12287         
12288         // create a top level template from the snippet..
12289         
12290         //Roo.log(div.innerHTML);
12291         
12292         var tpl = {
12293             uid : 'master',
12294             id : this.id++,
12295             attr : false,
12296             value : false,
12297             body : div.innerHTML,
12298             
12299             forCall : false,
12300             execCall : false,
12301             dom : div,
12302             isTop : true
12303             
12304         };
12305         tpls.unshift(tpl);
12306         
12307         
12308         // compile them...
12309         this.tpls = [];
12310         Roo.each(tpls, function(tp){
12311             this.compileTpl(tp);
12312             this.tpls[tp.id] = tp;
12313         }, this);
12314         
12315         this.master = tpls[0];
12316         return this;
12317         
12318         
12319     },
12320     
12321     compileNode : function(node, istop) {
12322         // test for
12323         //Roo.log(node);
12324         
12325         
12326         // skip anything not a tag..
12327         if (node.nodeType != 1) {
12328             if (node.nodeType == 3 && !this.inPre) {
12329                 // reduce white space..
12330                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12331                 
12332             }
12333             return;
12334         }
12335         
12336         var tpl = {
12337             uid : false,
12338             id : false,
12339             attr : false,
12340             value : false,
12341             body : '',
12342             
12343             forCall : false,
12344             execCall : false,
12345             dom : false,
12346             isTop : istop
12347             
12348             
12349         };
12350         
12351         
12352         switch(true) {
12353             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12354             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12355             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12356             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12357             // no default..
12358         }
12359         
12360         
12361         if (!tpl.attr) {
12362             // just itterate children..
12363             this.iterChild(node,this.compileNode);
12364             return;
12365         }
12366         tpl.uid = this.id++;
12367         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12368         node.removeAttribute('roo-'+ tpl.attr);
12369         if (tpl.attr != 'name') {
12370             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12371             node.parentNode.replaceChild(placeholder,  node);
12372         } else {
12373             
12374             var placeholder =  document.createElement('span');
12375             placeholder.className = 'roo-tpl-' + tpl.value;
12376             node.parentNode.replaceChild(placeholder,  node);
12377         }
12378         
12379         // parent now sees '{domtplXXXX}
12380         this.iterChild(node,this.compileNode);
12381         
12382         // we should now have node body...
12383         var div = document.createElement('div');
12384         div.appendChild(node);
12385         tpl.dom = node;
12386         // this has the unfortunate side effect of converting tagged attributes
12387         // eg. href="{...}" into %7C...%7D
12388         // this has been fixed by searching for those combo's although it's a bit hacky..
12389         
12390         
12391         tpl.body = div.innerHTML;
12392         
12393         
12394          
12395         tpl.id = tpl.uid;
12396         switch(tpl.attr) {
12397             case 'for' :
12398                 switch (tpl.value) {
12399                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12400                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12401                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12402                 }
12403                 break;
12404             
12405             case 'exec':
12406                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12407                 break;
12408             
12409             case 'if':     
12410                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12411                 break;
12412             
12413             case 'name':
12414                 tpl.id  = tpl.value; // replace non characters???
12415                 break;
12416             
12417         }
12418         
12419         
12420         this.tpls.push(tpl);
12421         
12422         
12423         
12424     },
12425     
12426     
12427     
12428     
12429     /**
12430      * Compile a segment of the template into a 'sub-template'
12431      *
12432      * 
12433      * 
12434      *
12435      */
12436     compileTpl : function(tpl)
12437     {
12438         var fm = Roo.util.Format;
12439         var useF = this.disableFormats !== true;
12440         
12441         var sep = Roo.isGecko ? "+\n" : ",\n";
12442         
12443         var undef = function(str) {
12444             Roo.debug && Roo.log("Property not found :"  + str);
12445             return '';
12446         };
12447           
12448         //Roo.log(tpl.body);
12449         
12450         
12451         
12452         var fn = function(m, lbrace, name, format, args)
12453         {
12454             //Roo.log("ARGS");
12455             //Roo.log(arguments);
12456             args = args ? args.replace(/\\'/g,"'") : args;
12457             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12458             if (typeof(format) == 'undefined') {
12459                 format =  'htmlEncode'; 
12460             }
12461             if (format == 'raw' ) {
12462                 format = false;
12463             }
12464             
12465             if(name.substr(0, 6) == 'domtpl'){
12466                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12467             }
12468             
12469             // build an array of options to determine if value is undefined..
12470             
12471             // basically get 'xxxx.yyyy' then do
12472             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12473             //    (function () { Roo.log("Property not found"); return ''; })() :
12474             //    ......
12475             
12476             var udef_ar = [];
12477             var lookfor = '';
12478             Roo.each(name.split('.'), function(st) {
12479                 lookfor += (lookfor.length ? '.': '') + st;
12480                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12481             });
12482             
12483             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12484             
12485             
12486             if(format && useF){
12487                 
12488                 args = args ? ',' + args : "";
12489                  
12490                 if(format.substr(0, 5) != "this."){
12491                     format = "fm." + format + '(';
12492                 }else{
12493                     format = 'this.call("'+ format.substr(5) + '", ';
12494                     args = ", values";
12495                 }
12496                 
12497                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12498             }
12499              
12500             if (args && args.length) {
12501                 // called with xxyx.yuu:(test,test)
12502                 // change to ()
12503                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12504             }
12505             // raw.. - :raw modifier..
12506             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12507             
12508         };
12509         var body;
12510         // branched to use + in gecko and [].join() in others
12511         if(Roo.isGecko){
12512             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12513                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12514                     "';};};";
12515         }else{
12516             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12517             body.push(tpl.body.replace(/(\r\n|\n)/g,
12518                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12519             body.push("'].join('');};};");
12520             body = body.join('');
12521         }
12522         
12523         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12524        
12525         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12526         eval(body);
12527         
12528         return this;
12529     },
12530      
12531     /**
12532      * same as applyTemplate, except it's done to one of the subTemplates
12533      * when using named templates, you can do:
12534      *
12535      * var str = pl.applySubTemplate('your-name', values);
12536      *
12537      * 
12538      * @param {Number} id of the template
12539      * @param {Object} values to apply to template
12540      * @param {Object} parent (normaly the instance of this object)
12541      */
12542     applySubTemplate : function(id, values, parent)
12543     {
12544         
12545         
12546         var t = this.tpls[id];
12547         
12548         
12549         try { 
12550             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12551                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12552                 return '';
12553             }
12554         } catch(e) {
12555             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12556             Roo.log(values);
12557           
12558             return '';
12559         }
12560         try { 
12561             
12562             if(t.execCall && t.execCall.call(this, values, parent)){
12563                 return '';
12564             }
12565         } catch(e) {
12566             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12567             Roo.log(values);
12568             return '';
12569         }
12570         
12571         try {
12572             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12573             parent = t.target ? values : parent;
12574             if(t.forCall && vs instanceof Array){
12575                 var buf = [];
12576                 for(var i = 0, len = vs.length; i < len; i++){
12577                     try {
12578                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12579                     } catch (e) {
12580                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12581                         Roo.log(e.body);
12582                         //Roo.log(t.compiled);
12583                         Roo.log(vs[i]);
12584                     }   
12585                 }
12586                 return buf.join('');
12587             }
12588         } catch (e) {
12589             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12590             Roo.log(values);
12591             return '';
12592         }
12593         try {
12594             return t.compiled.call(this, vs, parent);
12595         } catch (e) {
12596             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12597             Roo.log(e.body);
12598             //Roo.log(t.compiled);
12599             Roo.log(values);
12600             return '';
12601         }
12602     },
12603
12604    
12605
12606     applyTemplate : function(values){
12607         return this.master.compiled.call(this, values, {});
12608         //var s = this.subs;
12609     },
12610
12611     apply : function(){
12612         return this.applyTemplate.apply(this, arguments);
12613     }
12614
12615  });
12616
12617 Roo.DomTemplate.from = function(el){
12618     el = Roo.getDom(el);
12619     return new Roo.Domtemplate(el.value || el.innerHTML);
12620 };/*
12621  * Based on:
12622  * Ext JS Library 1.1.1
12623  * Copyright(c) 2006-2007, Ext JS, LLC.
12624  *
12625  * Originally Released Under LGPL - original licence link has changed is not relivant.
12626  *
12627  * Fork - LGPL
12628  * <script type="text/javascript">
12629  */
12630
12631 /**
12632  * @class Roo.util.DelayedTask
12633  * Provides a convenient method of performing setTimeout where a new
12634  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12635  * You can use this class to buffer
12636  * the keypress events for a certain number of milliseconds, and perform only if they stop
12637  * for that amount of time.
12638  * @constructor The parameters to this constructor serve as defaults and are not required.
12639  * @param {Function} fn (optional) The default function to timeout
12640  * @param {Object} scope (optional) The default scope of that timeout
12641  * @param {Array} args (optional) The default Array of arguments
12642  */
12643 Roo.util.DelayedTask = function(fn, scope, args){
12644     var id = null, d, t;
12645
12646     var call = function(){
12647         var now = new Date().getTime();
12648         if(now - t >= d){
12649             clearInterval(id);
12650             id = null;
12651             fn.apply(scope, args || []);
12652         }
12653     };
12654     /**
12655      * Cancels any pending timeout and queues a new one
12656      * @param {Number} delay The milliseconds to delay
12657      * @param {Function} newFn (optional) Overrides function passed to constructor
12658      * @param {Object} newScope (optional) Overrides scope passed to constructor
12659      * @param {Array} newArgs (optional) Overrides args passed to constructor
12660      */
12661     this.delay = function(delay, newFn, newScope, newArgs){
12662         if(id && delay != d){
12663             this.cancel();
12664         }
12665         d = delay;
12666         t = new Date().getTime();
12667         fn = newFn || fn;
12668         scope = newScope || scope;
12669         args = newArgs || args;
12670         if(!id){
12671             id = setInterval(call, d);
12672         }
12673     };
12674
12675     /**
12676      * Cancel the last queued timeout
12677      */
12678     this.cancel = function(){
12679         if(id){
12680             clearInterval(id);
12681             id = null;
12682         }
12683     };
12684 };/*
12685  * Based on:
12686  * Ext JS Library 1.1.1
12687  * Copyright(c) 2006-2007, Ext JS, LLC.
12688  *
12689  * Originally Released Under LGPL - original licence link has changed is not relivant.
12690  *
12691  * Fork - LGPL
12692  * <script type="text/javascript">
12693  */
12694  
12695  
12696 Roo.util.TaskRunner = function(interval){
12697     interval = interval || 10;
12698     var tasks = [], removeQueue = [];
12699     var id = 0;
12700     var running = false;
12701
12702     var stopThread = function(){
12703         running = false;
12704         clearInterval(id);
12705         id = 0;
12706     };
12707
12708     var startThread = function(){
12709         if(!running){
12710             running = true;
12711             id = setInterval(runTasks, interval);
12712         }
12713     };
12714
12715     var removeTask = function(task){
12716         removeQueue.push(task);
12717         if(task.onStop){
12718             task.onStop();
12719         }
12720     };
12721
12722     var runTasks = function(){
12723         if(removeQueue.length > 0){
12724             for(var i = 0, len = removeQueue.length; i < len; i++){
12725                 tasks.remove(removeQueue[i]);
12726             }
12727             removeQueue = [];
12728             if(tasks.length < 1){
12729                 stopThread();
12730                 return;
12731             }
12732         }
12733         var now = new Date().getTime();
12734         for(var i = 0, len = tasks.length; i < len; ++i){
12735             var t = tasks[i];
12736             var itime = now - t.taskRunTime;
12737             if(t.interval <= itime){
12738                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12739                 t.taskRunTime = now;
12740                 if(rt === false || t.taskRunCount === t.repeat){
12741                     removeTask(t);
12742                     return;
12743                 }
12744             }
12745             if(t.duration && t.duration <= (now - t.taskStartTime)){
12746                 removeTask(t);
12747             }
12748         }
12749     };
12750
12751     /**
12752      * Queues a new task.
12753      * @param {Object} task
12754      */
12755     this.start = function(task){
12756         tasks.push(task);
12757         task.taskStartTime = new Date().getTime();
12758         task.taskRunTime = 0;
12759         task.taskRunCount = 0;
12760         startThread();
12761         return task;
12762     };
12763
12764     this.stop = function(task){
12765         removeTask(task);
12766         return task;
12767     };
12768
12769     this.stopAll = function(){
12770         stopThread();
12771         for(var i = 0, len = tasks.length; i < len; i++){
12772             if(tasks[i].onStop){
12773                 tasks[i].onStop();
12774             }
12775         }
12776         tasks = [];
12777         removeQueue = [];
12778     };
12779 };
12780
12781 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12782  * Based on:
12783  * Ext JS Library 1.1.1
12784  * Copyright(c) 2006-2007, Ext JS, LLC.
12785  *
12786  * Originally Released Under LGPL - original licence link has changed is not relivant.
12787  *
12788  * Fork - LGPL
12789  * <script type="text/javascript">
12790  */
12791
12792  
12793 /**
12794  * @class Roo.util.MixedCollection
12795  * @extends Roo.util.Observable
12796  * A Collection class that maintains both numeric indexes and keys and exposes events.
12797  * @constructor
12798  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12799  * collection (defaults to false)
12800  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12801  * and return the key value for that item.  This is used when available to look up the key on items that
12802  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12803  * equivalent to providing an implementation for the {@link #getKey} method.
12804  */
12805 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12806     this.items = [];
12807     this.map = {};
12808     this.keys = [];
12809     this.length = 0;
12810     this.addEvents({
12811         /**
12812          * @event clear
12813          * Fires when the collection is cleared.
12814          */
12815         "clear" : true,
12816         /**
12817          * @event add
12818          * Fires when an item is added to the collection.
12819          * @param {Number} index The index at which the item was added.
12820          * @param {Object} o The item added.
12821          * @param {String} key The key associated with the added item.
12822          */
12823         "add" : true,
12824         /**
12825          * @event replace
12826          * Fires when an item is replaced in the collection.
12827          * @param {String} key he key associated with the new added.
12828          * @param {Object} old The item being replaced.
12829          * @param {Object} new The new item.
12830          */
12831         "replace" : true,
12832         /**
12833          * @event remove
12834          * Fires when an item is removed from the collection.
12835          * @param {Object} o The item being removed.
12836          * @param {String} key (optional) The key associated with the removed item.
12837          */
12838         "remove" : true,
12839         "sort" : true
12840     });
12841     this.allowFunctions = allowFunctions === true;
12842     if(keyFn){
12843         this.getKey = keyFn;
12844     }
12845     Roo.util.MixedCollection.superclass.constructor.call(this);
12846 };
12847
12848 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12849     allowFunctions : false,
12850     
12851 /**
12852  * Adds an item to the collection.
12853  * @param {String} key The key to associate with the item
12854  * @param {Object} o The item to add.
12855  * @return {Object} The item added.
12856  */
12857     add : function(key, o){
12858         if(arguments.length == 1){
12859             o = arguments[0];
12860             key = this.getKey(o);
12861         }
12862         if(typeof key == "undefined" || key === null){
12863             this.length++;
12864             this.items.push(o);
12865             this.keys.push(null);
12866         }else{
12867             var old = this.map[key];
12868             if(old){
12869                 return this.replace(key, o);
12870             }
12871             this.length++;
12872             this.items.push(o);
12873             this.map[key] = o;
12874             this.keys.push(key);
12875         }
12876         this.fireEvent("add", this.length-1, o, key);
12877         return o;
12878     },
12879        
12880 /**
12881   * MixedCollection has a generic way to fetch keys if you implement getKey.
12882 <pre><code>
12883 // normal way
12884 var mc = new Roo.util.MixedCollection();
12885 mc.add(someEl.dom.id, someEl);
12886 mc.add(otherEl.dom.id, otherEl);
12887 //and so on
12888
12889 // using getKey
12890 var mc = new Roo.util.MixedCollection();
12891 mc.getKey = function(el){
12892    return el.dom.id;
12893 };
12894 mc.add(someEl);
12895 mc.add(otherEl);
12896
12897 // or via the constructor
12898 var mc = new Roo.util.MixedCollection(false, function(el){
12899    return el.dom.id;
12900 });
12901 mc.add(someEl);
12902 mc.add(otherEl);
12903 </code></pre>
12904  * @param o {Object} The item for which to find the key.
12905  * @return {Object} The key for the passed item.
12906  */
12907     getKey : function(o){
12908          return o.id; 
12909     },
12910    
12911 /**
12912  * Replaces an item in the collection.
12913  * @param {String} key The key associated with the item to replace, or the item to replace.
12914  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12915  * @return {Object}  The new item.
12916  */
12917     replace : function(key, o){
12918         if(arguments.length == 1){
12919             o = arguments[0];
12920             key = this.getKey(o);
12921         }
12922         var old = this.item(key);
12923         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12924              return this.add(key, o);
12925         }
12926         var index = this.indexOfKey(key);
12927         this.items[index] = o;
12928         this.map[key] = o;
12929         this.fireEvent("replace", key, old, o);
12930         return o;
12931     },
12932    
12933 /**
12934  * Adds all elements of an Array or an Object to the collection.
12935  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12936  * an Array of values, each of which are added to the collection.
12937  */
12938     addAll : function(objs){
12939         if(arguments.length > 1 || objs instanceof Array){
12940             var args = arguments.length > 1 ? arguments : objs;
12941             for(var i = 0, len = args.length; i < len; i++){
12942                 this.add(args[i]);
12943             }
12944         }else{
12945             for(var key in objs){
12946                 if(this.allowFunctions || typeof objs[key] != "function"){
12947                     this.add(key, objs[key]);
12948                 }
12949             }
12950         }
12951     },
12952    
12953 /**
12954  * Executes the specified function once for every item in the collection, passing each
12955  * item as the first and only parameter. returning false from the function will stop the iteration.
12956  * @param {Function} fn The function to execute for each item.
12957  * @param {Object} scope (optional) The scope in which to execute the function.
12958  */
12959     each : function(fn, scope){
12960         var items = [].concat(this.items); // each safe for removal
12961         for(var i = 0, len = items.length; i < len; i++){
12962             if(fn.call(scope || items[i], items[i], i, len) === false){
12963                 break;
12964             }
12965         }
12966     },
12967    
12968 /**
12969  * Executes the specified function once for every key in the collection, passing each
12970  * key, and its associated item as the first two parameters.
12971  * @param {Function} fn The function to execute for each item.
12972  * @param {Object} scope (optional) The scope in which to execute the function.
12973  */
12974     eachKey : function(fn, scope){
12975         for(var i = 0, len = this.keys.length; i < len; i++){
12976             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12977         }
12978     },
12979    
12980 /**
12981  * Returns the first item in the collection which elicits a true return value from the
12982  * passed selection function.
12983  * @param {Function} fn The selection function to execute for each item.
12984  * @param {Object} scope (optional) The scope in which to execute the function.
12985  * @return {Object} The first item in the collection which returned true from the selection function.
12986  */
12987     find : function(fn, scope){
12988         for(var i = 0, len = this.items.length; i < len; i++){
12989             if(fn.call(scope || window, this.items[i], this.keys[i])){
12990                 return this.items[i];
12991             }
12992         }
12993         return null;
12994     },
12995    
12996 /**
12997  * Inserts an item at the specified index in the collection.
12998  * @param {Number} index The index to insert the item at.
12999  * @param {String} key The key to associate with the new item, or the item itself.
13000  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13001  * @return {Object} The item inserted.
13002  */
13003     insert : function(index, key, o){
13004         if(arguments.length == 2){
13005             o = arguments[1];
13006             key = this.getKey(o);
13007         }
13008         if(index >= this.length){
13009             return this.add(key, o);
13010         }
13011         this.length++;
13012         this.items.splice(index, 0, o);
13013         if(typeof key != "undefined" && key != null){
13014             this.map[key] = o;
13015         }
13016         this.keys.splice(index, 0, key);
13017         this.fireEvent("add", index, o, key);
13018         return o;
13019     },
13020    
13021 /**
13022  * Removed an item from the collection.
13023  * @param {Object} o The item to remove.
13024  * @return {Object} The item removed.
13025  */
13026     remove : function(o){
13027         return this.removeAt(this.indexOf(o));
13028     },
13029    
13030 /**
13031  * Remove an item from a specified index in the collection.
13032  * @param {Number} index The index within the collection of the item to remove.
13033  */
13034     removeAt : function(index){
13035         if(index < this.length && index >= 0){
13036             this.length--;
13037             var o = this.items[index];
13038             this.items.splice(index, 1);
13039             var key = this.keys[index];
13040             if(typeof key != "undefined"){
13041                 delete this.map[key];
13042             }
13043             this.keys.splice(index, 1);
13044             this.fireEvent("remove", o, key);
13045         }
13046     },
13047    
13048 /**
13049  * Removed an item associated with the passed key fom the collection.
13050  * @param {String} key The key of the item to remove.
13051  */
13052     removeKey : function(key){
13053         return this.removeAt(this.indexOfKey(key));
13054     },
13055    
13056 /**
13057  * Returns the number of items in the collection.
13058  * @return {Number} the number of items in the collection.
13059  */
13060     getCount : function(){
13061         return this.length; 
13062     },
13063    
13064 /**
13065  * Returns index within the collection of the passed Object.
13066  * @param {Object} o The item to find the index of.
13067  * @return {Number} index of the item.
13068  */
13069     indexOf : function(o){
13070         if(!this.items.indexOf){
13071             for(var i = 0, len = this.items.length; i < len; i++){
13072                 if(this.items[i] == o) return i;
13073             }
13074             return -1;
13075         }else{
13076             return this.items.indexOf(o);
13077         }
13078     },
13079    
13080 /**
13081  * Returns index within the collection of the passed key.
13082  * @param {String} key The key to find the index of.
13083  * @return {Number} index of the key.
13084  */
13085     indexOfKey : function(key){
13086         if(!this.keys.indexOf){
13087             for(var i = 0, len = this.keys.length; i < len; i++){
13088                 if(this.keys[i] == key) return i;
13089             }
13090             return -1;
13091         }else{
13092             return this.keys.indexOf(key);
13093         }
13094     },
13095    
13096 /**
13097  * Returns the item associated with the passed key OR index. Key has priority over index.
13098  * @param {String/Number} key The key or index of the item.
13099  * @return {Object} The item associated with the passed key.
13100  */
13101     item : function(key){
13102         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13103         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13104     },
13105     
13106 /**
13107  * Returns the item at the specified index.
13108  * @param {Number} index The index of the item.
13109  * @return {Object}
13110  */
13111     itemAt : function(index){
13112         return this.items[index];
13113     },
13114     
13115 /**
13116  * Returns the item associated with the passed key.
13117  * @param {String/Number} key The key of the item.
13118  * @return {Object} The item associated with the passed key.
13119  */
13120     key : function(key){
13121         return this.map[key];
13122     },
13123    
13124 /**
13125  * Returns true if the collection contains the passed Object as an item.
13126  * @param {Object} o  The Object to look for in the collection.
13127  * @return {Boolean} True if the collection contains the Object as an item.
13128  */
13129     contains : function(o){
13130         return this.indexOf(o) != -1;
13131     },
13132    
13133 /**
13134  * Returns true if the collection contains the passed Object as a key.
13135  * @param {String} key The key to look for in the collection.
13136  * @return {Boolean} True if the collection contains the Object as a key.
13137  */
13138     containsKey : function(key){
13139         return typeof this.map[key] != "undefined";
13140     },
13141    
13142 /**
13143  * Removes all items from the collection.
13144  */
13145     clear : function(){
13146         this.length = 0;
13147         this.items = [];
13148         this.keys = [];
13149         this.map = {};
13150         this.fireEvent("clear");
13151     },
13152    
13153 /**
13154  * Returns the first item in the collection.
13155  * @return {Object} the first item in the collection..
13156  */
13157     first : function(){
13158         return this.items[0]; 
13159     },
13160    
13161 /**
13162  * Returns the last item in the collection.
13163  * @return {Object} the last item in the collection..
13164  */
13165     last : function(){
13166         return this.items[this.length-1];   
13167     },
13168     
13169     _sort : function(property, dir, fn){
13170         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13171         fn = fn || function(a, b){
13172             return a-b;
13173         };
13174         var c = [], k = this.keys, items = this.items;
13175         for(var i = 0, len = items.length; i < len; i++){
13176             c[c.length] = {key: k[i], value: items[i], index: i};
13177         }
13178         c.sort(function(a, b){
13179             var v = fn(a[property], b[property]) * dsc;
13180             if(v == 0){
13181                 v = (a.index < b.index ? -1 : 1);
13182             }
13183             return v;
13184         });
13185         for(var i = 0, len = c.length; i < len; i++){
13186             items[i] = c[i].value;
13187             k[i] = c[i].key;
13188         }
13189         this.fireEvent("sort", this);
13190     },
13191     
13192     /**
13193      * Sorts this collection with the passed comparison function
13194      * @param {String} direction (optional) "ASC" or "DESC"
13195      * @param {Function} fn (optional) comparison function
13196      */
13197     sort : function(dir, fn){
13198         this._sort("value", dir, fn);
13199     },
13200     
13201     /**
13202      * Sorts this collection by keys
13203      * @param {String} direction (optional) "ASC" or "DESC"
13204      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13205      */
13206     keySort : function(dir, fn){
13207         this._sort("key", dir, fn || function(a, b){
13208             return String(a).toUpperCase()-String(b).toUpperCase();
13209         });
13210     },
13211     
13212     /**
13213      * Returns a range of items in this collection
13214      * @param {Number} startIndex (optional) defaults to 0
13215      * @param {Number} endIndex (optional) default to the last item
13216      * @return {Array} An array of items
13217      */
13218     getRange : function(start, end){
13219         var items = this.items;
13220         if(items.length < 1){
13221             return [];
13222         }
13223         start = start || 0;
13224         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13225         var r = [];
13226         if(start <= end){
13227             for(var i = start; i <= end; i++) {
13228                     r[r.length] = items[i];
13229             }
13230         }else{
13231             for(var i = start; i >= end; i--) {
13232                     r[r.length] = items[i];
13233             }
13234         }
13235         return r;
13236     },
13237         
13238     /**
13239      * Filter the <i>objects</i> in this collection by a specific property. 
13240      * Returns a new collection that has been filtered.
13241      * @param {String} property A property on your objects
13242      * @param {String/RegExp} value Either string that the property values 
13243      * should start with or a RegExp to test against the property
13244      * @return {MixedCollection} The new filtered collection
13245      */
13246     filter : function(property, value){
13247         if(!value.exec){ // not a regex
13248             value = String(value);
13249             if(value.length == 0){
13250                 return this.clone();
13251             }
13252             value = new RegExp("^" + Roo.escapeRe(value), "i");
13253         }
13254         return this.filterBy(function(o){
13255             return o && value.test(o[property]);
13256         });
13257         },
13258     
13259     /**
13260      * Filter by a function. * Returns a new collection that has been filtered.
13261      * The passed function will be called with each 
13262      * object in the collection. If the function returns true, the value is included 
13263      * otherwise it is filtered.
13264      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13265      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13266      * @return {MixedCollection} The new filtered collection
13267      */
13268     filterBy : function(fn, scope){
13269         var r = new Roo.util.MixedCollection();
13270         r.getKey = this.getKey;
13271         var k = this.keys, it = this.items;
13272         for(var i = 0, len = it.length; i < len; i++){
13273             if(fn.call(scope||this, it[i], k[i])){
13274                                 r.add(k[i], it[i]);
13275                         }
13276         }
13277         return r;
13278     },
13279     
13280     /**
13281      * Creates a duplicate of this collection
13282      * @return {MixedCollection}
13283      */
13284     clone : function(){
13285         var r = new Roo.util.MixedCollection();
13286         var k = this.keys, it = this.items;
13287         for(var i = 0, len = it.length; i < len; i++){
13288             r.add(k[i], it[i]);
13289         }
13290         r.getKey = this.getKey;
13291         return r;
13292     }
13293 });
13294 /**
13295  * Returns the item associated with the passed key or index.
13296  * @method
13297  * @param {String/Number} key The key or index of the item.
13298  * @return {Object} The item associated with the passed key.
13299  */
13300 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13301  * Based on:
13302  * Ext JS Library 1.1.1
13303  * Copyright(c) 2006-2007, Ext JS, LLC.
13304  *
13305  * Originally Released Under LGPL - original licence link has changed is not relivant.
13306  *
13307  * Fork - LGPL
13308  * <script type="text/javascript">
13309  */
13310 /**
13311  * @class Roo.util.JSON
13312  * Modified version of Douglas Crockford"s json.js that doesn"t
13313  * mess with the Object prototype 
13314  * http://www.json.org/js.html
13315  * @singleton
13316  */
13317 Roo.util.JSON = new (function(){
13318     var useHasOwn = {}.hasOwnProperty ? true : false;
13319     
13320     // crashes Safari in some instances
13321     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13322     
13323     var pad = function(n) {
13324         return n < 10 ? "0" + n : n;
13325     };
13326     
13327     var m = {
13328         "\b": '\\b',
13329         "\t": '\\t',
13330         "\n": '\\n',
13331         "\f": '\\f',
13332         "\r": '\\r',
13333         '"' : '\\"',
13334         "\\": '\\\\'
13335     };
13336
13337     var encodeString = function(s){
13338         if (/["\\\x00-\x1f]/.test(s)) {
13339             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13340                 var c = m[b];
13341                 if(c){
13342                     return c;
13343                 }
13344                 c = b.charCodeAt();
13345                 return "\\u00" +
13346                     Math.floor(c / 16).toString(16) +
13347                     (c % 16).toString(16);
13348             }) + '"';
13349         }
13350         return '"' + s + '"';
13351     };
13352     
13353     var encodeArray = function(o){
13354         var a = ["["], b, i, l = o.length, v;
13355             for (i = 0; i < l; i += 1) {
13356                 v = o[i];
13357                 switch (typeof v) {
13358                     case "undefined":
13359                     case "function":
13360                     case "unknown":
13361                         break;
13362                     default:
13363                         if (b) {
13364                             a.push(',');
13365                         }
13366                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13367                         b = true;
13368                 }
13369             }
13370             a.push("]");
13371             return a.join("");
13372     };
13373     
13374     var encodeDate = function(o){
13375         return '"' + o.getFullYear() + "-" +
13376                 pad(o.getMonth() + 1) + "-" +
13377                 pad(o.getDate()) + "T" +
13378                 pad(o.getHours()) + ":" +
13379                 pad(o.getMinutes()) + ":" +
13380                 pad(o.getSeconds()) + '"';
13381     };
13382     
13383     /**
13384      * Encodes an Object, Array or other value
13385      * @param {Mixed} o The variable to encode
13386      * @return {String} The JSON string
13387      */
13388     this.encode = function(o)
13389     {
13390         // should this be extended to fully wrap stringify..
13391         
13392         if(typeof o == "undefined" || o === null){
13393             return "null";
13394         }else if(o instanceof Array){
13395             return encodeArray(o);
13396         }else if(o instanceof Date){
13397             return encodeDate(o);
13398         }else if(typeof o == "string"){
13399             return encodeString(o);
13400         }else if(typeof o == "number"){
13401             return isFinite(o) ? String(o) : "null";
13402         }else if(typeof o == "boolean"){
13403             return String(o);
13404         }else {
13405             var a = ["{"], b, i, v;
13406             for (i in o) {
13407                 if(!useHasOwn || o.hasOwnProperty(i)) {
13408                     v = o[i];
13409                     switch (typeof v) {
13410                     case "undefined":
13411                     case "function":
13412                     case "unknown":
13413                         break;
13414                     default:
13415                         if(b){
13416                             a.push(',');
13417                         }
13418                         a.push(this.encode(i), ":",
13419                                 v === null ? "null" : this.encode(v));
13420                         b = true;
13421                     }
13422                 }
13423             }
13424             a.push("}");
13425             return a.join("");
13426         }
13427     };
13428     
13429     /**
13430      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13431      * @param {String} json The JSON string
13432      * @return {Object} The resulting object
13433      */
13434     this.decode = function(json){
13435         
13436         return  /** eval:var:json */ eval("(" + json + ')');
13437     };
13438 })();
13439 /** 
13440  * Shorthand for {@link Roo.util.JSON#encode}
13441  * @member Roo encode 
13442  * @method */
13443 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13444 /** 
13445  * Shorthand for {@link Roo.util.JSON#decode}
13446  * @member Roo decode 
13447  * @method */
13448 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13449 /*
13450  * Based on:
13451  * Ext JS Library 1.1.1
13452  * Copyright(c) 2006-2007, Ext JS, LLC.
13453  *
13454  * Originally Released Under LGPL - original licence link has changed is not relivant.
13455  *
13456  * Fork - LGPL
13457  * <script type="text/javascript">
13458  */
13459  
13460 /**
13461  * @class Roo.util.Format
13462  * Reusable data formatting functions
13463  * @singleton
13464  */
13465 Roo.util.Format = function(){
13466     var trimRe = /^\s+|\s+$/g;
13467     return {
13468         /**
13469          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13470          * @param {String} value The string to truncate
13471          * @param {Number} length The maximum length to allow before truncating
13472          * @return {String} The converted text
13473          */
13474         ellipsis : function(value, len){
13475             if(value && value.length > len){
13476                 return value.substr(0, len-3)+"...";
13477             }
13478             return value;
13479         },
13480
13481         /**
13482          * Checks a reference and converts it to empty string if it is undefined
13483          * @param {Mixed} value Reference to check
13484          * @return {Mixed} Empty string if converted, otherwise the original value
13485          */
13486         undef : function(value){
13487             return typeof value != "undefined" ? value : "";
13488         },
13489
13490         /**
13491          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13492          * @param {String} value The string to encode
13493          * @return {String} The encoded text
13494          */
13495         htmlEncode : function(value){
13496             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13497         },
13498
13499         /**
13500          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13501          * @param {String} value The string to decode
13502          * @return {String} The decoded text
13503          */
13504         htmlDecode : function(value){
13505             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13506         },
13507
13508         /**
13509          * Trims any whitespace from either side of a string
13510          * @param {String} value The text to trim
13511          * @return {String} The trimmed text
13512          */
13513         trim : function(value){
13514             return String(value).replace(trimRe, "");
13515         },
13516
13517         /**
13518          * Returns a substring from within an original string
13519          * @param {String} value The original text
13520          * @param {Number} start The start index of the substring
13521          * @param {Number} length The length of the substring
13522          * @return {String} The substring
13523          */
13524         substr : function(value, start, length){
13525             return String(value).substr(start, length);
13526         },
13527
13528         /**
13529          * Converts a string to all lower case letters
13530          * @param {String} value The text to convert
13531          * @return {String} The converted text
13532          */
13533         lowercase : function(value){
13534             return String(value).toLowerCase();
13535         },
13536
13537         /**
13538          * Converts a string to all upper case letters
13539          * @param {String} value The text to convert
13540          * @return {String} The converted text
13541          */
13542         uppercase : function(value){
13543             return String(value).toUpperCase();
13544         },
13545
13546         /**
13547          * Converts the first character only of a string to upper case
13548          * @param {String} value The text to convert
13549          * @return {String} The converted text
13550          */
13551         capitalize : function(value){
13552             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13553         },
13554
13555         // private
13556         call : function(value, fn){
13557             if(arguments.length > 2){
13558                 var args = Array.prototype.slice.call(arguments, 2);
13559                 args.unshift(value);
13560                  
13561                 return /** eval:var:value */  eval(fn).apply(window, args);
13562             }else{
13563                 /** eval:var:value */
13564                 return /** eval:var:value */ eval(fn).call(window, value);
13565             }
13566         },
13567
13568        
13569         /**
13570          * safer version of Math.toFixed..??/
13571          * @param {Number/String} value The numeric value to format
13572          * @param {Number/String} value Decimal places 
13573          * @return {String} The formatted currency string
13574          */
13575         toFixed : function(v, n)
13576         {
13577             // why not use to fixed - precision is buggered???
13578             if (!n) {
13579                 return Math.round(v-0);
13580             }
13581             var fact = Math.pow(10,n+1);
13582             v = (Math.round((v-0)*fact))/fact;
13583             var z = (''+fact).substring(2);
13584             if (v == Math.floor(v)) {
13585                 return Math.floor(v) + '.' + z;
13586             }
13587             
13588             // now just padd decimals..
13589             var ps = String(v).split('.');
13590             var fd = (ps[1] + z);
13591             var r = fd.substring(0,n); 
13592             var rm = fd.substring(n); 
13593             if (rm < 5) {
13594                 return ps[0] + '.' + r;
13595             }
13596             r*=1; // turn it into a number;
13597             r++;
13598             if (String(r).length != n) {
13599                 ps[0]*=1;
13600                 ps[0]++;
13601                 r = String(r).substring(1); // chop the end off.
13602             }
13603             
13604             return ps[0] + '.' + r;
13605              
13606         },
13607         
13608         /**
13609          * Format a number as US currency
13610          * @param {Number/String} value The numeric value to format
13611          * @return {String} The formatted currency string
13612          */
13613         usMoney : function(v){
13614             return '$' + Roo.util.Format.number(v);
13615         },
13616         
13617         /**
13618          * Format a number
13619          * eventually this should probably emulate php's number_format
13620          * @param {Number/String} value The numeric value to format
13621          * @param {Number} decimals number of decimal places
13622          * @return {String} The formatted currency string
13623          */
13624         number : function(v,decimals)
13625         {
13626             // multiply and round.
13627             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13628             var mul = Math.pow(10, decimals);
13629             var zero = String(mul).substring(1);
13630             v = (Math.round((v-0)*mul))/mul;
13631             
13632             // if it's '0' number.. then
13633             
13634             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13635             v = String(v);
13636             var ps = v.split('.');
13637             var whole = ps[0];
13638             
13639             
13640             var r = /(\d+)(\d{3})/;
13641             // add comma's
13642             while (r.test(whole)) {
13643                 whole = whole.replace(r, '$1' + ',' + '$2');
13644             }
13645             
13646             
13647             var sub = ps[1] ?
13648                     // has decimals..
13649                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13650                     // does not have decimals
13651                     (decimals ? ('.' + zero) : '');
13652             
13653             
13654             return whole + sub ;
13655         },
13656         
13657         /**
13658          * Parse a value into a formatted date using the specified format pattern.
13659          * @param {Mixed} value The value to format
13660          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13661          * @return {String} The formatted date string
13662          */
13663         date : function(v, format){
13664             if(!v){
13665                 return "";
13666             }
13667             if(!(v instanceof Date)){
13668                 v = new Date(Date.parse(v));
13669             }
13670             return v.dateFormat(format || Roo.util.Format.defaults.date);
13671         },
13672
13673         /**
13674          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13675          * @param {String} format Any valid date format string
13676          * @return {Function} The date formatting function
13677          */
13678         dateRenderer : function(format){
13679             return function(v){
13680                 return Roo.util.Format.date(v, format);  
13681             };
13682         },
13683
13684         // private
13685         stripTagsRE : /<\/?[^>]+>/gi,
13686         
13687         /**
13688          * Strips all HTML tags
13689          * @param {Mixed} value The text from which to strip tags
13690          * @return {String} The stripped text
13691          */
13692         stripTags : function(v){
13693             return !v ? v : String(v).replace(this.stripTagsRE, "");
13694         }
13695     };
13696 }();
13697 Roo.util.Format.defaults = {
13698     date : 'd/M/Y'
13699 };/*
13700  * Based on:
13701  * Ext JS Library 1.1.1
13702  * Copyright(c) 2006-2007, Ext JS, LLC.
13703  *
13704  * Originally Released Under LGPL - original licence link has changed is not relivant.
13705  *
13706  * Fork - LGPL
13707  * <script type="text/javascript">
13708  */
13709
13710
13711  
13712
13713 /**
13714  * @class Roo.MasterTemplate
13715  * @extends Roo.Template
13716  * Provides a template that can have child templates. The syntax is:
13717 <pre><code>
13718 var t = new Roo.MasterTemplate(
13719         '&lt;select name="{name}"&gt;',
13720                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13721         '&lt;/select&gt;'
13722 );
13723 t.add('options', {value: 'foo', text: 'bar'});
13724 // or you can add multiple child elements in one shot
13725 t.addAll('options', [
13726     {value: 'foo', text: 'bar'},
13727     {value: 'foo2', text: 'bar2'},
13728     {value: 'foo3', text: 'bar3'}
13729 ]);
13730 // then append, applying the master template values
13731 t.append('my-form', {name: 'my-select'});
13732 </code></pre>
13733 * A name attribute for the child template is not required if you have only one child
13734 * template or you want to refer to them by index.
13735  */
13736 Roo.MasterTemplate = function(){
13737     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13738     this.originalHtml = this.html;
13739     var st = {};
13740     var m, re = this.subTemplateRe;
13741     re.lastIndex = 0;
13742     var subIndex = 0;
13743     while(m = re.exec(this.html)){
13744         var name = m[1], content = m[2];
13745         st[subIndex] = {
13746             name: name,
13747             index: subIndex,
13748             buffer: [],
13749             tpl : new Roo.Template(content)
13750         };
13751         if(name){
13752             st[name] = st[subIndex];
13753         }
13754         st[subIndex].tpl.compile();
13755         st[subIndex].tpl.call = this.call.createDelegate(this);
13756         subIndex++;
13757     }
13758     this.subCount = subIndex;
13759     this.subs = st;
13760 };
13761 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13762     /**
13763     * The regular expression used to match sub templates
13764     * @type RegExp
13765     * @property
13766     */
13767     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13768
13769     /**
13770      * Applies the passed values to a child template.
13771      * @param {String/Number} name (optional) The name or index of the child template
13772      * @param {Array/Object} values The values to be applied to the template
13773      * @return {MasterTemplate} this
13774      */
13775      add : function(name, values){
13776         if(arguments.length == 1){
13777             values = arguments[0];
13778             name = 0;
13779         }
13780         var s = this.subs[name];
13781         s.buffer[s.buffer.length] = s.tpl.apply(values);
13782         return this;
13783     },
13784
13785     /**
13786      * Applies all the passed values to a child template.
13787      * @param {String/Number} name (optional) The name or index of the child template
13788      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13789      * @param {Boolean} reset (optional) True to reset the template first
13790      * @return {MasterTemplate} this
13791      */
13792     fill : function(name, values, reset){
13793         var a = arguments;
13794         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13795             values = a[0];
13796             name = 0;
13797             reset = a[1];
13798         }
13799         if(reset){
13800             this.reset();
13801         }
13802         for(var i = 0, len = values.length; i < len; i++){
13803             this.add(name, values[i]);
13804         }
13805         return this;
13806     },
13807
13808     /**
13809      * Resets the template for reuse
13810      * @return {MasterTemplate} this
13811      */
13812      reset : function(){
13813         var s = this.subs;
13814         for(var i = 0; i < this.subCount; i++){
13815             s[i].buffer = [];
13816         }
13817         return this;
13818     },
13819
13820     applyTemplate : function(values){
13821         var s = this.subs;
13822         var replaceIndex = -1;
13823         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13824             return s[++replaceIndex].buffer.join("");
13825         });
13826         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13827     },
13828
13829     apply : function(){
13830         return this.applyTemplate.apply(this, arguments);
13831     },
13832
13833     compile : function(){return this;}
13834 });
13835
13836 /**
13837  * Alias for fill().
13838  * @method
13839  */
13840 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13841  /**
13842  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13843  * var tpl = Roo.MasterTemplate.from('element-id');
13844  * @param {String/HTMLElement} el
13845  * @param {Object} config
13846  * @static
13847  */
13848 Roo.MasterTemplate.from = function(el, config){
13849     el = Roo.getDom(el);
13850     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13851 };/*
13852  * Based on:
13853  * Ext JS Library 1.1.1
13854  * Copyright(c) 2006-2007, Ext JS, LLC.
13855  *
13856  * Originally Released Under LGPL - original licence link has changed is not relivant.
13857  *
13858  * Fork - LGPL
13859  * <script type="text/javascript">
13860  */
13861
13862  
13863 /**
13864  * @class Roo.util.CSS
13865  * Utility class for manipulating CSS rules
13866  * @singleton
13867  */
13868 Roo.util.CSS = function(){
13869         var rules = null;
13870         var doc = document;
13871
13872     var camelRe = /(-[a-z])/gi;
13873     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13874
13875    return {
13876    /**
13877     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13878     * tag and appended to the HEAD of the document.
13879     * @param {String|Object} cssText The text containing the css rules
13880     * @param {String} id An id to add to the stylesheet for later removal
13881     * @return {StyleSheet}
13882     */
13883     createStyleSheet : function(cssText, id){
13884         var ss;
13885         var head = doc.getElementsByTagName("head")[0];
13886         var nrules = doc.createElement("style");
13887         nrules.setAttribute("type", "text/css");
13888         if(id){
13889             nrules.setAttribute("id", id);
13890         }
13891         if (typeof(cssText) != 'string') {
13892             // support object maps..
13893             // not sure if this a good idea.. 
13894             // perhaps it should be merged with the general css handling
13895             // and handle js style props.
13896             var cssTextNew = [];
13897             for(var n in cssText) {
13898                 var citems = [];
13899                 for(var k in cssText[n]) {
13900                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13901                 }
13902                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13903                 
13904             }
13905             cssText = cssTextNew.join("\n");
13906             
13907         }
13908        
13909        
13910        if(Roo.isIE){
13911            head.appendChild(nrules);
13912            ss = nrules.styleSheet;
13913            ss.cssText = cssText;
13914        }else{
13915            try{
13916                 nrules.appendChild(doc.createTextNode(cssText));
13917            }catch(e){
13918                nrules.cssText = cssText; 
13919            }
13920            head.appendChild(nrules);
13921            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13922        }
13923        this.cacheStyleSheet(ss);
13924        return ss;
13925    },
13926
13927    /**
13928     * Removes a style or link tag by id
13929     * @param {String} id The id of the tag
13930     */
13931    removeStyleSheet : function(id){
13932        var existing = doc.getElementById(id);
13933        if(existing){
13934            existing.parentNode.removeChild(existing);
13935        }
13936    },
13937
13938    /**
13939     * Dynamically swaps an existing stylesheet reference for a new one
13940     * @param {String} id The id of an existing link tag to remove
13941     * @param {String} url The href of the new stylesheet to include
13942     */
13943    swapStyleSheet : function(id, url){
13944        this.removeStyleSheet(id);
13945        var ss = doc.createElement("link");
13946        ss.setAttribute("rel", "stylesheet");
13947        ss.setAttribute("type", "text/css");
13948        ss.setAttribute("id", id);
13949        ss.setAttribute("href", url);
13950        doc.getElementsByTagName("head")[0].appendChild(ss);
13951    },
13952    
13953    /**
13954     * Refresh the rule cache if you have dynamically added stylesheets
13955     * @return {Object} An object (hash) of rules indexed by selector
13956     */
13957    refreshCache : function(){
13958        return this.getRules(true);
13959    },
13960
13961    // private
13962    cacheStyleSheet : function(stylesheet){
13963        if(!rules){
13964            rules = {};
13965        }
13966        try{// try catch for cross domain access issue
13967            var ssRules = stylesheet.cssRules || stylesheet.rules;
13968            for(var j = ssRules.length-1; j >= 0; --j){
13969                rules[ssRules[j].selectorText] = ssRules[j];
13970            }
13971        }catch(e){}
13972    },
13973    
13974    /**
13975     * Gets all css rules for the document
13976     * @param {Boolean} refreshCache true to refresh the internal cache
13977     * @return {Object} An object (hash) of rules indexed by selector
13978     */
13979    getRules : function(refreshCache){
13980                 if(rules == null || refreshCache){
13981                         rules = {};
13982                         var ds = doc.styleSheets;
13983                         for(var i =0, len = ds.length; i < len; i++){
13984                             try{
13985                         this.cacheStyleSheet(ds[i]);
13986                     }catch(e){} 
13987                 }
13988                 }
13989                 return rules;
13990         },
13991         
13992         /**
13993     * Gets an an individual CSS rule by selector(s)
13994     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13995     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13996     * @return {CSSRule} The CSS rule or null if one is not found
13997     */
13998    getRule : function(selector, refreshCache){
13999                 var rs = this.getRules(refreshCache);
14000                 if(!(selector instanceof Array)){
14001                     return rs[selector];
14002                 }
14003                 for(var i = 0; i < selector.length; i++){
14004                         if(rs[selector[i]]){
14005                                 return rs[selector[i]];
14006                         }
14007                 }
14008                 return null;
14009         },
14010         
14011         
14012         /**
14013     * Updates a rule property
14014     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14015     * @param {String} property The css property
14016     * @param {String} value The new value for the property
14017     * @return {Boolean} true If a rule was found and updated
14018     */
14019    updateRule : function(selector, property, value){
14020                 if(!(selector instanceof Array)){
14021                         var rule = this.getRule(selector);
14022                         if(rule){
14023                                 rule.style[property.replace(camelRe, camelFn)] = value;
14024                                 return true;
14025                         }
14026                 }else{
14027                         for(var i = 0; i < selector.length; i++){
14028                                 if(this.updateRule(selector[i], property, value)){
14029                                         return true;
14030                                 }
14031                         }
14032                 }
14033                 return false;
14034         }
14035    };   
14036 }();/*
14037  * Based on:
14038  * Ext JS Library 1.1.1
14039  * Copyright(c) 2006-2007, Ext JS, LLC.
14040  *
14041  * Originally Released Under LGPL - original licence link has changed is not relivant.
14042  *
14043  * Fork - LGPL
14044  * <script type="text/javascript">
14045  */
14046
14047  
14048
14049 /**
14050  * @class Roo.util.ClickRepeater
14051  * @extends Roo.util.Observable
14052  * 
14053  * A wrapper class which can be applied to any element. Fires a "click" event while the
14054  * mouse is pressed. The interval between firings may be specified in the config but
14055  * defaults to 10 milliseconds.
14056  * 
14057  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14058  * 
14059  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14060  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14061  * Similar to an autorepeat key delay.
14062  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14063  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14064  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14065  *           "interval" and "delay" are ignored. "immediate" is honored.
14066  * @cfg {Boolean} preventDefault True to prevent the default click event
14067  * @cfg {Boolean} stopDefault True to stop the default click event
14068  * 
14069  * @history
14070  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14071  *     2007-02-02 jvs Renamed to ClickRepeater
14072  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14073  *
14074  *  @constructor
14075  * @param {String/HTMLElement/Element} el The element to listen on
14076  * @param {Object} config
14077  **/
14078 Roo.util.ClickRepeater = function(el, config)
14079 {
14080     this.el = Roo.get(el);
14081     this.el.unselectable();
14082
14083     Roo.apply(this, config);
14084
14085     this.addEvents({
14086     /**
14087      * @event mousedown
14088      * Fires when the mouse button is depressed.
14089      * @param {Roo.util.ClickRepeater} this
14090      */
14091         "mousedown" : true,
14092     /**
14093      * @event click
14094      * Fires on a specified interval during the time the element is pressed.
14095      * @param {Roo.util.ClickRepeater} this
14096      */
14097         "click" : true,
14098     /**
14099      * @event mouseup
14100      * Fires when the mouse key is released.
14101      * @param {Roo.util.ClickRepeater} this
14102      */
14103         "mouseup" : true
14104     });
14105
14106     this.el.on("mousedown", this.handleMouseDown, this);
14107     if(this.preventDefault || this.stopDefault){
14108         this.el.on("click", function(e){
14109             if(this.preventDefault){
14110                 e.preventDefault();
14111             }
14112             if(this.stopDefault){
14113                 e.stopEvent();
14114             }
14115         }, this);
14116     }
14117
14118     // allow inline handler
14119     if(this.handler){
14120         this.on("click", this.handler,  this.scope || this);
14121     }
14122
14123     Roo.util.ClickRepeater.superclass.constructor.call(this);
14124 };
14125
14126 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14127     interval : 20,
14128     delay: 250,
14129     preventDefault : true,
14130     stopDefault : false,
14131     timer : 0,
14132
14133     // private
14134     handleMouseDown : function(){
14135         clearTimeout(this.timer);
14136         this.el.blur();
14137         if(this.pressClass){
14138             this.el.addClass(this.pressClass);
14139         }
14140         this.mousedownTime = new Date();
14141
14142         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14143         this.el.on("mouseout", this.handleMouseOut, this);
14144
14145         this.fireEvent("mousedown", this);
14146         this.fireEvent("click", this);
14147         
14148         this.timer = this.click.defer(this.delay || this.interval, this);
14149     },
14150
14151     // private
14152     click : function(){
14153         this.fireEvent("click", this);
14154         this.timer = this.click.defer(this.getInterval(), this);
14155     },
14156
14157     // private
14158     getInterval: function(){
14159         if(!this.accelerate){
14160             return this.interval;
14161         }
14162         var pressTime = this.mousedownTime.getElapsed();
14163         if(pressTime < 500){
14164             return 400;
14165         }else if(pressTime < 1700){
14166             return 320;
14167         }else if(pressTime < 2600){
14168             return 250;
14169         }else if(pressTime < 3500){
14170             return 180;
14171         }else if(pressTime < 4400){
14172             return 140;
14173         }else if(pressTime < 5300){
14174             return 80;
14175         }else if(pressTime < 6200){
14176             return 50;
14177         }else{
14178             return 10;
14179         }
14180     },
14181
14182     // private
14183     handleMouseOut : function(){
14184         clearTimeout(this.timer);
14185         if(this.pressClass){
14186             this.el.removeClass(this.pressClass);
14187         }
14188         this.el.on("mouseover", this.handleMouseReturn, this);
14189     },
14190
14191     // private
14192     handleMouseReturn : function(){
14193         this.el.un("mouseover", this.handleMouseReturn);
14194         if(this.pressClass){
14195             this.el.addClass(this.pressClass);
14196         }
14197         this.click();
14198     },
14199
14200     // private
14201     handleMouseUp : function(){
14202         clearTimeout(this.timer);
14203         this.el.un("mouseover", this.handleMouseReturn);
14204         this.el.un("mouseout", this.handleMouseOut);
14205         Roo.get(document).un("mouseup", this.handleMouseUp);
14206         this.el.removeClass(this.pressClass);
14207         this.fireEvent("mouseup", this);
14208     }
14209 });/*
14210  * Based on:
14211  * Ext JS Library 1.1.1
14212  * Copyright(c) 2006-2007, Ext JS, LLC.
14213  *
14214  * Originally Released Under LGPL - original licence link has changed is not relivant.
14215  *
14216  * Fork - LGPL
14217  * <script type="text/javascript">
14218  */
14219
14220  
14221 /**
14222  * @class Roo.KeyNav
14223  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14224  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14225  * way to implement custom navigation schemes for any UI component.</p>
14226  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14227  * pageUp, pageDown, del, home, end.  Usage:</p>
14228  <pre><code>
14229 var nav = new Roo.KeyNav("my-element", {
14230     "left" : function(e){
14231         this.moveLeft(e.ctrlKey);
14232     },
14233     "right" : function(e){
14234         this.moveRight(e.ctrlKey);
14235     },
14236     "enter" : function(e){
14237         this.save();
14238     },
14239     scope : this
14240 });
14241 </code></pre>
14242  * @constructor
14243  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14244  * @param {Object} config The config
14245  */
14246 Roo.KeyNav = function(el, config){
14247     this.el = Roo.get(el);
14248     Roo.apply(this, config);
14249     if(!this.disabled){
14250         this.disabled = true;
14251         this.enable();
14252     }
14253 };
14254
14255 Roo.KeyNav.prototype = {
14256     /**
14257      * @cfg {Boolean} disabled
14258      * True to disable this KeyNav instance (defaults to false)
14259      */
14260     disabled : false,
14261     /**
14262      * @cfg {String} defaultEventAction
14263      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14264      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14265      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14266      */
14267     defaultEventAction: "stopEvent",
14268     /**
14269      * @cfg {Boolean} forceKeyDown
14270      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14271      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14272      * handle keydown instead of keypress.
14273      */
14274     forceKeyDown : false,
14275
14276     // private
14277     prepareEvent : function(e){
14278         var k = e.getKey();
14279         var h = this.keyToHandler[k];
14280         //if(h && this[h]){
14281         //    e.stopPropagation();
14282         //}
14283         if(Roo.isSafari && h && k >= 37 && k <= 40){
14284             e.stopEvent();
14285         }
14286     },
14287
14288     // private
14289     relay : function(e){
14290         var k = e.getKey();
14291         var h = this.keyToHandler[k];
14292         if(h && this[h]){
14293             if(this.doRelay(e, this[h], h) !== true){
14294                 e[this.defaultEventAction]();
14295             }
14296         }
14297     },
14298
14299     // private
14300     doRelay : function(e, h, hname){
14301         return h.call(this.scope || this, e);
14302     },
14303
14304     // possible handlers
14305     enter : false,
14306     left : false,
14307     right : false,
14308     up : false,
14309     down : false,
14310     tab : false,
14311     esc : false,
14312     pageUp : false,
14313     pageDown : false,
14314     del : false,
14315     home : false,
14316     end : false,
14317
14318     // quick lookup hash
14319     keyToHandler : {
14320         37 : "left",
14321         39 : "right",
14322         38 : "up",
14323         40 : "down",
14324         33 : "pageUp",
14325         34 : "pageDown",
14326         46 : "del",
14327         36 : "home",
14328         35 : "end",
14329         13 : "enter",
14330         27 : "esc",
14331         9  : "tab"
14332     },
14333
14334         /**
14335          * Enable this KeyNav
14336          */
14337         enable: function(){
14338                 if(this.disabled){
14339             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14340             // the EventObject will normalize Safari automatically
14341             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14342                 this.el.on("keydown", this.relay,  this);
14343             }else{
14344                 this.el.on("keydown", this.prepareEvent,  this);
14345                 this.el.on("keypress", this.relay,  this);
14346             }
14347                     this.disabled = false;
14348                 }
14349         },
14350
14351         /**
14352          * Disable this KeyNav
14353          */
14354         disable: function(){
14355                 if(!this.disabled){
14356                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14357                 this.el.un("keydown", this.relay);
14358             }else{
14359                 this.el.un("keydown", this.prepareEvent);
14360                 this.el.un("keypress", this.relay);
14361             }
14362                     this.disabled = true;
14363                 }
14364         }
14365 };/*
14366  * Based on:
14367  * Ext JS Library 1.1.1
14368  * Copyright(c) 2006-2007, Ext JS, LLC.
14369  *
14370  * Originally Released Under LGPL - original licence link has changed is not relivant.
14371  *
14372  * Fork - LGPL
14373  * <script type="text/javascript">
14374  */
14375
14376  
14377 /**
14378  * @class Roo.KeyMap
14379  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14380  * The constructor accepts the same config object as defined by {@link #addBinding}.
14381  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14382  * combination it will call the function with this signature (if the match is a multi-key
14383  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14384  * A KeyMap can also handle a string representation of keys.<br />
14385  * Usage:
14386  <pre><code>
14387 // map one key by key code
14388 var map = new Roo.KeyMap("my-element", {
14389     key: 13, // or Roo.EventObject.ENTER
14390     fn: myHandler,
14391     scope: myObject
14392 });
14393
14394 // map multiple keys to one action by string
14395 var map = new Roo.KeyMap("my-element", {
14396     key: "a\r\n\t",
14397     fn: myHandler,
14398     scope: myObject
14399 });
14400
14401 // map multiple keys to multiple actions by strings and array of codes
14402 var map = new Roo.KeyMap("my-element", [
14403     {
14404         key: [10,13],
14405         fn: function(){ alert("Return was pressed"); }
14406     }, {
14407         key: "abc",
14408         fn: function(){ alert('a, b or c was pressed'); }
14409     }, {
14410         key: "\t",
14411         ctrl:true,
14412         shift:true,
14413         fn: function(){ alert('Control + shift + tab was pressed.'); }
14414     }
14415 ]);
14416 </code></pre>
14417  * <b>Note: A KeyMap starts enabled</b>
14418  * @constructor
14419  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14420  * @param {Object} config The config (see {@link #addBinding})
14421  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14422  */
14423 Roo.KeyMap = function(el, config, eventName){
14424     this.el  = Roo.get(el);
14425     this.eventName = eventName || "keydown";
14426     this.bindings = [];
14427     if(config){
14428         this.addBinding(config);
14429     }
14430     this.enable();
14431 };
14432
14433 Roo.KeyMap.prototype = {
14434     /**
14435      * True to stop the event from bubbling and prevent the default browser action if the
14436      * key was handled by the KeyMap (defaults to false)
14437      * @type Boolean
14438      */
14439     stopEvent : false,
14440
14441     /**
14442      * Add a new binding to this KeyMap. The following config object properties are supported:
14443      * <pre>
14444 Property    Type             Description
14445 ----------  ---------------  ----------------------------------------------------------------------
14446 key         String/Array     A single keycode or an array of keycodes to handle
14447 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14448 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14449 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14450 fn          Function         The function to call when KeyMap finds the expected key combination
14451 scope       Object           The scope of the callback function
14452 </pre>
14453      *
14454      * Usage:
14455      * <pre><code>
14456 // Create a KeyMap
14457 var map = new Roo.KeyMap(document, {
14458     key: Roo.EventObject.ENTER,
14459     fn: handleKey,
14460     scope: this
14461 });
14462
14463 //Add a new binding to the existing KeyMap later
14464 map.addBinding({
14465     key: 'abc',
14466     shift: true,
14467     fn: handleKey,
14468     scope: this
14469 });
14470 </code></pre>
14471      * @param {Object/Array} config A single KeyMap config or an array of configs
14472      */
14473         addBinding : function(config){
14474         if(config instanceof Array){
14475             for(var i = 0, len = config.length; i < len; i++){
14476                 this.addBinding(config[i]);
14477             }
14478             return;
14479         }
14480         var keyCode = config.key,
14481             shift = config.shift, 
14482             ctrl = config.ctrl, 
14483             alt = config.alt,
14484             fn = config.fn,
14485             scope = config.scope;
14486         if(typeof keyCode == "string"){
14487             var ks = [];
14488             var keyString = keyCode.toUpperCase();
14489             for(var j = 0, len = keyString.length; j < len; j++){
14490                 ks.push(keyString.charCodeAt(j));
14491             }
14492             keyCode = ks;
14493         }
14494         var keyArray = keyCode instanceof Array;
14495         var handler = function(e){
14496             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14497                 var k = e.getKey();
14498                 if(keyArray){
14499                     for(var i = 0, len = keyCode.length; i < len; i++){
14500                         if(keyCode[i] == k){
14501                           if(this.stopEvent){
14502                               e.stopEvent();
14503                           }
14504                           fn.call(scope || window, k, e);
14505                           return;
14506                         }
14507                     }
14508                 }else{
14509                     if(k == keyCode){
14510                         if(this.stopEvent){
14511                            e.stopEvent();
14512                         }
14513                         fn.call(scope || window, k, e);
14514                     }
14515                 }
14516             }
14517         };
14518         this.bindings.push(handler);  
14519         },
14520
14521     /**
14522      * Shorthand for adding a single key listener
14523      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14524      * following options:
14525      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14526      * @param {Function} fn The function to call
14527      * @param {Object} scope (optional) The scope of the function
14528      */
14529     on : function(key, fn, scope){
14530         var keyCode, shift, ctrl, alt;
14531         if(typeof key == "object" && !(key instanceof Array)){
14532             keyCode = key.key;
14533             shift = key.shift;
14534             ctrl = key.ctrl;
14535             alt = key.alt;
14536         }else{
14537             keyCode = key;
14538         }
14539         this.addBinding({
14540             key: keyCode,
14541             shift: shift,
14542             ctrl: ctrl,
14543             alt: alt,
14544             fn: fn,
14545             scope: scope
14546         })
14547     },
14548
14549     // private
14550     handleKeyDown : function(e){
14551             if(this.enabled){ //just in case
14552             var b = this.bindings;
14553             for(var i = 0, len = b.length; i < len; i++){
14554                 b[i].call(this, e);
14555             }
14556             }
14557         },
14558         
14559         /**
14560          * Returns true if this KeyMap is enabled
14561          * @return {Boolean} 
14562          */
14563         isEnabled : function(){
14564             return this.enabled;  
14565         },
14566         
14567         /**
14568          * Enables this KeyMap
14569          */
14570         enable: function(){
14571                 if(!this.enabled){
14572                     this.el.on(this.eventName, this.handleKeyDown, this);
14573                     this.enabled = true;
14574                 }
14575         },
14576
14577         /**
14578          * Disable this KeyMap
14579          */
14580         disable: function(){
14581                 if(this.enabled){
14582                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14583                     this.enabled = false;
14584                 }
14585         }
14586 };/*
14587  * Based on:
14588  * Ext JS Library 1.1.1
14589  * Copyright(c) 2006-2007, Ext JS, LLC.
14590  *
14591  * Originally Released Under LGPL - original licence link has changed is not relivant.
14592  *
14593  * Fork - LGPL
14594  * <script type="text/javascript">
14595  */
14596
14597  
14598 /**
14599  * @class Roo.util.TextMetrics
14600  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14601  * wide, in pixels, a given block of text will be.
14602  * @singleton
14603  */
14604 Roo.util.TextMetrics = function(){
14605     var shared;
14606     return {
14607         /**
14608          * Measures the size of the specified text
14609          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14610          * that can affect the size of the rendered text
14611          * @param {String} text The text to measure
14612          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14613          * in order to accurately measure the text height
14614          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14615          */
14616         measure : function(el, text, fixedWidth){
14617             if(!shared){
14618                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14619             }
14620             shared.bind(el);
14621             shared.setFixedWidth(fixedWidth || 'auto');
14622             return shared.getSize(text);
14623         },
14624
14625         /**
14626          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14627          * the overhead of multiple calls to initialize the style properties on each measurement.
14628          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14629          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14630          * in order to accurately measure the text height
14631          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14632          */
14633         createInstance : function(el, fixedWidth){
14634             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14635         }
14636     };
14637 }();
14638
14639  
14640
14641 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14642     var ml = new Roo.Element(document.createElement('div'));
14643     document.body.appendChild(ml.dom);
14644     ml.position('absolute');
14645     ml.setLeftTop(-1000, -1000);
14646     ml.hide();
14647
14648     if(fixedWidth){
14649         ml.setWidth(fixedWidth);
14650     }
14651      
14652     var instance = {
14653         /**
14654          * Returns the size of the specified text based on the internal element's style and width properties
14655          * @memberOf Roo.util.TextMetrics.Instance#
14656          * @param {String} text The text to measure
14657          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14658          */
14659         getSize : function(text){
14660             ml.update(text);
14661             var s = ml.getSize();
14662             ml.update('');
14663             return s;
14664         },
14665
14666         /**
14667          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14668          * that can affect the size of the rendered text
14669          * @memberOf Roo.util.TextMetrics.Instance#
14670          * @param {String/HTMLElement} el The element, dom node or id
14671          */
14672         bind : function(el){
14673             ml.setStyle(
14674                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14675             );
14676         },
14677
14678         /**
14679          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14680          * to set a fixed width in order to accurately measure the text height.
14681          * @memberOf Roo.util.TextMetrics.Instance#
14682          * @param {Number} width The width to set on the element
14683          */
14684         setFixedWidth : function(width){
14685             ml.setWidth(width);
14686         },
14687
14688         /**
14689          * Returns the measured width of the specified text
14690          * @memberOf Roo.util.TextMetrics.Instance#
14691          * @param {String} text The text to measure
14692          * @return {Number} width The width in pixels
14693          */
14694         getWidth : function(text){
14695             ml.dom.style.width = 'auto';
14696             return this.getSize(text).width;
14697         },
14698
14699         /**
14700          * Returns the measured height of the specified text.  For multiline text, be sure to call
14701          * {@link #setFixedWidth} if necessary.
14702          * @memberOf Roo.util.TextMetrics.Instance#
14703          * @param {String} text The text to measure
14704          * @return {Number} height The height in pixels
14705          */
14706         getHeight : function(text){
14707             return this.getSize(text).height;
14708         }
14709     };
14710
14711     instance.bind(bindTo);
14712
14713     return instance;
14714 };
14715
14716 // backwards compat
14717 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14718  * Based on:
14719  * Ext JS Library 1.1.1
14720  * Copyright(c) 2006-2007, Ext JS, LLC.
14721  *
14722  * Originally Released Under LGPL - original licence link has changed is not relivant.
14723  *
14724  * Fork - LGPL
14725  * <script type="text/javascript">
14726  */
14727
14728 /**
14729  * @class Roo.state.Provider
14730  * Abstract base class for state provider implementations. This class provides methods
14731  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14732  * Provider interface.
14733  */
14734 Roo.state.Provider = function(){
14735     /**
14736      * @event statechange
14737      * Fires when a state change occurs.
14738      * @param {Provider} this This state provider
14739      * @param {String} key The state key which was changed
14740      * @param {String} value The encoded value for the state
14741      */
14742     this.addEvents({
14743         "statechange": true
14744     });
14745     this.state = {};
14746     Roo.state.Provider.superclass.constructor.call(this);
14747 };
14748 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14749     /**
14750      * Returns the current value for a key
14751      * @param {String} name The key name
14752      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14753      * @return {Mixed} The state data
14754      */
14755     get : function(name, defaultValue){
14756         return typeof this.state[name] == "undefined" ?
14757             defaultValue : this.state[name];
14758     },
14759     
14760     /**
14761      * Clears a value from the state
14762      * @param {String} name The key name
14763      */
14764     clear : function(name){
14765         delete this.state[name];
14766         this.fireEvent("statechange", this, name, null);
14767     },
14768     
14769     /**
14770      * Sets the value for a key
14771      * @param {String} name The key name
14772      * @param {Mixed} value The value to set
14773      */
14774     set : function(name, value){
14775         this.state[name] = value;
14776         this.fireEvent("statechange", this, name, value);
14777     },
14778     
14779     /**
14780      * Decodes a string previously encoded with {@link #encodeValue}.
14781      * @param {String} value The value to decode
14782      * @return {Mixed} The decoded value
14783      */
14784     decodeValue : function(cookie){
14785         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14786         var matches = re.exec(unescape(cookie));
14787         if(!matches || !matches[1]) return; // non state cookie
14788         var type = matches[1];
14789         var v = matches[2];
14790         switch(type){
14791             case "n":
14792                 return parseFloat(v);
14793             case "d":
14794                 return new Date(Date.parse(v));
14795             case "b":
14796                 return (v == "1");
14797             case "a":
14798                 var all = [];
14799                 var values = v.split("^");
14800                 for(var i = 0, len = values.length; i < len; i++){
14801                     all.push(this.decodeValue(values[i]));
14802                 }
14803                 return all;
14804            case "o":
14805                 var all = {};
14806                 var values = v.split("^");
14807                 for(var i = 0, len = values.length; i < len; i++){
14808                     var kv = values[i].split("=");
14809                     all[kv[0]] = this.decodeValue(kv[1]);
14810                 }
14811                 return all;
14812            default:
14813                 return v;
14814         }
14815     },
14816     
14817     /**
14818      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14819      * @param {Mixed} value The value to encode
14820      * @return {String} The encoded value
14821      */
14822     encodeValue : function(v){
14823         var enc;
14824         if(typeof v == "number"){
14825             enc = "n:" + v;
14826         }else if(typeof v == "boolean"){
14827             enc = "b:" + (v ? "1" : "0");
14828         }else if(v instanceof Date){
14829             enc = "d:" + v.toGMTString();
14830         }else if(v instanceof Array){
14831             var flat = "";
14832             for(var i = 0, len = v.length; i < len; i++){
14833                 flat += this.encodeValue(v[i]);
14834                 if(i != len-1) flat += "^";
14835             }
14836             enc = "a:" + flat;
14837         }else if(typeof v == "object"){
14838             var flat = "";
14839             for(var key in v){
14840                 if(typeof v[key] != "function"){
14841                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14842                 }
14843             }
14844             enc = "o:" + flat.substring(0, flat.length-1);
14845         }else{
14846             enc = "s:" + v;
14847         }
14848         return escape(enc);        
14849     }
14850 });
14851
14852 /*
14853  * Based on:
14854  * Ext JS Library 1.1.1
14855  * Copyright(c) 2006-2007, Ext JS, LLC.
14856  *
14857  * Originally Released Under LGPL - original licence link has changed is not relivant.
14858  *
14859  * Fork - LGPL
14860  * <script type="text/javascript">
14861  */
14862 /**
14863  * @class Roo.state.Manager
14864  * This is the global state manager. By default all components that are "state aware" check this class
14865  * for state information if you don't pass them a custom state provider. In order for this class
14866  * to be useful, it must be initialized with a provider when your application initializes.
14867  <pre><code>
14868 // in your initialization function
14869 init : function(){
14870    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14871    ...
14872    // supposed you have a {@link Roo.BorderLayout}
14873    var layout = new Roo.BorderLayout(...);
14874    layout.restoreState();
14875    // or a {Roo.BasicDialog}
14876    var dialog = new Roo.BasicDialog(...);
14877    dialog.restoreState();
14878  </code></pre>
14879  * @singleton
14880  */
14881 Roo.state.Manager = function(){
14882     var provider = new Roo.state.Provider();
14883     
14884     return {
14885         /**
14886          * Configures the default state provider for your application
14887          * @param {Provider} stateProvider The state provider to set
14888          */
14889         setProvider : function(stateProvider){
14890             provider = stateProvider;
14891         },
14892         
14893         /**
14894          * Returns the current value for a key
14895          * @param {String} name The key name
14896          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14897          * @return {Mixed} The state data
14898          */
14899         get : function(key, defaultValue){
14900             return provider.get(key, defaultValue);
14901         },
14902         
14903         /**
14904          * Sets the value for a key
14905          * @param {String} name The key name
14906          * @param {Mixed} value The state data
14907          */
14908          set : function(key, value){
14909             provider.set(key, value);
14910         },
14911         
14912         /**
14913          * Clears a value from the state
14914          * @param {String} name The key name
14915          */
14916         clear : function(key){
14917             provider.clear(key);
14918         },
14919         
14920         /**
14921          * Gets the currently configured state provider
14922          * @return {Provider} The state provider
14923          */
14924         getProvider : function(){
14925             return provider;
14926         }
14927     };
14928 }();
14929 /*
14930  * Based on:
14931  * Ext JS Library 1.1.1
14932  * Copyright(c) 2006-2007, Ext JS, LLC.
14933  *
14934  * Originally Released Under LGPL - original licence link has changed is not relivant.
14935  *
14936  * Fork - LGPL
14937  * <script type="text/javascript">
14938  */
14939 /**
14940  * @class Roo.state.CookieProvider
14941  * @extends Roo.state.Provider
14942  * The default Provider implementation which saves state via cookies.
14943  * <br />Usage:
14944  <pre><code>
14945    var cp = new Roo.state.CookieProvider({
14946        path: "/cgi-bin/",
14947        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14948        domain: "roojs.com"
14949    })
14950    Roo.state.Manager.setProvider(cp);
14951  </code></pre>
14952  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14953  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14954  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14955  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14956  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14957  * domain the page is running on including the 'www' like 'www.roojs.com')
14958  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14959  * @constructor
14960  * Create a new CookieProvider
14961  * @param {Object} config The configuration object
14962  */
14963 Roo.state.CookieProvider = function(config){
14964     Roo.state.CookieProvider.superclass.constructor.call(this);
14965     this.path = "/";
14966     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14967     this.domain = null;
14968     this.secure = false;
14969     Roo.apply(this, config);
14970     this.state = this.readCookies();
14971 };
14972
14973 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14974     // private
14975     set : function(name, value){
14976         if(typeof value == "undefined" || value === null){
14977             this.clear(name);
14978             return;
14979         }
14980         this.setCookie(name, value);
14981         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14982     },
14983
14984     // private
14985     clear : function(name){
14986         this.clearCookie(name);
14987         Roo.state.CookieProvider.superclass.clear.call(this, name);
14988     },
14989
14990     // private
14991     readCookies : function(){
14992         var cookies = {};
14993         var c = document.cookie + ";";
14994         var re = /\s?(.*?)=(.*?);/g;
14995         var matches;
14996         while((matches = re.exec(c)) != null){
14997             var name = matches[1];
14998             var value = matches[2];
14999             if(name && name.substring(0,3) == "ys-"){
15000                 cookies[name.substr(3)] = this.decodeValue(value);
15001             }
15002         }
15003         return cookies;
15004     },
15005
15006     // private
15007     setCookie : function(name, value){
15008         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15009            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15010            ((this.path == null) ? "" : ("; path=" + this.path)) +
15011            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15012            ((this.secure == true) ? "; secure" : "");
15013     },
15014
15015     // private
15016     clearCookie : function(name){
15017         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15018            ((this.path == null) ? "" : ("; path=" + this.path)) +
15019            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15020            ((this.secure == true) ? "; secure" : "");
15021     }
15022 });/*
15023  * Based on:
15024  * Ext JS Library 1.1.1
15025  * Copyright(c) 2006-2007, Ext JS, LLC.
15026  *
15027  * Originally Released Under LGPL - original licence link has changed is not relivant.
15028  *
15029  * Fork - LGPL
15030  * <script type="text/javascript">
15031  */
15032  
15033
15034 /**
15035  * @class Roo.ComponentMgr
15036  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15037  * @singleton
15038  */
15039 Roo.ComponentMgr = function(){
15040     var all = new Roo.util.MixedCollection();
15041
15042     return {
15043         /**
15044          * Registers a component.
15045          * @param {Roo.Component} c The component
15046          */
15047         register : function(c){
15048             all.add(c);
15049         },
15050
15051         /**
15052          * Unregisters a component.
15053          * @param {Roo.Component} c The component
15054          */
15055         unregister : function(c){
15056             all.remove(c);
15057         },
15058
15059         /**
15060          * Returns a component by id
15061          * @param {String} id The component id
15062          */
15063         get : function(id){
15064             return all.get(id);
15065         },
15066
15067         /**
15068          * Registers a function that will be called when a specified component is added to ComponentMgr
15069          * @param {String} id The component id
15070          * @param {Funtction} fn The callback function
15071          * @param {Object} scope The scope of the callback
15072          */
15073         onAvailable : function(id, fn, scope){
15074             all.on("add", function(index, o){
15075                 if(o.id == id){
15076                     fn.call(scope || o, o);
15077                     all.un("add", fn, scope);
15078                 }
15079             });
15080         }
15081     };
15082 }();/*
15083  * Based on:
15084  * Ext JS Library 1.1.1
15085  * Copyright(c) 2006-2007, Ext JS, LLC.
15086  *
15087  * Originally Released Under LGPL - original licence link has changed is not relivant.
15088  *
15089  * Fork - LGPL
15090  * <script type="text/javascript">
15091  */
15092  
15093 /**
15094  * @class Roo.Component
15095  * @extends Roo.util.Observable
15096  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15097  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15098  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15099  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15100  * All visual components (widgets) that require rendering into a layout should subclass Component.
15101  * @constructor
15102  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15103  * 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
15104  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15105  */
15106 Roo.Component = function(config){
15107     config = config || {};
15108     if(config.tagName || config.dom || typeof config == "string"){ // element object
15109         config = {el: config, id: config.id || config};
15110     }
15111     this.initialConfig = config;
15112
15113     Roo.apply(this, config);
15114     this.addEvents({
15115         /**
15116          * @event disable
15117          * Fires after the component is disabled.
15118              * @param {Roo.Component} this
15119              */
15120         disable : true,
15121         /**
15122          * @event enable
15123          * Fires after the component is enabled.
15124              * @param {Roo.Component} this
15125              */
15126         enable : true,
15127         /**
15128          * @event beforeshow
15129          * Fires before the component is shown.  Return false to stop the show.
15130              * @param {Roo.Component} this
15131              */
15132         beforeshow : true,
15133         /**
15134          * @event show
15135          * Fires after the component is shown.
15136              * @param {Roo.Component} this
15137              */
15138         show : true,
15139         /**
15140          * @event beforehide
15141          * Fires before the component is hidden. Return false to stop the hide.
15142              * @param {Roo.Component} this
15143              */
15144         beforehide : true,
15145         /**
15146          * @event hide
15147          * Fires after the component is hidden.
15148              * @param {Roo.Component} this
15149              */
15150         hide : true,
15151         /**
15152          * @event beforerender
15153          * Fires before the component is rendered. Return false to stop the render.
15154              * @param {Roo.Component} this
15155              */
15156         beforerender : true,
15157         /**
15158          * @event render
15159          * Fires after the component is rendered.
15160              * @param {Roo.Component} this
15161              */
15162         render : true,
15163         /**
15164          * @event beforedestroy
15165          * Fires before the component is destroyed. Return false to stop the destroy.
15166              * @param {Roo.Component} this
15167              */
15168         beforedestroy : true,
15169         /**
15170          * @event destroy
15171          * Fires after the component is destroyed.
15172              * @param {Roo.Component} this
15173              */
15174         destroy : true
15175     });
15176     if(!this.id){
15177         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15178     }
15179     Roo.ComponentMgr.register(this);
15180     Roo.Component.superclass.constructor.call(this);
15181     this.initComponent();
15182     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15183         this.render(this.renderTo);
15184         delete this.renderTo;
15185     }
15186 };
15187
15188 /** @private */
15189 Roo.Component.AUTO_ID = 1000;
15190
15191 Roo.extend(Roo.Component, Roo.util.Observable, {
15192     /**
15193      * @scope Roo.Component.prototype
15194      * @type {Boolean}
15195      * true if this component is hidden. Read-only.
15196      */
15197     hidden : false,
15198     /**
15199      * @type {Boolean}
15200      * true if this component is disabled. Read-only.
15201      */
15202     disabled : false,
15203     /**
15204      * @type {Boolean}
15205      * true if this component has been rendered. Read-only.
15206      */
15207     rendered : false,
15208     
15209     /** @cfg {String} disableClass
15210      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15211      */
15212     disabledClass : "x-item-disabled",
15213         /** @cfg {Boolean} allowDomMove
15214          * Whether the component can move the Dom node when rendering (defaults to true).
15215          */
15216     allowDomMove : true,
15217     /** @cfg {String} hideMode (display|visibility)
15218      * How this component should hidden. Supported values are
15219      * "visibility" (css visibility), "offsets" (negative offset position) and
15220      * "display" (css display) - defaults to "display".
15221      */
15222     hideMode: 'display',
15223
15224     /** @private */
15225     ctype : "Roo.Component",
15226
15227     /**
15228      * @cfg {String} actionMode 
15229      * which property holds the element that used for  hide() / show() / disable() / enable()
15230      * default is 'el' 
15231      */
15232     actionMode : "el",
15233
15234     /** @private */
15235     getActionEl : function(){
15236         return this[this.actionMode];
15237     },
15238
15239     initComponent : Roo.emptyFn,
15240     /**
15241      * If this is a lazy rendering component, render it to its container element.
15242      * @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.
15243      */
15244     render : function(container, position){
15245         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15246             if(!container && this.el){
15247                 this.el = Roo.get(this.el);
15248                 container = this.el.dom.parentNode;
15249                 this.allowDomMove = false;
15250             }
15251             this.container = Roo.get(container);
15252             this.rendered = true;
15253             if(position !== undefined){
15254                 if(typeof position == 'number'){
15255                     position = this.container.dom.childNodes[position];
15256                 }else{
15257                     position = Roo.getDom(position);
15258                 }
15259             }
15260             this.onRender(this.container, position || null);
15261             if(this.cls){
15262                 this.el.addClass(this.cls);
15263                 delete this.cls;
15264             }
15265             if(this.style){
15266                 this.el.applyStyles(this.style);
15267                 delete this.style;
15268             }
15269             this.fireEvent("render", this);
15270             this.afterRender(this.container);
15271             if(this.hidden){
15272                 this.hide();
15273             }
15274             if(this.disabled){
15275                 this.disable();
15276             }
15277         }
15278         return this;
15279     },
15280
15281     /** @private */
15282     // default function is not really useful
15283     onRender : function(ct, position){
15284         if(this.el){
15285             this.el = Roo.get(this.el);
15286             if(this.allowDomMove !== false){
15287                 ct.dom.insertBefore(this.el.dom, position);
15288             }
15289         }
15290     },
15291
15292     /** @private */
15293     getAutoCreate : function(){
15294         var cfg = typeof this.autoCreate == "object" ?
15295                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15296         if(this.id && !cfg.id){
15297             cfg.id = this.id;
15298         }
15299         return cfg;
15300     },
15301
15302     /** @private */
15303     afterRender : Roo.emptyFn,
15304
15305     /**
15306      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15307      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15308      */
15309     destroy : function(){
15310         if(this.fireEvent("beforedestroy", this) !== false){
15311             this.purgeListeners();
15312             this.beforeDestroy();
15313             if(this.rendered){
15314                 this.el.removeAllListeners();
15315                 this.el.remove();
15316                 if(this.actionMode == "container"){
15317                     this.container.remove();
15318                 }
15319             }
15320             this.onDestroy();
15321             Roo.ComponentMgr.unregister(this);
15322             this.fireEvent("destroy", this);
15323         }
15324     },
15325
15326         /** @private */
15327     beforeDestroy : function(){
15328
15329     },
15330
15331         /** @private */
15332         onDestroy : function(){
15333
15334     },
15335
15336     /**
15337      * Returns the underlying {@link Roo.Element}.
15338      * @return {Roo.Element} The element
15339      */
15340     getEl : function(){
15341         return this.el;
15342     },
15343
15344     /**
15345      * Returns the id of this component.
15346      * @return {String}
15347      */
15348     getId : function(){
15349         return this.id;
15350     },
15351
15352     /**
15353      * Try to focus this component.
15354      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15355      * @return {Roo.Component} this
15356      */
15357     focus : function(selectText){
15358         if(this.rendered){
15359             this.el.focus();
15360             if(selectText === true){
15361                 this.el.dom.select();
15362             }
15363         }
15364         return this;
15365     },
15366
15367     /** @private */
15368     blur : function(){
15369         if(this.rendered){
15370             this.el.blur();
15371         }
15372         return this;
15373     },
15374
15375     /**
15376      * Disable this component.
15377      * @return {Roo.Component} this
15378      */
15379     disable : function(){
15380         if(this.rendered){
15381             this.onDisable();
15382         }
15383         this.disabled = true;
15384         this.fireEvent("disable", this);
15385         return this;
15386     },
15387
15388         // private
15389     onDisable : function(){
15390         this.getActionEl().addClass(this.disabledClass);
15391         this.el.dom.disabled = true;
15392     },
15393
15394     /**
15395      * Enable this component.
15396      * @return {Roo.Component} this
15397      */
15398     enable : function(){
15399         if(this.rendered){
15400             this.onEnable();
15401         }
15402         this.disabled = false;
15403         this.fireEvent("enable", this);
15404         return this;
15405     },
15406
15407         // private
15408     onEnable : function(){
15409         this.getActionEl().removeClass(this.disabledClass);
15410         this.el.dom.disabled = false;
15411     },
15412
15413     /**
15414      * Convenience function for setting disabled/enabled by boolean.
15415      * @param {Boolean} disabled
15416      */
15417     setDisabled : function(disabled){
15418         this[disabled ? "disable" : "enable"]();
15419     },
15420
15421     /**
15422      * Show this component.
15423      * @return {Roo.Component} this
15424      */
15425     show: function(){
15426         if(this.fireEvent("beforeshow", this) !== false){
15427             this.hidden = false;
15428             if(this.rendered){
15429                 this.onShow();
15430             }
15431             this.fireEvent("show", this);
15432         }
15433         return this;
15434     },
15435
15436     // private
15437     onShow : function(){
15438         var ae = this.getActionEl();
15439         if(this.hideMode == 'visibility'){
15440             ae.dom.style.visibility = "visible";
15441         }else if(this.hideMode == 'offsets'){
15442             ae.removeClass('x-hidden');
15443         }else{
15444             ae.dom.style.display = "";
15445         }
15446     },
15447
15448     /**
15449      * Hide this component.
15450      * @return {Roo.Component} this
15451      */
15452     hide: function(){
15453         if(this.fireEvent("beforehide", this) !== false){
15454             this.hidden = true;
15455             if(this.rendered){
15456                 this.onHide();
15457             }
15458             this.fireEvent("hide", this);
15459         }
15460         return this;
15461     },
15462
15463     // private
15464     onHide : function(){
15465         var ae = this.getActionEl();
15466         if(this.hideMode == 'visibility'){
15467             ae.dom.style.visibility = "hidden";
15468         }else if(this.hideMode == 'offsets'){
15469             ae.addClass('x-hidden');
15470         }else{
15471             ae.dom.style.display = "none";
15472         }
15473     },
15474
15475     /**
15476      * Convenience function to hide or show this component by boolean.
15477      * @param {Boolean} visible True to show, false to hide
15478      * @return {Roo.Component} this
15479      */
15480     setVisible: function(visible){
15481         if(visible) {
15482             this.show();
15483         }else{
15484             this.hide();
15485         }
15486         return this;
15487     },
15488
15489     /**
15490      * Returns true if this component is visible.
15491      */
15492     isVisible : function(){
15493         return this.getActionEl().isVisible();
15494     },
15495
15496     cloneConfig : function(overrides){
15497         overrides = overrides || {};
15498         var id = overrides.id || Roo.id();
15499         var cfg = Roo.applyIf(overrides, this.initialConfig);
15500         cfg.id = id; // prevent dup id
15501         return new this.constructor(cfg);
15502     }
15503 });/*
15504  * Based on:
15505  * Ext JS Library 1.1.1
15506  * Copyright(c) 2006-2007, Ext JS, LLC.
15507  *
15508  * Originally Released Under LGPL - original licence link has changed is not relivant.
15509  *
15510  * Fork - LGPL
15511  * <script type="text/javascript">
15512  */
15513
15514 /**
15515  * @class Roo.BoxComponent
15516  * @extends Roo.Component
15517  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15518  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15519  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15520  * layout containers.
15521  * @constructor
15522  * @param {Roo.Element/String/Object} config The configuration options.
15523  */
15524 Roo.BoxComponent = function(config){
15525     Roo.Component.call(this, config);
15526     this.addEvents({
15527         /**
15528          * @event resize
15529          * Fires after the component is resized.
15530              * @param {Roo.Component} this
15531              * @param {Number} adjWidth The box-adjusted width that was set
15532              * @param {Number} adjHeight The box-adjusted height that was set
15533              * @param {Number} rawWidth The width that was originally specified
15534              * @param {Number} rawHeight The height that was originally specified
15535              */
15536         resize : true,
15537         /**
15538          * @event move
15539          * Fires after the component is moved.
15540              * @param {Roo.Component} this
15541              * @param {Number} x The new x position
15542              * @param {Number} y The new y position
15543              */
15544         move : true
15545     });
15546 };
15547
15548 Roo.extend(Roo.BoxComponent, Roo.Component, {
15549     // private, set in afterRender to signify that the component has been rendered
15550     boxReady : false,
15551     // private, used to defer height settings to subclasses
15552     deferHeight: false,
15553     /** @cfg {Number} width
15554      * width (optional) size of component
15555      */
15556      /** @cfg {Number} height
15557      * height (optional) size of component
15558      */
15559      
15560     /**
15561      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15562      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15563      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15564      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15565      * @return {Roo.BoxComponent} this
15566      */
15567     setSize : function(w, h){
15568         // support for standard size objects
15569         if(typeof w == 'object'){
15570             h = w.height;
15571             w = w.width;
15572         }
15573         // not rendered
15574         if(!this.boxReady){
15575             this.width = w;
15576             this.height = h;
15577             return this;
15578         }
15579
15580         // prevent recalcs when not needed
15581         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15582             return this;
15583         }
15584         this.lastSize = {width: w, height: h};
15585
15586         var adj = this.adjustSize(w, h);
15587         var aw = adj.width, ah = adj.height;
15588         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15589             var rz = this.getResizeEl();
15590             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15591                 rz.setSize(aw, ah);
15592             }else if(!this.deferHeight && ah !== undefined){
15593                 rz.setHeight(ah);
15594             }else if(aw !== undefined){
15595                 rz.setWidth(aw);
15596             }
15597             this.onResize(aw, ah, w, h);
15598             this.fireEvent('resize', this, aw, ah, w, h);
15599         }
15600         return this;
15601     },
15602
15603     /**
15604      * Gets the current size of the component's underlying element.
15605      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15606      */
15607     getSize : function(){
15608         return this.el.getSize();
15609     },
15610
15611     /**
15612      * Gets the current XY position of the component's underlying element.
15613      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15614      * @return {Array} The XY position of the element (e.g., [100, 200])
15615      */
15616     getPosition : function(local){
15617         if(local === true){
15618             return [this.el.getLeft(true), this.el.getTop(true)];
15619         }
15620         return this.xy || this.el.getXY();
15621     },
15622
15623     /**
15624      * Gets the current box measurements of the component's underlying element.
15625      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15626      * @returns {Object} box An object in the format {x, y, width, height}
15627      */
15628     getBox : function(local){
15629         var s = this.el.getSize();
15630         if(local){
15631             s.x = this.el.getLeft(true);
15632             s.y = this.el.getTop(true);
15633         }else{
15634             var xy = this.xy || this.el.getXY();
15635             s.x = xy[0];
15636             s.y = xy[1];
15637         }
15638         return s;
15639     },
15640
15641     /**
15642      * Sets the current box measurements of the component's underlying element.
15643      * @param {Object} box An object in the format {x, y, width, height}
15644      * @returns {Roo.BoxComponent} this
15645      */
15646     updateBox : function(box){
15647         this.setSize(box.width, box.height);
15648         this.setPagePosition(box.x, box.y);
15649         return this;
15650     },
15651
15652     // protected
15653     getResizeEl : function(){
15654         return this.resizeEl || this.el;
15655     },
15656
15657     // protected
15658     getPositionEl : function(){
15659         return this.positionEl || this.el;
15660     },
15661
15662     /**
15663      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15664      * This method fires the move event.
15665      * @param {Number} left The new left
15666      * @param {Number} top The new top
15667      * @returns {Roo.BoxComponent} this
15668      */
15669     setPosition : function(x, y){
15670         this.x = x;
15671         this.y = y;
15672         if(!this.boxReady){
15673             return this;
15674         }
15675         var adj = this.adjustPosition(x, y);
15676         var ax = adj.x, ay = adj.y;
15677
15678         var el = this.getPositionEl();
15679         if(ax !== undefined || ay !== undefined){
15680             if(ax !== undefined && ay !== undefined){
15681                 el.setLeftTop(ax, ay);
15682             }else if(ax !== undefined){
15683                 el.setLeft(ax);
15684             }else if(ay !== undefined){
15685                 el.setTop(ay);
15686             }
15687             this.onPosition(ax, ay);
15688             this.fireEvent('move', this, ax, ay);
15689         }
15690         return this;
15691     },
15692
15693     /**
15694      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15695      * This method fires the move event.
15696      * @param {Number} x The new x position
15697      * @param {Number} y The new y position
15698      * @returns {Roo.BoxComponent} this
15699      */
15700     setPagePosition : function(x, y){
15701         this.pageX = x;
15702         this.pageY = y;
15703         if(!this.boxReady){
15704             return;
15705         }
15706         if(x === undefined || y === undefined){ // cannot translate undefined points
15707             return;
15708         }
15709         var p = this.el.translatePoints(x, y);
15710         this.setPosition(p.left, p.top);
15711         return this;
15712     },
15713
15714     // private
15715     onRender : function(ct, position){
15716         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15717         if(this.resizeEl){
15718             this.resizeEl = Roo.get(this.resizeEl);
15719         }
15720         if(this.positionEl){
15721             this.positionEl = Roo.get(this.positionEl);
15722         }
15723     },
15724
15725     // private
15726     afterRender : function(){
15727         Roo.BoxComponent.superclass.afterRender.call(this);
15728         this.boxReady = true;
15729         this.setSize(this.width, this.height);
15730         if(this.x || this.y){
15731             this.setPosition(this.x, this.y);
15732         }
15733         if(this.pageX || this.pageY){
15734             this.setPagePosition(this.pageX, this.pageY);
15735         }
15736     },
15737
15738     /**
15739      * Force the component's size to recalculate based on the underlying element's current height and width.
15740      * @returns {Roo.BoxComponent} this
15741      */
15742     syncSize : function(){
15743         delete this.lastSize;
15744         this.setSize(this.el.getWidth(), this.el.getHeight());
15745         return this;
15746     },
15747
15748     /**
15749      * Called after the component is resized, this method is empty by default but can be implemented by any
15750      * subclass that needs to perform custom logic after a resize occurs.
15751      * @param {Number} adjWidth The box-adjusted width that was set
15752      * @param {Number} adjHeight The box-adjusted height that was set
15753      * @param {Number} rawWidth The width that was originally specified
15754      * @param {Number} rawHeight The height that was originally specified
15755      */
15756     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15757
15758     },
15759
15760     /**
15761      * Called after the component is moved, this method is empty by default but can be implemented by any
15762      * subclass that needs to perform custom logic after a move occurs.
15763      * @param {Number} x The new x position
15764      * @param {Number} y The new y position
15765      */
15766     onPosition : function(x, y){
15767
15768     },
15769
15770     // private
15771     adjustSize : function(w, h){
15772         if(this.autoWidth){
15773             w = 'auto';
15774         }
15775         if(this.autoHeight){
15776             h = 'auto';
15777         }
15778         return {width : w, height: h};
15779     },
15780
15781     // private
15782     adjustPosition : function(x, y){
15783         return {x : x, y: y};
15784     }
15785 });/*
15786  * Original code for Roojs - LGPL
15787  * <script type="text/javascript">
15788  */
15789  
15790 /**
15791  * @class Roo.XComponent
15792  * A delayed Element creator...
15793  * Or a way to group chunks of interface together.
15794  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15795  *  used in conjunction with XComponent.build() it will create an instance of each element,
15796  *  then call addxtype() to build the User interface.
15797  * 
15798  * Mypart.xyx = new Roo.XComponent({
15799
15800     parent : 'Mypart.xyz', // empty == document.element.!!
15801     order : '001',
15802     name : 'xxxx'
15803     region : 'xxxx'
15804     disabled : function() {} 
15805      
15806     tree : function() { // return an tree of xtype declared components
15807         var MODULE = this;
15808         return 
15809         {
15810             xtype : 'NestedLayoutPanel',
15811             // technicall
15812         }
15813      ]
15814  *})
15815  *
15816  *
15817  * It can be used to build a big heiracy, with parent etc.
15818  * or you can just use this to render a single compoent to a dom element
15819  * MYPART.render(Roo.Element | String(id) | dom_element )
15820  *
15821  *
15822  * Usage patterns.
15823  *
15824  * Classic Roo
15825  *
15826  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15827  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15828  *
15829  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15830  *
15831  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15832  * - if mulitple topModules exist, the last one is defined as the top module.
15833  *
15834  * Embeded Roo
15835  * 
15836  * When the top level or multiple modules are to embedded into a existing HTML page,
15837  * the parent element can container '#id' of the element where the module will be drawn.
15838  *
15839  * Bootstrap Roo
15840  *
15841  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15842  * it relies more on a include mechanism, where sub modules are included into an outer page.
15843  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15844  * 
15845  * Bootstrap Roo Included elements
15846  *
15847  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15848  * hence confusing the component builder as it thinks there are multiple top level elements. 
15849  *
15850  * 
15851  * 
15852  * @extends Roo.util.Observable
15853  * @constructor
15854  * @param cfg {Object} configuration of component
15855  * 
15856  */
15857 Roo.XComponent = function(cfg) {
15858     Roo.apply(this, cfg);
15859     this.addEvents({ 
15860         /**
15861              * @event built
15862              * Fires when this the componnt is built
15863              * @param {Roo.XComponent} c the component
15864              */
15865         'built' : true
15866         
15867     });
15868     this.region = this.region || 'center'; // default..
15869     Roo.XComponent.register(this);
15870     this.modules = false;
15871     this.el = false; // where the layout goes..
15872     
15873     
15874 }
15875 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15876     /**
15877      * @property el
15878      * The created element (with Roo.factory())
15879      * @type {Roo.Layout}
15880      */
15881     el  : false,
15882     
15883     /**
15884      * @property el
15885      * for BC  - use el in new code
15886      * @type {Roo.Layout}
15887      */
15888     panel : false,
15889     
15890     /**
15891      * @property layout
15892      * for BC  - use el in new code
15893      * @type {Roo.Layout}
15894      */
15895     layout : false,
15896     
15897      /**
15898      * @cfg {Function|boolean} disabled
15899      * If this module is disabled by some rule, return true from the funtion
15900      */
15901     disabled : false,
15902     
15903     /**
15904      * @cfg {String} parent 
15905      * Name of parent element which it get xtype added to..
15906      */
15907     parent: false,
15908     
15909     /**
15910      * @cfg {String} order
15911      * Used to set the order in which elements are created (usefull for multiple tabs)
15912      */
15913     
15914     order : false,
15915     /**
15916      * @cfg {String} name
15917      * String to display while loading.
15918      */
15919     name : false,
15920     /**
15921      * @cfg {String} region
15922      * Region to render component to (defaults to center)
15923      */
15924     region : 'center',
15925     
15926     /**
15927      * @cfg {Array} items
15928      * A single item array - the first element is the root of the tree..
15929      * It's done this way to stay compatible with the Xtype system...
15930      */
15931     items : false,
15932     
15933     /**
15934      * @property _tree
15935      * The method that retuns the tree of parts that make up this compoennt 
15936      * @type {function}
15937      */
15938     _tree  : false,
15939     
15940      /**
15941      * render
15942      * render element to dom or tree
15943      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15944      */
15945     
15946     render : function(el)
15947     {
15948         
15949         el = el || false;
15950         var hp = this.parent ? 1 : 0;
15951         Roo.debug &&  Roo.log(this);
15952         
15953         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15954             // if parent is a '#.....' string, then let's use that..
15955             var ename = this.parent.substr(1);
15956             this.parent = false;
15957             Roo.debug && Roo.log(ename);
15958             switch (ename) {
15959                 case 'bootstrap-body' :
15960                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15961                         this.parent = { el :  new  Roo.bootstrap.Body() };
15962                         Roo.debug && Roo.log("setting el to doc body");
15963                          
15964                     } else {
15965                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15966                     }
15967                     break;
15968                 case 'bootstrap':
15969                     this.parent = { el : true};
15970                     // fall through
15971                 default:
15972                     el = Roo.get(ename);
15973                     break;
15974             }
15975                 
15976             
15977             if (!el && !this.parent) {
15978                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15979                 return;
15980             }
15981         }
15982         Roo.debug && Roo.log("EL:");
15983         Roo.debug && Roo.log(el);
15984         Roo.debug && Roo.log("this.parent.el:");
15985         Roo.debug && Roo.log(this.parent.el);
15986         
15987         var tree = this._tree ? this._tree() : this.tree();
15988
15989         // altertive root elements ??? - we need a better way to indicate these.
15990         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15991                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15992         
15993         if (!this.parent && is_alt) {
15994             //el = Roo.get(document.body);
15995             this.parent = { el : true };
15996         }
15997             
15998             
15999         
16000         if (!this.parent) {
16001             
16002             Roo.debug && Roo.log("no parent - creating one");
16003             
16004             el = el ? Roo.get(el) : false;      
16005             
16006             // it's a top level one..
16007             this.parent =  {
16008                 el : new Roo.BorderLayout(el || document.body, {
16009                 
16010                      center: {
16011                          titlebar: false,
16012                          autoScroll:false,
16013                          closeOnTab: true,
16014                          tabPosition: 'top',
16015                           //resizeTabs: true,
16016                          alwaysShowTabs: el && hp? false :  true,
16017                          hideTabs: el || !hp ? true :  false,
16018                          minTabWidth: 140
16019                      }
16020                  })
16021             }
16022         }
16023         
16024         if (!this.parent.el) {
16025                 // probably an old style ctor, which has been disabled.
16026                 return;
16027
16028         }
16029                 // The 'tree' method is  '_tree now' 
16030             
16031         tree.region = tree.region || this.region;
16032         
16033         if (this.parent.el === true) {
16034             // bootstrap... - body..
16035             this.parent.el = Roo.factory(tree);
16036         }
16037         
16038         this.el = this.parent.el.addxtype(tree);
16039         this.fireEvent('built', this);
16040         
16041         this.panel = this.el;
16042         this.layout = this.panel.layout;
16043         this.parentLayout = this.parent.layout  || false;  
16044          
16045     }
16046     
16047 });
16048
16049 Roo.apply(Roo.XComponent, {
16050     /**
16051      * @property  hideProgress
16052      * true to disable the building progress bar.. usefull on single page renders.
16053      * @type Boolean
16054      */
16055     hideProgress : false,
16056     /**
16057      * @property  buildCompleted
16058      * True when the builder has completed building the interface.
16059      * @type Boolean
16060      */
16061     buildCompleted : false,
16062      
16063     /**
16064      * @property  topModule
16065      * the upper most module - uses document.element as it's constructor.
16066      * @type Object
16067      */
16068      
16069     topModule  : false,
16070       
16071     /**
16072      * @property  modules
16073      * array of modules to be created by registration system.
16074      * @type {Array} of Roo.XComponent
16075      */
16076     
16077     modules : [],
16078     /**
16079      * @property  elmodules
16080      * array of modules to be created by which use #ID 
16081      * @type {Array} of Roo.XComponent
16082      */
16083      
16084     elmodules : [],
16085
16086      /**
16087      * @property  build_from_html
16088      * Build elements from html - used by bootstrap HTML stuff 
16089      *    - this is cleared after build is completed
16090      * @type {boolean} true  (default false)
16091      */
16092      
16093     build_from_html : false,
16094
16095     /**
16096      * Register components to be built later.
16097      *
16098      * This solves the following issues
16099      * - Building is not done on page load, but after an authentication process has occured.
16100      * - Interface elements are registered on page load
16101      * - Parent Interface elements may not be loaded before child, so this handles that..
16102      * 
16103      *
16104      * example:
16105      * 
16106      * MyApp.register({
16107           order : '000001',
16108           module : 'Pman.Tab.projectMgr',
16109           region : 'center',
16110           parent : 'Pman.layout',
16111           disabled : false,  // or use a function..
16112         })
16113      
16114      * * @param {Object} details about module
16115      */
16116     register : function(obj) {
16117                 
16118         Roo.XComponent.event.fireEvent('register', obj);
16119         switch(typeof(obj.disabled) ) {
16120                 
16121             case 'undefined':
16122                 break;
16123             
16124             case 'function':
16125                 if ( obj.disabled() ) {
16126                         return;
16127                 }
16128                 break;
16129             
16130             default:
16131                 if (obj.disabled) {
16132                         return;
16133                 }
16134                 break;
16135         }
16136                 
16137         this.modules.push(obj);
16138          
16139     },
16140     /**
16141      * convert a string to an object..
16142      * eg. 'AAA.BBB' -> finds AAA.BBB
16143
16144      */
16145     
16146     toObject : function(str)
16147     {
16148         if (!str || typeof(str) == 'object') {
16149             return str;
16150         }
16151         if (str.substring(0,1) == '#') {
16152             return str;
16153         }
16154
16155         var ar = str.split('.');
16156         var rt, o;
16157         rt = ar.shift();
16158             /** eval:var:o */
16159         try {
16160             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16161         } catch (e) {
16162             throw "Module not found : " + str;
16163         }
16164         
16165         if (o === false) {
16166             throw "Module not found : " + str;
16167         }
16168         Roo.each(ar, function(e) {
16169             if (typeof(o[e]) == 'undefined') {
16170                 throw "Module not found : " + str;
16171             }
16172             o = o[e];
16173         });
16174         
16175         return o;
16176         
16177     },
16178     
16179     
16180     /**
16181      * move modules into their correct place in the tree..
16182      * 
16183      */
16184     preBuild : function ()
16185     {
16186         var _t = this;
16187         Roo.each(this.modules , function (obj)
16188         {
16189             Roo.XComponent.event.fireEvent('beforebuild', obj);
16190             
16191             var opar = obj.parent;
16192             try { 
16193                 obj.parent = this.toObject(opar);
16194             } catch(e) {
16195                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16196                 return;
16197             }
16198             
16199             if (!obj.parent) {
16200                 Roo.debug && Roo.log("GOT top level module");
16201                 Roo.debug && Roo.log(obj);
16202                 obj.modules = new Roo.util.MixedCollection(false, 
16203                     function(o) { return o.order + '' }
16204                 );
16205                 this.topModule = obj;
16206                 return;
16207             }
16208                         // parent is a string (usually a dom element name..)
16209             if (typeof(obj.parent) == 'string') {
16210                 this.elmodules.push(obj);
16211                 return;
16212             }
16213             if (obj.parent.constructor != Roo.XComponent) {
16214                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16215             }
16216             if (!obj.parent.modules) {
16217                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16218                     function(o) { return o.order + '' }
16219                 );
16220             }
16221             if (obj.parent.disabled) {
16222                 obj.disabled = true;
16223             }
16224             obj.parent.modules.add(obj);
16225         }, this);
16226     },
16227     
16228      /**
16229      * make a list of modules to build.
16230      * @return {Array} list of modules. 
16231      */ 
16232     
16233     buildOrder : function()
16234     {
16235         var _this = this;
16236         var cmp = function(a,b) {   
16237             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16238         };
16239         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16240             throw "No top level modules to build";
16241         }
16242         
16243         // make a flat list in order of modules to build.
16244         var mods = this.topModule ? [ this.topModule ] : [];
16245                 
16246         
16247         // elmodules (is a list of DOM based modules )
16248         Roo.each(this.elmodules, function(e) {
16249             mods.push(e);
16250             if (!this.topModule &&
16251                 typeof(e.parent) == 'string' &&
16252                 e.parent.substring(0,1) == '#' &&
16253                 Roo.get(e.parent.substr(1))
16254                ) {
16255                 
16256                 _this.topModule = e;
16257             }
16258             
16259         });
16260
16261         
16262         // add modules to their parents..
16263         var addMod = function(m) {
16264             Roo.debug && Roo.log("build Order: add: " + m.name);
16265                 
16266             mods.push(m);
16267             if (m.modules && !m.disabled) {
16268                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16269                 m.modules.keySort('ASC',  cmp );
16270                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16271     
16272                 m.modules.each(addMod);
16273             } else {
16274                 Roo.debug && Roo.log("build Order: no child modules");
16275             }
16276             // not sure if this is used any more..
16277             if (m.finalize) {
16278                 m.finalize.name = m.name + " (clean up) ";
16279                 mods.push(m.finalize);
16280             }
16281             
16282         }
16283         if (this.topModule && this.topModule.modules) { 
16284             this.topModule.modules.keySort('ASC',  cmp );
16285             this.topModule.modules.each(addMod);
16286         } 
16287         return mods;
16288     },
16289     
16290      /**
16291      * Build the registered modules.
16292      * @param {Object} parent element.
16293      * @param {Function} optional method to call after module has been added.
16294      * 
16295      */ 
16296    
16297     build : function(opts) 
16298     {
16299         
16300         if (typeof(opts) != 'undefined') {
16301             Roo.apply(this,opts);
16302         }
16303         
16304         this.preBuild();
16305         var mods = this.buildOrder();
16306       
16307         //this.allmods = mods;
16308         //Roo.debug && Roo.log(mods);
16309         //return;
16310         if (!mods.length) { // should not happen
16311             throw "NO modules!!!";
16312         }
16313         
16314         
16315         var msg = "Building Interface...";
16316         // flash it up as modal - so we store the mask!?
16317         if (!this.hideProgress && Roo.MessageBox) {
16318             Roo.MessageBox.show({ title: 'loading' });
16319             Roo.MessageBox.show({
16320                title: "Please wait...",
16321                msg: msg,
16322                width:450,
16323                progress:true,
16324                closable:false,
16325                modal: false
16326               
16327             });
16328         }
16329         var total = mods.length;
16330         
16331         var _this = this;
16332         var progressRun = function() {
16333             if (!mods.length) {
16334                 Roo.debug && Roo.log('hide?');
16335                 if (!this.hideProgress && Roo.MessageBox) {
16336                     Roo.MessageBox.hide();
16337                 }
16338                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16339                 
16340                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16341                 
16342                 // THE END...
16343                 return false;   
16344             }
16345             
16346             var m = mods.shift();
16347             
16348             
16349             Roo.debug && Roo.log(m);
16350             // not sure if this is supported any more.. - modules that are are just function
16351             if (typeof(m) == 'function') { 
16352                 m.call(this);
16353                 return progressRun.defer(10, _this);
16354             } 
16355             
16356             
16357             msg = "Building Interface " + (total  - mods.length) + 
16358                     " of " + total + 
16359                     (m.name ? (' - ' + m.name) : '');
16360                         Roo.debug && Roo.log(msg);
16361             if (!this.hideProgress &&  Roo.MessageBox) { 
16362                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16363             }
16364             
16365          
16366             // is the module disabled?
16367             var disabled = (typeof(m.disabled) == 'function') ?
16368                 m.disabled.call(m.module.disabled) : m.disabled;    
16369             
16370             
16371             if (disabled) {
16372                 return progressRun(); // we do not update the display!
16373             }
16374             
16375             // now build 
16376             
16377                         
16378                         
16379             m.render();
16380             // it's 10 on top level, and 1 on others??? why...
16381             return progressRun.defer(10, _this);
16382              
16383         }
16384         progressRun.defer(1, _this);
16385      
16386         
16387         
16388     },
16389         
16390         
16391         /**
16392          * Event Object.
16393          *
16394          *
16395          */
16396         event: false, 
16397     /**
16398          * wrapper for event.on - aliased later..  
16399          * Typically use to register a event handler for register:
16400          *
16401          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16402          *
16403          */
16404     on : false
16405    
16406     
16407     
16408 });
16409
16410 Roo.XComponent.event = new Roo.util.Observable({
16411                 events : { 
16412                         /**
16413                          * @event register
16414                          * Fires when an Component is registered,
16415                          * set the disable property on the Component to stop registration.
16416                          * @param {Roo.XComponent} c the component being registerd.
16417                          * 
16418                          */
16419                         'register' : true,
16420             /**
16421                          * @event beforebuild
16422                          * Fires before each Component is built
16423                          * can be used to apply permissions.
16424                          * @param {Roo.XComponent} c the component being registerd.
16425                          * 
16426                          */
16427                         'beforebuild' : true,
16428                         /**
16429                          * @event buildcomplete
16430                          * Fires on the top level element when all elements have been built
16431                          * @param {Roo.XComponent} the top level component.
16432                          */
16433                         'buildcomplete' : true
16434                         
16435                 }
16436 });
16437
16438 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16439