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                     Roo.log('got here');
4402                     el.insertAdjacentHTML('BeforeEnd', html);
4403                     return el.lastChild;
4404                 case "afterend":
4405                     el.insertAdjacentHTML('AfterEnd', html);
4406                     return el.nextSibling;
4407             }
4408             throw 'Illegal insertion point -> "' + where + '"';
4409         }
4410         var range = el.ownerDocument.createRange();
4411         var frag;
4412         switch(where){
4413              case "beforebegin":
4414                 range.setStartBefore(el);
4415                 frag = range.createContextualFragment(html);
4416                 el.parentNode.insertBefore(frag, el);
4417                 return el.previousSibling;
4418              case "afterbegin":
4419                 if(el.firstChild){
4420                     range.setStartBefore(el.firstChild);
4421                     frag = range.createContextualFragment(html);
4422                     el.insertBefore(frag, el.firstChild);
4423                     return el.firstChild;
4424                 }else{
4425                     el.innerHTML = html;
4426                     return el.firstChild;
4427                 }
4428             case "beforeend":
4429                 if(el.lastChild){
4430                     range.setStartAfter(el.lastChild);
4431                     frag = range.createContextualFragment(html);
4432                     el.appendChild(frag);
4433                     return el.lastChild;
4434                 }else{
4435                     el.innerHTML = html;
4436                     return el.lastChild;
4437                 }
4438             case "afterend":
4439                 range.setStartAfter(el);
4440                 frag = range.createContextualFragment(html);
4441                 el.parentNode.insertBefore(frag, el.nextSibling);
4442                 return el.nextSibling;
4443             }
4444             throw 'Illegal insertion point -> "' + where + '"';
4445     },
4446
4447     /**
4448      * Creates new Dom element(s) and inserts them before el
4449      * @param {String/HTMLElement/Element} el The context element
4450      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4451      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4452      * @return {HTMLElement/Roo.Element} The new node
4453      */
4454     insertBefore : function(el, o, returnElement){
4455         return this.doInsert(el, o, returnElement, "beforeBegin");
4456     },
4457
4458     /**
4459      * Creates new Dom element(s) and inserts them after el
4460      * @param {String/HTMLElement/Element} el The context element
4461      * @param {Object} o The Dom object spec (and children)
4462      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4463      * @return {HTMLElement/Roo.Element} The new node
4464      */
4465     insertAfter : function(el, o, returnElement){
4466         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4467     },
4468
4469     /**
4470      * Creates new Dom element(s) and inserts them as the first child of el
4471      * @param {String/HTMLElement/Element} el The context element
4472      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4473      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4474      * @return {HTMLElement/Roo.Element} The new node
4475      */
4476     insertFirst : function(el, o, returnElement){
4477         return this.doInsert(el, o, returnElement, "afterBegin");
4478     },
4479
4480     // private
4481     doInsert : function(el, o, returnElement, pos, sibling){
4482         el = Roo.getDom(el);
4483         var newNode;
4484         if(this.useDom || o.ns){
4485             newNode = createDom(o, null);
4486             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4487         }else{
4488             var html = createHtml(o);
4489             newNode = this.insertHtml(pos, el, html);
4490         }
4491         return returnElement ? Roo.get(newNode, true) : newNode;
4492     },
4493
4494     /**
4495      * Creates new Dom element(s) and appends them to el
4496      * @param {String/HTMLElement/Element} el The context element
4497      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4498      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4499      * @return {HTMLElement/Roo.Element} The new node
4500      */
4501     append : function(el, o, returnElement){
4502         el = Roo.getDom(el);
4503         var newNode;
4504         if(this.useDom || o.ns){
4505             newNode = createDom(o, null);
4506             el.appendChild(newNode);
4507         }else{
4508             var html = createHtml(o);
4509             newNode = this.insertHtml("beforeEnd", el, html);
4510         }
4511         return returnElement ? Roo.get(newNode, true) : newNode;
4512     },
4513
4514     /**
4515      * Creates new Dom element(s) and overwrites the contents of el with them
4516      * @param {String/HTMLElement/Element} el The context element
4517      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4518      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4519      * @return {HTMLElement/Roo.Element} The new node
4520      */
4521     overwrite : function(el, o, returnElement){
4522         el = Roo.getDom(el);
4523         if (o.ns) {
4524           
4525             while (el.childNodes.length) {
4526                 el.removeChild(el.firstChild);
4527             }
4528             createDom(o, el);
4529         } else {
4530             el.innerHTML = createHtml(o);   
4531         }
4532         
4533         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4534     },
4535
4536     /**
4537      * Creates a new Roo.DomHelper.Template from the Dom object spec
4538      * @param {Object} o The Dom object spec (and children)
4539      * @return {Roo.DomHelper.Template} The new template
4540      */
4541     createTemplate : function(o){
4542         var html = createHtml(o);
4543         return new Roo.Template(html);
4544     }
4545     };
4546 }();
4547 /*
4548  * Based on:
4549  * Ext JS Library 1.1.1
4550  * Copyright(c) 2006-2007, Ext JS, LLC.
4551  *
4552  * Originally Released Under LGPL - original licence link has changed is not relivant.
4553  *
4554  * Fork - LGPL
4555  * <script type="text/javascript">
4556  */
4557  
4558 /**
4559 * @class Roo.Template
4560 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4561 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4562 * Usage:
4563 <pre><code>
4564 var t = new Roo.Template({
4565     html :  '&lt;div name="{id}"&gt;' + 
4566         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4567         '&lt;/div&gt;',
4568     myformat: function (value, allValues) {
4569         return 'XX' + value;
4570     }
4571 });
4572 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4573 </code></pre>
4574 * For more information see this blog post with examples:
4575 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4576      - Create Elements using DOM, HTML fragments and Templates</a>. 
4577 * @constructor
4578 * @param {Object} cfg - Configuration object.
4579 */
4580 Roo.Template = function(cfg){
4581     // BC!
4582     if(cfg instanceof Array){
4583         cfg = cfg.join("");
4584     }else if(arguments.length > 1){
4585         cfg = Array.prototype.join.call(arguments, "");
4586     }
4587     
4588     
4589     if (typeof(cfg) == 'object') {
4590         Roo.apply(this,cfg)
4591     } else {
4592         // bc
4593         this.html = cfg;
4594     }
4595     if (this.url) {
4596         this.load();
4597     }
4598     
4599 };
4600 Roo.Template.prototype = {
4601     
4602     /**
4603      * @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..
4604      *                    it should be fixed so that template is observable...
4605      */
4606     url : false,
4607     /**
4608      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4609      */
4610     html : '',
4611     /**
4612      * Returns an HTML fragment of this template with the specified values applied.
4613      * @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'})
4614      * @return {String} The HTML fragment
4615      */
4616     applyTemplate : function(values){
4617         try {
4618            
4619             if(this.compiled){
4620                 return this.compiled(values);
4621             }
4622             var useF = this.disableFormats !== true;
4623             var fm = Roo.util.Format, tpl = this;
4624             var fn = function(m, name, format, args){
4625                 if(format && useF){
4626                     if(format.substr(0, 5) == "this."){
4627                         return tpl.call(format.substr(5), values[name], values);
4628                     }else{
4629                         if(args){
4630                             // quoted values are required for strings in compiled templates, 
4631                             // but for non compiled we need to strip them
4632                             // quoted reversed for jsmin
4633                             var re = /^\s*['"](.*)["']\s*$/;
4634                             args = args.split(',');
4635                             for(var i = 0, len = args.length; i < len; i++){
4636                                 args[i] = args[i].replace(re, "$1");
4637                             }
4638                             args = [values[name]].concat(args);
4639                         }else{
4640                             args = [values[name]];
4641                         }
4642                         return fm[format].apply(fm, args);
4643                     }
4644                 }else{
4645                     return values[name] !== undefined ? values[name] : "";
4646                 }
4647             };
4648             return this.html.replace(this.re, fn);
4649         } catch (e) {
4650             Roo.log(e);
4651             throw e;
4652         }
4653          
4654     },
4655     
4656     loading : false,
4657       
4658     load : function ()
4659     {
4660          
4661         if (this.loading) {
4662             return;
4663         }
4664         var _t = this;
4665         
4666         this.loading = true;
4667         this.compiled = false;
4668         
4669         var cx = new Roo.data.Connection();
4670         cx.request({
4671             url : this.url,
4672             method : 'GET',
4673             success : function (response) {
4674                 _t.loading = false;
4675                 _t.html = response.responseText;
4676                 _t.url = false;
4677                 _t.compile();
4678              },
4679             failure : function(response) {
4680                 Roo.log("Template failed to load from " + _t.url);
4681                 _t.loading = false;
4682             }
4683         });
4684     },
4685
4686     /**
4687      * Sets the HTML used as the template and optionally compiles it.
4688      * @param {String} html
4689      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4690      * @return {Roo.Template} this
4691      */
4692     set : function(html, compile){
4693         this.html = html;
4694         this.compiled = null;
4695         if(compile){
4696             this.compile();
4697         }
4698         return this;
4699     },
4700     
4701     /**
4702      * True to disable format functions (defaults to false)
4703      * @type Boolean
4704      */
4705     disableFormats : false,
4706     
4707     /**
4708     * The regular expression used to match template variables 
4709     * @type RegExp
4710     * @property 
4711     */
4712     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4713     
4714     /**
4715      * Compiles the template into an internal function, eliminating the RegEx overhead.
4716      * @return {Roo.Template} this
4717      */
4718     compile : function(){
4719         var fm = Roo.util.Format;
4720         var useF = this.disableFormats !== true;
4721         var sep = Roo.isGecko ? "+" : ",";
4722         var fn = function(m, name, format, args){
4723             if(format && useF){
4724                 args = args ? ',' + args : "";
4725                 if(format.substr(0, 5) != "this."){
4726                     format = "fm." + format + '(';
4727                 }else{
4728                     format = 'this.call("'+ format.substr(5) + '", ';
4729                     args = ", values";
4730                 }
4731             }else{
4732                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4733             }
4734             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4735         };
4736         var body;
4737         // branched to use + in gecko and [].join() in others
4738         if(Roo.isGecko){
4739             body = "this.compiled = function(values){ return '" +
4740                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4741                     "';};";
4742         }else{
4743             body = ["this.compiled = function(values){ return ['"];
4744             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4745             body.push("'].join('');};");
4746             body = body.join('');
4747         }
4748         /**
4749          * eval:var:values
4750          * eval:var:fm
4751          */
4752         eval(body);
4753         return this;
4754     },
4755     
4756     // private function used to call members
4757     call : function(fnName, value, allValues){
4758         return this[fnName](value, allValues);
4759     },
4760     
4761     /**
4762      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4763      * @param {String/HTMLElement/Roo.Element} el The context element
4764      * @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'})
4765      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4766      * @return {HTMLElement/Roo.Element} The new node or Element
4767      */
4768     insertFirst: function(el, values, returnElement){
4769         return this.doInsert('afterBegin', el, values, returnElement);
4770     },
4771
4772     /**
4773      * Applies the supplied values to the template and inserts the new node(s) before el.
4774      * @param {String/HTMLElement/Roo.Element} el The context element
4775      * @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'})
4776      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4777      * @return {HTMLElement/Roo.Element} The new node or Element
4778      */
4779     insertBefore: function(el, values, returnElement){
4780         return this.doInsert('beforeBegin', el, values, returnElement);
4781     },
4782
4783     /**
4784      * Applies the supplied values to the template and inserts the new node(s) after el.
4785      * @param {String/HTMLElement/Roo.Element} el The context element
4786      * @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'})
4787      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4788      * @return {HTMLElement/Roo.Element} The new node or Element
4789      */
4790     insertAfter : function(el, values, returnElement){
4791         return this.doInsert('afterEnd', el, values, returnElement);
4792     },
4793     
4794     /**
4795      * Applies the supplied values to the template and appends the new node(s) to el.
4796      * @param {String/HTMLElement/Roo.Element} el The context element
4797      * @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'})
4798      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4799      * @return {HTMLElement/Roo.Element} The new node or Element
4800      */
4801     append : function(el, values, returnElement){
4802         return this.doInsert('beforeEnd', el, values, returnElement);
4803     },
4804
4805     doInsert : function(where, el, values, returnEl){
4806         el = Roo.getDom(el);
4807         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4808         return returnEl ? Roo.get(newNode, true) : newNode;
4809     },
4810
4811     /**
4812      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4813      * @param {String/HTMLElement/Roo.Element} el The context element
4814      * @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'})
4815      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4816      * @return {HTMLElement/Roo.Element} The new node or Element
4817      */
4818     overwrite : function(el, values, returnElement){
4819         el = Roo.getDom(el);
4820         el.innerHTML = this.applyTemplate(values);
4821         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4822     }
4823 };
4824 /**
4825  * Alias for {@link #applyTemplate}
4826  * @method
4827  */
4828 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4829
4830 // backwards compat
4831 Roo.DomHelper.Template = Roo.Template;
4832
4833 /**
4834  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4835  * @param {String/HTMLElement} el A DOM element or its id
4836  * @returns {Roo.Template} The created template
4837  * @static
4838  */
4839 Roo.Template.from = function(el){
4840     el = Roo.getDom(el);
4841     return new Roo.Template(el.value || el.innerHTML);
4842 };/*
4843  * Based on:
4844  * Ext JS Library 1.1.1
4845  * Copyright(c) 2006-2007, Ext JS, LLC.
4846  *
4847  * Originally Released Under LGPL - original licence link has changed is not relivant.
4848  *
4849  * Fork - LGPL
4850  * <script type="text/javascript">
4851  */
4852  
4853
4854 /*
4855  * This is code is also distributed under MIT license for use
4856  * with jQuery and prototype JavaScript libraries.
4857  */
4858 /**
4859  * @class Roo.DomQuery
4860 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).
4861 <p>
4862 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>
4863
4864 <p>
4865 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.
4866 </p>
4867 <h4>Element Selectors:</h4>
4868 <ul class="list">
4869     <li> <b>*</b> any element</li>
4870     <li> <b>E</b> an element with the tag E</li>
4871     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4872     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4873     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4874     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4875 </ul>
4876 <h4>Attribute Selectors:</h4>
4877 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4878 <ul class="list">
4879     <li> <b>E[foo]</b> has an attribute "foo"</li>
4880     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4881     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4882     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4883     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4884     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4885     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4886 </ul>
4887 <h4>Pseudo Classes:</h4>
4888 <ul class="list">
4889     <li> <b>E:first-child</b> E is the first child of its parent</li>
4890     <li> <b>E:last-child</b> E is the last child of its parent</li>
4891     <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>
4892     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4893     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4894     <li> <b>E:only-child</b> E is the only child of its parent</li>
4895     <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>
4896     <li> <b>E:first</b> the first E in the resultset</li>
4897     <li> <b>E:last</b> the last E in the resultset</li>
4898     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4899     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4900     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4901     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4902     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4903     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4904     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4905     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4906     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4907 </ul>
4908 <h4>CSS Value Selectors:</h4>
4909 <ul class="list">
4910     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4911     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4912     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4913     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4914     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4915     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4916 </ul>
4917  * @singleton
4918  */
4919 Roo.DomQuery = function(){
4920     var cache = {}, simpleCache = {}, valueCache = {};
4921     var nonSpace = /\S/;
4922     var trimRe = /^\s+|\s+$/g;
4923     var tplRe = /\{(\d+)\}/g;
4924     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4925     var tagTokenRe = /^(#)?([\w-\*]+)/;
4926     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4927
4928     function child(p, index){
4929         var i = 0;
4930         var n = p.firstChild;
4931         while(n){
4932             if(n.nodeType == 1){
4933                if(++i == index){
4934                    return n;
4935                }
4936             }
4937             n = n.nextSibling;
4938         }
4939         return null;
4940     };
4941
4942     function next(n){
4943         while((n = n.nextSibling) && n.nodeType != 1);
4944         return n;
4945     };
4946
4947     function prev(n){
4948         while((n = n.previousSibling) && n.nodeType != 1);
4949         return n;
4950     };
4951
4952     function children(d){
4953         var n = d.firstChild, ni = -1;
4954             while(n){
4955                 var nx = n.nextSibling;
4956                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4957                     d.removeChild(n);
4958                 }else{
4959                     n.nodeIndex = ++ni;
4960                 }
4961                 n = nx;
4962             }
4963             return this;
4964         };
4965
4966     function byClassName(c, a, v){
4967         if(!v){
4968             return c;
4969         }
4970         var r = [], ri = -1, cn;
4971         for(var i = 0, ci; ci = c[i]; i++){
4972             if((' '+ci.className+' ').indexOf(v) != -1){
4973                 r[++ri] = ci;
4974             }
4975         }
4976         return r;
4977     };
4978
4979     function attrValue(n, attr){
4980         if(!n.tagName && typeof n.length != "undefined"){
4981             n = n[0];
4982         }
4983         if(!n){
4984             return null;
4985         }
4986         if(attr == "for"){
4987             return n.htmlFor;
4988         }
4989         if(attr == "class" || attr == "className"){
4990             return n.className;
4991         }
4992         return n.getAttribute(attr) || n[attr];
4993
4994     };
4995
4996     function getNodes(ns, mode, tagName){
4997         var result = [], ri = -1, cs;
4998         if(!ns){
4999             return result;
5000         }
5001         tagName = tagName || "*";
5002         if(typeof ns.getElementsByTagName != "undefined"){
5003             ns = [ns];
5004         }
5005         if(!mode){
5006             for(var i = 0, ni; ni = ns[i]; i++){
5007                 cs = ni.getElementsByTagName(tagName);
5008                 for(var j = 0, ci; ci = cs[j]; j++){
5009                     result[++ri] = ci;
5010                 }
5011             }
5012         }else if(mode == "/" || mode == ">"){
5013             var utag = tagName.toUpperCase();
5014             for(var i = 0, ni, cn; ni = ns[i]; i++){
5015                 cn = ni.children || ni.childNodes;
5016                 for(var j = 0, cj; cj = cn[j]; j++){
5017                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5018                         result[++ri] = cj;
5019                     }
5020                 }
5021             }
5022         }else if(mode == "+"){
5023             var utag = tagName.toUpperCase();
5024             for(var i = 0, n; n = ns[i]; i++){
5025                 while((n = n.nextSibling) && n.nodeType != 1);
5026                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5027                     result[++ri] = n;
5028                 }
5029             }
5030         }else if(mode == "~"){
5031             for(var i = 0, n; n = ns[i]; i++){
5032                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5033                 if(n){
5034                     result[++ri] = n;
5035                 }
5036             }
5037         }
5038         return result;
5039     };
5040
5041     function concat(a, b){
5042         if(b.slice){
5043             return a.concat(b);
5044         }
5045         for(var i = 0, l = b.length; i < l; i++){
5046             a[a.length] = b[i];
5047         }
5048         return a;
5049     }
5050
5051     function byTag(cs, tagName){
5052         if(cs.tagName || cs == document){
5053             cs = [cs];
5054         }
5055         if(!tagName){
5056             return cs;
5057         }
5058         var r = [], ri = -1;
5059         tagName = tagName.toLowerCase();
5060         for(var i = 0, ci; ci = cs[i]; i++){
5061             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5062                 r[++ri] = ci;
5063             }
5064         }
5065         return r;
5066     };
5067
5068     function byId(cs, attr, id){
5069         if(cs.tagName || cs == document){
5070             cs = [cs];
5071         }
5072         if(!id){
5073             return cs;
5074         }
5075         var r = [], ri = -1;
5076         for(var i = 0,ci; ci = cs[i]; i++){
5077             if(ci && ci.id == id){
5078                 r[++ri] = ci;
5079                 return r;
5080             }
5081         }
5082         return r;
5083     };
5084
5085     function byAttribute(cs, attr, value, op, custom){
5086         var r = [], ri = -1, st = custom=="{";
5087         var f = Roo.DomQuery.operators[op];
5088         for(var i = 0, ci; ci = cs[i]; i++){
5089             var a;
5090             if(st){
5091                 a = Roo.DomQuery.getStyle(ci, attr);
5092             }
5093             else if(attr == "class" || attr == "className"){
5094                 a = ci.className;
5095             }else if(attr == "for"){
5096                 a = ci.htmlFor;
5097             }else if(attr == "href"){
5098                 a = ci.getAttribute("href", 2);
5099             }else{
5100                 a = ci.getAttribute(attr);
5101             }
5102             if((f && f(a, value)) || (!f && a)){
5103                 r[++ri] = ci;
5104             }
5105         }
5106         return r;
5107     };
5108
5109     function byPseudo(cs, name, value){
5110         return Roo.DomQuery.pseudos[name](cs, value);
5111     };
5112
5113     // This is for IE MSXML which does not support expandos.
5114     // IE runs the same speed using setAttribute, however FF slows way down
5115     // and Safari completely fails so they need to continue to use expandos.
5116     var isIE = window.ActiveXObject ? true : false;
5117
5118     // this eval is stop the compressor from
5119     // renaming the variable to something shorter
5120     
5121     /** eval:var:batch */
5122     var batch = 30803; 
5123
5124     var key = 30803;
5125
5126     function nodupIEXml(cs){
5127         var d = ++key;
5128         cs[0].setAttribute("_nodup", d);
5129         var r = [cs[0]];
5130         for(var i = 1, len = cs.length; i < len; i++){
5131             var c = cs[i];
5132             if(!c.getAttribute("_nodup") != d){
5133                 c.setAttribute("_nodup", d);
5134                 r[r.length] = c;
5135             }
5136         }
5137         for(var i = 0, len = cs.length; i < len; i++){
5138             cs[i].removeAttribute("_nodup");
5139         }
5140         return r;
5141     }
5142
5143     function nodup(cs){
5144         if(!cs){
5145             return [];
5146         }
5147         var len = cs.length, c, i, r = cs, cj, ri = -1;
5148         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5149             return cs;
5150         }
5151         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5152             return nodupIEXml(cs);
5153         }
5154         var d = ++key;
5155         cs[0]._nodup = d;
5156         for(i = 1; c = cs[i]; i++){
5157             if(c._nodup != d){
5158                 c._nodup = d;
5159             }else{
5160                 r = [];
5161                 for(var j = 0; j < i; j++){
5162                     r[++ri] = cs[j];
5163                 }
5164                 for(j = i+1; cj = cs[j]; j++){
5165                     if(cj._nodup != d){
5166                         cj._nodup = d;
5167                         r[++ri] = cj;
5168                     }
5169                 }
5170                 return r;
5171             }
5172         }
5173         return r;
5174     }
5175
5176     function quickDiffIEXml(c1, c2){
5177         var d = ++key;
5178         for(var i = 0, len = c1.length; i < len; i++){
5179             c1[i].setAttribute("_qdiff", d);
5180         }
5181         var r = [];
5182         for(var i = 0, len = c2.length; i < len; i++){
5183             if(c2[i].getAttribute("_qdiff") != d){
5184                 r[r.length] = c2[i];
5185             }
5186         }
5187         for(var i = 0, len = c1.length; i < len; i++){
5188            c1[i].removeAttribute("_qdiff");
5189         }
5190         return r;
5191     }
5192
5193     function quickDiff(c1, c2){
5194         var len1 = c1.length;
5195         if(!len1){
5196             return c2;
5197         }
5198         if(isIE && c1[0].selectSingleNode){
5199             return quickDiffIEXml(c1, c2);
5200         }
5201         var d = ++key;
5202         for(var i = 0; i < len1; i++){
5203             c1[i]._qdiff = d;
5204         }
5205         var r = [];
5206         for(var i = 0, len = c2.length; i < len; i++){
5207             if(c2[i]._qdiff != d){
5208                 r[r.length] = c2[i];
5209             }
5210         }
5211         return r;
5212     }
5213
5214     function quickId(ns, mode, root, id){
5215         if(ns == root){
5216            var d = root.ownerDocument || root;
5217            return d.getElementById(id);
5218         }
5219         ns = getNodes(ns, mode, "*");
5220         return byId(ns, null, id);
5221     }
5222
5223     return {
5224         getStyle : function(el, name){
5225             return Roo.fly(el).getStyle(name);
5226         },
5227         /**
5228          * Compiles a selector/xpath query into a reusable function. The returned function
5229          * takes one parameter "root" (optional), which is the context node from where the query should start.
5230          * @param {String} selector The selector/xpath query
5231          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5232          * @return {Function}
5233          */
5234         compile : function(path, type){
5235             type = type || "select";
5236             
5237             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5238             var q = path, mode, lq;
5239             var tk = Roo.DomQuery.matchers;
5240             var tklen = tk.length;
5241             var mm;
5242
5243             // accept leading mode switch
5244             var lmode = q.match(modeRe);
5245             if(lmode && lmode[1]){
5246                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5247                 q = q.replace(lmode[1], "");
5248             }
5249             // strip leading slashes
5250             while(path.substr(0, 1)=="/"){
5251                 path = path.substr(1);
5252             }
5253
5254             while(q && lq != q){
5255                 lq = q;
5256                 var tm = q.match(tagTokenRe);
5257                 if(type == "select"){
5258                     if(tm){
5259                         if(tm[1] == "#"){
5260                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5261                         }else{
5262                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5263                         }
5264                         q = q.replace(tm[0], "");
5265                     }else if(q.substr(0, 1) != '@'){
5266                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5267                     }
5268                 }else{
5269                     if(tm){
5270                         if(tm[1] == "#"){
5271                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5272                         }else{
5273                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5274                         }
5275                         q = q.replace(tm[0], "");
5276                     }
5277                 }
5278                 while(!(mm = q.match(modeRe))){
5279                     var matched = false;
5280                     for(var j = 0; j < tklen; j++){
5281                         var t = tk[j];
5282                         var m = q.match(t.re);
5283                         if(m){
5284                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5285                                                     return m[i];
5286                                                 });
5287                             q = q.replace(m[0], "");
5288                             matched = true;
5289                             break;
5290                         }
5291                     }
5292                     // prevent infinite loop on bad selector
5293                     if(!matched){
5294                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5295                     }
5296                 }
5297                 if(mm[1]){
5298                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5299                     q = q.replace(mm[1], "");
5300                 }
5301             }
5302             fn[fn.length] = "return nodup(n);\n}";
5303             
5304              /** 
5305               * list of variables that need from compression as they are used by eval.
5306              *  eval:var:batch 
5307              *  eval:var:nodup
5308              *  eval:var:byTag
5309              *  eval:var:ById
5310              *  eval:var:getNodes
5311              *  eval:var:quickId
5312              *  eval:var:mode
5313              *  eval:var:root
5314              *  eval:var:n
5315              *  eval:var:byClassName
5316              *  eval:var:byPseudo
5317              *  eval:var:byAttribute
5318              *  eval:var:attrValue
5319              * 
5320              **/ 
5321             eval(fn.join(""));
5322             return f;
5323         },
5324
5325         /**
5326          * Selects a group of elements.
5327          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5328          * @param {Node} root (optional) The start of the query (defaults to document).
5329          * @return {Array}
5330          */
5331         select : function(path, root, type){
5332             if(!root || root == document){
5333                 root = document;
5334             }
5335             if(typeof root == "string"){
5336                 root = document.getElementById(root);
5337             }
5338             var paths = path.split(",");
5339             var results = [];
5340             for(var i = 0, len = paths.length; i < len; i++){
5341                 var p = paths[i].replace(trimRe, "");
5342                 if(!cache[p]){
5343                     cache[p] = Roo.DomQuery.compile(p);
5344                     if(!cache[p]){
5345                         throw p + " is not a valid selector";
5346                     }
5347                 }
5348                 var result = cache[p](root);
5349                 if(result && result != document){
5350                     results = results.concat(result);
5351                 }
5352             }
5353             if(paths.length > 1){
5354                 return nodup(results);
5355             }
5356             return results;
5357         },
5358
5359         /**
5360          * Selects a single element.
5361          * @param {String} selector The selector/xpath query
5362          * @param {Node} root (optional) The start of the query (defaults to document).
5363          * @return {Element}
5364          */
5365         selectNode : function(path, root){
5366             return Roo.DomQuery.select(path, root)[0];
5367         },
5368
5369         /**
5370          * Selects the value of a node, optionally replacing null with the defaultValue.
5371          * @param {String} selector The selector/xpath query
5372          * @param {Node} root (optional) The start of the query (defaults to document).
5373          * @param {String} defaultValue
5374          */
5375         selectValue : function(path, root, defaultValue){
5376             path = path.replace(trimRe, "");
5377             if(!valueCache[path]){
5378                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5379             }
5380             var n = valueCache[path](root);
5381             n = n[0] ? n[0] : n;
5382             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5383             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5384         },
5385
5386         /**
5387          * Selects the value of a node, parsing integers and floats.
5388          * @param {String} selector The selector/xpath query
5389          * @param {Node} root (optional) The start of the query (defaults to document).
5390          * @param {Number} defaultValue
5391          * @return {Number}
5392          */
5393         selectNumber : function(path, root, defaultValue){
5394             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5395             return parseFloat(v);
5396         },
5397
5398         /**
5399          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5400          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5401          * @param {String} selector The simple selector to test
5402          * @return {Boolean}
5403          */
5404         is : function(el, ss){
5405             if(typeof el == "string"){
5406                 el = document.getElementById(el);
5407             }
5408             var isArray = (el instanceof Array);
5409             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5410             return isArray ? (result.length == el.length) : (result.length > 0);
5411         },
5412
5413         /**
5414          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5415          * @param {Array} el An array of elements to filter
5416          * @param {String} selector The simple selector to test
5417          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5418          * the selector instead of the ones that match
5419          * @return {Array}
5420          */
5421         filter : function(els, ss, nonMatches){
5422             ss = ss.replace(trimRe, "");
5423             if(!simpleCache[ss]){
5424                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5425             }
5426             var result = simpleCache[ss](els);
5427             return nonMatches ? quickDiff(result, els) : result;
5428         },
5429
5430         /**
5431          * Collection of matching regular expressions and code snippets.
5432          */
5433         matchers : [{
5434                 re: /^\.([\w-]+)/,
5435                 select: 'n = byClassName(n, null, " {1} ");'
5436             }, {
5437                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5438                 select: 'n = byPseudo(n, "{1}", "{2}");'
5439             },{
5440                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5441                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5442             }, {
5443                 re: /^#([\w-]+)/,
5444                 select: 'n = byId(n, null, "{1}");'
5445             },{
5446                 re: /^@([\w-]+)/,
5447                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5448             }
5449         ],
5450
5451         /**
5452          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5453          * 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;.
5454          */
5455         operators : {
5456             "=" : function(a, v){
5457                 return a == v;
5458             },
5459             "!=" : function(a, v){
5460                 return a != v;
5461             },
5462             "^=" : function(a, v){
5463                 return a && a.substr(0, v.length) == v;
5464             },
5465             "$=" : function(a, v){
5466                 return a && a.substr(a.length-v.length) == v;
5467             },
5468             "*=" : function(a, v){
5469                 return a && a.indexOf(v) !== -1;
5470             },
5471             "%=" : function(a, v){
5472                 return (a % v) == 0;
5473             },
5474             "|=" : function(a, v){
5475                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5476             },
5477             "~=" : function(a, v){
5478                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5479             }
5480         },
5481
5482         /**
5483          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5484          * and the argument (if any) supplied in the selector.
5485          */
5486         pseudos : {
5487             "first-child" : function(c){
5488                 var r = [], ri = -1, n;
5489                 for(var i = 0, ci; ci = n = c[i]; i++){
5490                     while((n = n.previousSibling) && n.nodeType != 1);
5491                     if(!n){
5492                         r[++ri] = ci;
5493                     }
5494                 }
5495                 return r;
5496             },
5497
5498             "last-child" : function(c){
5499                 var r = [], ri = -1, n;
5500                 for(var i = 0, ci; ci = n = c[i]; i++){
5501                     while((n = n.nextSibling) && n.nodeType != 1);
5502                     if(!n){
5503                         r[++ri] = ci;
5504                     }
5505                 }
5506                 return r;
5507             },
5508
5509             "nth-child" : function(c, a) {
5510                 var r = [], ri = -1;
5511                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5512                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5513                 for(var i = 0, n; n = c[i]; i++){
5514                     var pn = n.parentNode;
5515                     if (batch != pn._batch) {
5516                         var j = 0;
5517                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5518                             if(cn.nodeType == 1){
5519                                cn.nodeIndex = ++j;
5520                             }
5521                         }
5522                         pn._batch = batch;
5523                     }
5524                     if (f == 1) {
5525                         if (l == 0 || n.nodeIndex == l){
5526                             r[++ri] = n;
5527                         }
5528                     } else if ((n.nodeIndex + l) % f == 0){
5529                         r[++ri] = n;
5530                     }
5531                 }
5532
5533                 return r;
5534             },
5535
5536             "only-child" : function(c){
5537                 var r = [], ri = -1;;
5538                 for(var i = 0, ci; ci = c[i]; i++){
5539                     if(!prev(ci) && !next(ci)){
5540                         r[++ri] = ci;
5541                     }
5542                 }
5543                 return r;
5544             },
5545
5546             "empty" : function(c){
5547                 var r = [], ri = -1;
5548                 for(var i = 0, ci; ci = c[i]; i++){
5549                     var cns = ci.childNodes, j = 0, cn, empty = true;
5550                     while(cn = cns[j]){
5551                         ++j;
5552                         if(cn.nodeType == 1 || cn.nodeType == 3){
5553                             empty = false;
5554                             break;
5555                         }
5556                     }
5557                     if(empty){
5558                         r[++ri] = ci;
5559                     }
5560                 }
5561                 return r;
5562             },
5563
5564             "contains" : function(c, v){
5565                 var r = [], ri = -1;
5566                 for(var i = 0, ci; ci = c[i]; i++){
5567                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5568                         r[++ri] = ci;
5569                     }
5570                 }
5571                 return r;
5572             },
5573
5574             "nodeValue" : function(c, v){
5575                 var r = [], ri = -1;
5576                 for(var i = 0, ci; ci = c[i]; i++){
5577                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5578                         r[++ri] = ci;
5579                     }
5580                 }
5581                 return r;
5582             },
5583
5584             "checked" : function(c){
5585                 var r = [], ri = -1;
5586                 for(var i = 0, ci; ci = c[i]; i++){
5587                     if(ci.checked == true){
5588                         r[++ri] = ci;
5589                     }
5590                 }
5591                 return r;
5592             },
5593
5594             "not" : function(c, ss){
5595                 return Roo.DomQuery.filter(c, ss, true);
5596             },
5597
5598             "odd" : function(c){
5599                 return this["nth-child"](c, "odd");
5600             },
5601
5602             "even" : function(c){
5603                 return this["nth-child"](c, "even");
5604             },
5605
5606             "nth" : function(c, a){
5607                 return c[a-1] || [];
5608             },
5609
5610             "first" : function(c){
5611                 return c[0] || [];
5612             },
5613
5614             "last" : function(c){
5615                 return c[c.length-1] || [];
5616             },
5617
5618             "has" : function(c, ss){
5619                 var s = Roo.DomQuery.select;
5620                 var r = [], ri = -1;
5621                 for(var i = 0, ci; ci = c[i]; i++){
5622                     if(s(ss, ci).length > 0){
5623                         r[++ri] = ci;
5624                     }
5625                 }
5626                 return r;
5627             },
5628
5629             "next" : function(c, ss){
5630                 var is = Roo.DomQuery.is;
5631                 var r = [], ri = -1;
5632                 for(var i = 0, ci; ci = c[i]; i++){
5633                     var n = next(ci);
5634                     if(n && is(n, ss)){
5635                         r[++ri] = ci;
5636                     }
5637                 }
5638                 return r;
5639             },
5640
5641             "prev" : function(c, ss){
5642                 var is = Roo.DomQuery.is;
5643                 var r = [], ri = -1;
5644                 for(var i = 0, ci; ci = c[i]; i++){
5645                     var n = prev(ci);
5646                     if(n && is(n, ss)){
5647                         r[++ri] = ci;
5648                     }
5649                 }
5650                 return r;
5651             }
5652         }
5653     };
5654 }();
5655
5656 /**
5657  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5658  * @param {String} path The selector/xpath query
5659  * @param {Node} root (optional) The start of the query (defaults to document).
5660  * @return {Array}
5661  * @member Roo
5662  * @method query
5663  */
5664 Roo.query = Roo.DomQuery.select;
5665 /*
5666  * Based on:
5667  * Ext JS Library 1.1.1
5668  * Copyright(c) 2006-2007, Ext JS, LLC.
5669  *
5670  * Originally Released Under LGPL - original licence link has changed is not relivant.
5671  *
5672  * Fork - LGPL
5673  * <script type="text/javascript">
5674  */
5675
5676 /**
5677  * @class Roo.util.Observable
5678  * Base class that provides a common interface for publishing events. Subclasses are expected to
5679  * to have a property "events" with all the events defined.<br>
5680  * For example:
5681  * <pre><code>
5682  Employee = function(name){
5683     this.name = name;
5684     this.addEvents({
5685         "fired" : true,
5686         "quit" : true
5687     });
5688  }
5689  Roo.extend(Employee, Roo.util.Observable);
5690 </code></pre>
5691  * @param {Object} config properties to use (incuding events / listeners)
5692  */
5693
5694 Roo.util.Observable = function(cfg){
5695     
5696     cfg = cfg|| {};
5697     this.addEvents(cfg.events || {});
5698     if (cfg.events) {
5699         delete cfg.events; // make sure
5700     }
5701      
5702     Roo.apply(this, cfg);
5703     
5704     if(this.listeners){
5705         this.on(this.listeners);
5706         delete this.listeners;
5707     }
5708 };
5709 Roo.util.Observable.prototype = {
5710     /** 
5711  * @cfg {Object} listeners  list of events and functions to call for this object, 
5712  * For example :
5713  * <pre><code>
5714     listeners :  { 
5715        'click' : function(e) {
5716            ..... 
5717         } ,
5718         .... 
5719     } 
5720   </code></pre>
5721  */
5722     
5723     
5724     /**
5725      * Fires the specified event with the passed parameters (minus the event name).
5726      * @param {String} eventName
5727      * @param {Object...} args Variable number of parameters are passed to handlers
5728      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5729      */
5730     fireEvent : function(){
5731         var ce = this.events[arguments[0].toLowerCase()];
5732         if(typeof ce == "object"){
5733             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5734         }else{
5735             return true;
5736         }
5737     },
5738
5739     // private
5740     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5741
5742     /**
5743      * Appends an event handler to this component
5744      * @param {String}   eventName The type of event to listen for
5745      * @param {Function} handler The method the event invokes
5746      * @param {Object}   scope (optional) The scope in which to execute the handler
5747      * function. The handler function's "this" context.
5748      * @param {Object}   options (optional) An object containing handler configuration
5749      * properties. This may contain any of the following properties:<ul>
5750      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5751      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5752      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5753      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5754      * by the specified number of milliseconds. If the event fires again within that time, the original
5755      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5756      * </ul><br>
5757      * <p>
5758      * <b>Combining Options</b><br>
5759      * Using the options argument, it is possible to combine different types of listeners:<br>
5760      * <br>
5761      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5762                 <pre><code>
5763                 el.on('click', this.onClick, this, {
5764                         single: true,
5765                 delay: 100,
5766                 forumId: 4
5767                 });
5768                 </code></pre>
5769      * <p>
5770      * <b>Attaching multiple handlers in 1 call</b><br>
5771      * The method also allows for a single argument to be passed which is a config object containing properties
5772      * which specify multiple handlers.
5773      * <pre><code>
5774                 el.on({
5775                         'click': {
5776                         fn: this.onClick,
5777                         scope: this,
5778                         delay: 100
5779                 }, 
5780                 'mouseover': {
5781                         fn: this.onMouseOver,
5782                         scope: this
5783                 },
5784                 'mouseout': {
5785                         fn: this.onMouseOut,
5786                         scope: this
5787                 }
5788                 });
5789                 </code></pre>
5790      * <p>
5791      * Or a shorthand syntax which passes the same scope object to all handlers:
5792         <pre><code>
5793                 el.on({
5794                         'click': this.onClick,
5795                 'mouseover': this.onMouseOver,
5796                 'mouseout': this.onMouseOut,
5797                 scope: this
5798                 });
5799                 </code></pre>
5800      */
5801     addListener : function(eventName, fn, scope, o){
5802         if(typeof eventName == "object"){
5803             o = eventName;
5804             for(var e in o){
5805                 if(this.filterOptRe.test(e)){
5806                     continue;
5807                 }
5808                 if(typeof o[e] == "function"){
5809                     // shared options
5810                     this.addListener(e, o[e], o.scope,  o);
5811                 }else{
5812                     // individual options
5813                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5814                 }
5815             }
5816             return;
5817         }
5818         o = (!o || typeof o == "boolean") ? {} : o;
5819         eventName = eventName.toLowerCase();
5820         var ce = this.events[eventName] || true;
5821         if(typeof ce == "boolean"){
5822             ce = new Roo.util.Event(this, eventName);
5823             this.events[eventName] = ce;
5824         }
5825         ce.addListener(fn, scope, o);
5826     },
5827
5828     /**
5829      * Removes a listener
5830      * @param {String}   eventName     The type of event to listen for
5831      * @param {Function} handler        The handler to remove
5832      * @param {Object}   scope  (optional) The scope (this object) for the handler
5833      */
5834     removeListener : function(eventName, fn, scope){
5835         var ce = this.events[eventName.toLowerCase()];
5836         if(typeof ce == "object"){
5837             ce.removeListener(fn, scope);
5838         }
5839     },
5840
5841     /**
5842      * Removes all listeners for this object
5843      */
5844     purgeListeners : function(){
5845         for(var evt in this.events){
5846             if(typeof this.events[evt] == "object"){
5847                  this.events[evt].clearListeners();
5848             }
5849         }
5850     },
5851
5852     relayEvents : function(o, events){
5853         var createHandler = function(ename){
5854             return function(){
5855                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5856             };
5857         };
5858         for(var i = 0, len = events.length; i < len; i++){
5859             var ename = events[i];
5860             if(!this.events[ename]){ this.events[ename] = true; };
5861             o.on(ename, createHandler(ename), this);
5862         }
5863     },
5864
5865     /**
5866      * Used to define events on this Observable
5867      * @param {Object} object The object with the events defined
5868      */
5869     addEvents : function(o){
5870         if(!this.events){
5871             this.events = {};
5872         }
5873         Roo.applyIf(this.events, o);
5874     },
5875
5876     /**
5877      * Checks to see if this object has any listeners for a specified event
5878      * @param {String} eventName The name of the event to check for
5879      * @return {Boolean} True if the event is being listened for, else false
5880      */
5881     hasListener : function(eventName){
5882         var e = this.events[eventName];
5883         return typeof e == "object" && e.listeners.length > 0;
5884     }
5885 };
5886 /**
5887  * Appends an event handler to this element (shorthand for addListener)
5888  * @param {String}   eventName     The type of event to listen for
5889  * @param {Function} handler        The method the event invokes
5890  * @param {Object}   scope (optional) The scope in which to execute the handler
5891  * function. The handler function's "this" context.
5892  * @param {Object}   options  (optional)
5893  * @method
5894  */
5895 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5896 /**
5897  * Removes a listener (shorthand for removeListener)
5898  * @param {String}   eventName     The type of event to listen for
5899  * @param {Function} handler        The handler to remove
5900  * @param {Object}   scope  (optional) The scope (this object) for the handler
5901  * @method
5902  */
5903 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5904
5905 /**
5906  * Starts capture on the specified Observable. All events will be passed
5907  * to the supplied function with the event name + standard signature of the event
5908  * <b>before</b> the event is fired. If the supplied function returns false,
5909  * the event will not fire.
5910  * @param {Observable} o The Observable to capture
5911  * @param {Function} fn The function to call
5912  * @param {Object} scope (optional) The scope (this object) for the fn
5913  * @static
5914  */
5915 Roo.util.Observable.capture = function(o, fn, scope){
5916     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5917 };
5918
5919 /**
5920  * Removes <b>all</b> added captures from the Observable.
5921  * @param {Observable} o The Observable to release
5922  * @static
5923  */
5924 Roo.util.Observable.releaseCapture = function(o){
5925     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5926 };
5927
5928 (function(){
5929
5930     var createBuffered = function(h, o, scope){
5931         var task = new Roo.util.DelayedTask();
5932         return function(){
5933             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5934         };
5935     };
5936
5937     var createSingle = function(h, e, fn, scope){
5938         return function(){
5939             e.removeListener(fn, scope);
5940             return h.apply(scope, arguments);
5941         };
5942     };
5943
5944     var createDelayed = function(h, o, scope){
5945         return function(){
5946             var args = Array.prototype.slice.call(arguments, 0);
5947             setTimeout(function(){
5948                 h.apply(scope, args);
5949             }, o.delay || 10);
5950         };
5951     };
5952
5953     Roo.util.Event = function(obj, name){
5954         this.name = name;
5955         this.obj = obj;
5956         this.listeners = [];
5957     };
5958
5959     Roo.util.Event.prototype = {
5960         addListener : function(fn, scope, options){
5961             var o = options || {};
5962             scope = scope || this.obj;
5963             if(!this.isListening(fn, scope)){
5964                 var l = {fn: fn, scope: scope, options: o};
5965                 var h = fn;
5966                 if(o.delay){
5967                     h = createDelayed(h, o, scope);
5968                 }
5969                 if(o.single){
5970                     h = createSingle(h, this, fn, scope);
5971                 }
5972                 if(o.buffer){
5973                     h = createBuffered(h, o, scope);
5974                 }
5975                 l.fireFn = h;
5976                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5977                     this.listeners.push(l);
5978                 }else{
5979                     this.listeners = this.listeners.slice(0);
5980                     this.listeners.push(l);
5981                 }
5982             }
5983         },
5984
5985         findListener : function(fn, scope){
5986             scope = scope || this.obj;
5987             var ls = this.listeners;
5988             for(var i = 0, len = ls.length; i < len; i++){
5989                 var l = ls[i];
5990                 if(l.fn == fn && l.scope == scope){
5991                     return i;
5992                 }
5993             }
5994             return -1;
5995         },
5996
5997         isListening : function(fn, scope){
5998             return this.findListener(fn, scope) != -1;
5999         },
6000
6001         removeListener : function(fn, scope){
6002             var index;
6003             if((index = this.findListener(fn, scope)) != -1){
6004                 if(!this.firing){
6005                     this.listeners.splice(index, 1);
6006                 }else{
6007                     this.listeners = this.listeners.slice(0);
6008                     this.listeners.splice(index, 1);
6009                 }
6010                 return true;
6011             }
6012             return false;
6013         },
6014
6015         clearListeners : function(){
6016             this.listeners = [];
6017         },
6018
6019         fire : function(){
6020             var ls = this.listeners, scope, len = ls.length;
6021             if(len > 0){
6022                 this.firing = true;
6023                 var args = Array.prototype.slice.call(arguments, 0);
6024                 for(var i = 0; i < len; i++){
6025                     var l = ls[i];
6026                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6027                         this.firing = false;
6028                         return false;
6029                     }
6030                 }
6031                 this.firing = false;
6032             }
6033             return true;
6034         }
6035     };
6036 })();/*
6037  * Based on:
6038  * Ext JS Library 1.1.1
6039  * Copyright(c) 2006-2007, Ext JS, LLC.
6040  *
6041  * Originally Released Under LGPL - original licence link has changed is not relivant.
6042  *
6043  * Fork - LGPL
6044  * <script type="text/javascript">
6045  */
6046
6047 /**
6048  * @class Roo.EventManager
6049  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6050  * several useful events directly.
6051  * See {@link Roo.EventObject} for more details on normalized event objects.
6052  * @singleton
6053  */
6054 Roo.EventManager = function(){
6055     var docReadyEvent, docReadyProcId, docReadyState = false;
6056     var resizeEvent, resizeTask, textEvent, textSize;
6057     var E = Roo.lib.Event;
6058     var D = Roo.lib.Dom;
6059
6060     
6061     
6062
6063     var fireDocReady = function(){
6064         if(!docReadyState){
6065             docReadyState = true;
6066             Roo.isReady = true;
6067             if(docReadyProcId){
6068                 clearInterval(docReadyProcId);
6069             }
6070             if(Roo.isGecko || Roo.isOpera) {
6071                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6072             }
6073             if(Roo.isIE){
6074                 var defer = document.getElementById("ie-deferred-loader");
6075                 if(defer){
6076                     defer.onreadystatechange = null;
6077                     defer.parentNode.removeChild(defer);
6078                 }
6079             }
6080             if(docReadyEvent){
6081                 docReadyEvent.fire();
6082                 docReadyEvent.clearListeners();
6083             }
6084         }
6085     };
6086     
6087     var initDocReady = function(){
6088         docReadyEvent = new Roo.util.Event();
6089         if(Roo.isGecko || Roo.isOpera) {
6090             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6091         }else if(Roo.isIE){
6092             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6093             var defer = document.getElementById("ie-deferred-loader");
6094             defer.onreadystatechange = function(){
6095                 if(this.readyState == "complete"){
6096                     fireDocReady();
6097                 }
6098             };
6099         }else if(Roo.isSafari){ 
6100             docReadyProcId = setInterval(function(){
6101                 var rs = document.readyState;
6102                 if(rs == "complete") {
6103                     fireDocReady();     
6104                  }
6105             }, 10);
6106         }
6107         // no matter what, make sure it fires on load
6108         E.on(window, "load", fireDocReady);
6109     };
6110
6111     var createBuffered = function(h, o){
6112         var task = new Roo.util.DelayedTask(h);
6113         return function(e){
6114             // create new event object impl so new events don't wipe out properties
6115             e = new Roo.EventObjectImpl(e);
6116             task.delay(o.buffer, h, null, [e]);
6117         };
6118     };
6119
6120     var createSingle = function(h, el, ename, fn){
6121         return function(e){
6122             Roo.EventManager.removeListener(el, ename, fn);
6123             h(e);
6124         };
6125     };
6126
6127     var createDelayed = function(h, o){
6128         return function(e){
6129             // create new event object impl so new events don't wipe out properties
6130             e = new Roo.EventObjectImpl(e);
6131             setTimeout(function(){
6132                 h(e);
6133             }, o.delay || 10);
6134         };
6135     };
6136     var transitionEndVal = false;
6137     
6138     var transitionEnd = function()
6139     {
6140         if (transitionEndVal) {
6141             return transitionEndVal;
6142         }
6143         var el = document.createElement('div');
6144
6145         var transEndEventNames = {
6146             WebkitTransition : 'webkitTransitionEnd',
6147             MozTransition    : 'transitionend',
6148             OTransition      : 'oTransitionEnd otransitionend',
6149             transition       : 'transitionend'
6150         };
6151     
6152         for (var name in transEndEventNames) {
6153             if (el.style[name] !== undefined) {
6154                 transitionEndVal = transEndEventNames[name];
6155                 return  transitionEndVal ;
6156             }
6157         }
6158     }
6159     
6160
6161     var listen = function(element, ename, opt, fn, scope){
6162         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6163         fn = fn || o.fn; scope = scope || o.scope;
6164         var el = Roo.getDom(element);
6165         
6166         
6167         if(!el){
6168             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6169         }
6170         
6171         if (ename == 'transitionend') {
6172             ename = transitionEnd();
6173         }
6174         var h = function(e){
6175             e = Roo.EventObject.setEvent(e);
6176             var t;
6177             if(o.delegate){
6178                 t = e.getTarget(o.delegate, el);
6179                 if(!t){
6180                     return;
6181                 }
6182             }else{
6183                 t = e.target;
6184             }
6185             if(o.stopEvent === true){
6186                 e.stopEvent();
6187             }
6188             if(o.preventDefault === true){
6189                e.preventDefault();
6190             }
6191             if(o.stopPropagation === true){
6192                 e.stopPropagation();
6193             }
6194
6195             if(o.normalized === false){
6196                 e = e.browserEvent;
6197             }
6198
6199             fn.call(scope || el, e, t, o);
6200         };
6201         if(o.delay){
6202             h = createDelayed(h, o);
6203         }
6204         if(o.single){
6205             h = createSingle(h, el, ename, fn);
6206         }
6207         if(o.buffer){
6208             h = createBuffered(h, o);
6209         }
6210         fn._handlers = fn._handlers || [];
6211         
6212         
6213         fn._handlers.push([Roo.id(el), ename, h]);
6214         
6215         
6216          
6217         E.on(el, ename, h);
6218         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6219             el.addEventListener("DOMMouseScroll", h, false);
6220             E.on(window, 'unload', function(){
6221                 el.removeEventListener("DOMMouseScroll", h, false);
6222             });
6223         }
6224         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6225             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6226         }
6227         return h;
6228     };
6229
6230     var stopListening = function(el, ename, fn){
6231         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6232         if(hds){
6233             for(var i = 0, len = hds.length; i < len; i++){
6234                 var h = hds[i];
6235                 if(h[0] == id && h[1] == ename){
6236                     hd = h[2];
6237                     hds.splice(i, 1);
6238                     break;
6239                 }
6240             }
6241         }
6242         E.un(el, ename, hd);
6243         el = Roo.getDom(el);
6244         if(ename == "mousewheel" && el.addEventListener){
6245             el.removeEventListener("DOMMouseScroll", hd, false);
6246         }
6247         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6248             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6249         }
6250     };
6251
6252     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6253     
6254     var pub = {
6255         
6256         
6257         /** 
6258          * Fix for doc tools
6259          * @scope Roo.EventManager
6260          */
6261         
6262         
6263         /** 
6264          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6265          * object with a Roo.EventObject
6266          * @param {Function} fn        The method the event invokes
6267          * @param {Object}   scope    An object that becomes the scope of the handler
6268          * @param {boolean}  override If true, the obj passed in becomes
6269          *                             the execution scope of the listener
6270          * @return {Function} The wrapped function
6271          * @deprecated
6272          */
6273         wrap : function(fn, scope, override){
6274             return function(e){
6275                 Roo.EventObject.setEvent(e);
6276                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6277             };
6278         },
6279         
6280         /**
6281      * Appends an event handler to an element (shorthand for addListener)
6282      * @param {String/HTMLElement}   element        The html element or id to assign the
6283      * @param {String}   eventName The type of event to listen for
6284      * @param {Function} handler The method the event invokes
6285      * @param {Object}   scope (optional) The scope in which to execute the handler
6286      * function. The handler function's "this" context.
6287      * @param {Object}   options (optional) An object containing handler configuration
6288      * properties. This may contain any of the following properties:<ul>
6289      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6290      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6291      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6292      * <li>preventDefault {Boolean} True to prevent the default action</li>
6293      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6294      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6295      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6296      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6297      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6298      * by the specified number of milliseconds. If the event fires again within that time, the original
6299      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6300      * </ul><br>
6301      * <p>
6302      * <b>Combining Options</b><br>
6303      * Using the options argument, it is possible to combine different types of listeners:<br>
6304      * <br>
6305      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6306      * Code:<pre><code>
6307 el.on('click', this.onClick, this, {
6308     single: true,
6309     delay: 100,
6310     stopEvent : true,
6311     forumId: 4
6312 });</code></pre>
6313      * <p>
6314      * <b>Attaching multiple handlers in 1 call</b><br>
6315       * The method also allows for a single argument to be passed which is a config object containing properties
6316      * which specify multiple handlers.
6317      * <p>
6318      * Code:<pre><code>
6319 el.on({
6320     'click' : {
6321         fn: this.onClick
6322         scope: this,
6323         delay: 100
6324     },
6325     'mouseover' : {
6326         fn: this.onMouseOver
6327         scope: this
6328     },
6329     'mouseout' : {
6330         fn: this.onMouseOut
6331         scope: this
6332     }
6333 });</code></pre>
6334      * <p>
6335      * Or a shorthand syntax:<br>
6336      * Code:<pre><code>
6337 el.on({
6338     'click' : this.onClick,
6339     'mouseover' : this.onMouseOver,
6340     'mouseout' : this.onMouseOut
6341     scope: this
6342 });</code></pre>
6343      */
6344         addListener : function(element, eventName, fn, scope, options){
6345             if(typeof eventName == "object"){
6346                 var o = eventName;
6347                 for(var e in o){
6348                     if(propRe.test(e)){
6349                         continue;
6350                     }
6351                     if(typeof o[e] == "function"){
6352                         // shared options
6353                         listen(element, e, o, o[e], o.scope);
6354                     }else{
6355                         // individual options
6356                         listen(element, e, o[e]);
6357                     }
6358                 }
6359                 return;
6360             }
6361             return listen(element, eventName, options, fn, scope);
6362         },
6363         
6364         /**
6365          * Removes an event handler
6366          *
6367          * @param {String/HTMLElement}   element        The id or html element to remove the 
6368          *                             event from
6369          * @param {String}   eventName     The type of event
6370          * @param {Function} fn
6371          * @return {Boolean} True if a listener was actually removed
6372          */
6373         removeListener : function(element, eventName, fn){
6374             return stopListening(element, eventName, fn);
6375         },
6376         
6377         /**
6378          * Fires when the document is ready (before onload and before images are loaded). Can be 
6379          * accessed shorthanded Roo.onReady().
6380          * @param {Function} fn        The method the event invokes
6381          * @param {Object}   scope    An  object that becomes the scope of the handler
6382          * @param {boolean}  options
6383          */
6384         onDocumentReady : function(fn, scope, options){
6385             if(docReadyState){ // if it already fired
6386                 docReadyEvent.addListener(fn, scope, options);
6387                 docReadyEvent.fire();
6388                 docReadyEvent.clearListeners();
6389                 return;
6390             }
6391             if(!docReadyEvent){
6392                 initDocReady();
6393             }
6394             docReadyEvent.addListener(fn, scope, options);
6395         },
6396         
6397         /**
6398          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6399          * @param {Function} fn        The method the event invokes
6400          * @param {Object}   scope    An object that becomes the scope of the handler
6401          * @param {boolean}  options
6402          */
6403         onWindowResize : function(fn, scope, options){
6404             if(!resizeEvent){
6405                 resizeEvent = new Roo.util.Event();
6406                 resizeTask = new Roo.util.DelayedTask(function(){
6407                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6408                 });
6409                 E.on(window, "resize", function(){
6410                     if(Roo.isIE){
6411                         resizeTask.delay(50);
6412                     }else{
6413                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6414                     }
6415                 });
6416             }
6417             resizeEvent.addListener(fn, scope, options);
6418         },
6419
6420         /**
6421          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6422          * @param {Function} fn        The method the event invokes
6423          * @param {Object}   scope    An object that becomes the scope of the handler
6424          * @param {boolean}  options
6425          */
6426         onTextResize : function(fn, scope, options){
6427             if(!textEvent){
6428                 textEvent = new Roo.util.Event();
6429                 var textEl = new Roo.Element(document.createElement('div'));
6430                 textEl.dom.className = 'x-text-resize';
6431                 textEl.dom.innerHTML = 'X';
6432                 textEl.appendTo(document.body);
6433                 textSize = textEl.dom.offsetHeight;
6434                 setInterval(function(){
6435                     if(textEl.dom.offsetHeight != textSize){
6436                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6437                     }
6438                 }, this.textResizeInterval);
6439             }
6440             textEvent.addListener(fn, scope, options);
6441         },
6442
6443         /**
6444          * Removes the passed window resize listener.
6445          * @param {Function} fn        The method the event invokes
6446          * @param {Object}   scope    The scope of handler
6447          */
6448         removeResizeListener : function(fn, scope){
6449             if(resizeEvent){
6450                 resizeEvent.removeListener(fn, scope);
6451             }
6452         },
6453
6454         // private
6455         fireResize : function(){
6456             if(resizeEvent){
6457                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6458             }   
6459         },
6460         /**
6461          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6462          */
6463         ieDeferSrc : false,
6464         /**
6465          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6466          */
6467         textResizeInterval : 50
6468     };
6469     
6470     /**
6471      * Fix for doc tools
6472      * @scopeAlias pub=Roo.EventManager
6473      */
6474     
6475      /**
6476      * Appends an event handler to an element (shorthand for addListener)
6477      * @param {String/HTMLElement}   element        The html element or id to assign the
6478      * @param {String}   eventName The type of event to listen for
6479      * @param {Function} handler The method the event invokes
6480      * @param {Object}   scope (optional) The scope in which to execute the handler
6481      * function. The handler function's "this" context.
6482      * @param {Object}   options (optional) An object containing handler configuration
6483      * properties. This may contain any of the following properties:<ul>
6484      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6485      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6486      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6487      * <li>preventDefault {Boolean} True to prevent the default action</li>
6488      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6489      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6490      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6491      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6492      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6493      * by the specified number of milliseconds. If the event fires again within that time, the original
6494      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6495      * </ul><br>
6496      * <p>
6497      * <b>Combining Options</b><br>
6498      * Using the options argument, it is possible to combine different types of listeners:<br>
6499      * <br>
6500      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6501      * Code:<pre><code>
6502 el.on('click', this.onClick, this, {
6503     single: true,
6504     delay: 100,
6505     stopEvent : true,
6506     forumId: 4
6507 });</code></pre>
6508      * <p>
6509      * <b>Attaching multiple handlers in 1 call</b><br>
6510       * The method also allows for a single argument to be passed which is a config object containing properties
6511      * which specify multiple handlers.
6512      * <p>
6513      * Code:<pre><code>
6514 el.on({
6515     'click' : {
6516         fn: this.onClick
6517         scope: this,
6518         delay: 100
6519     },
6520     'mouseover' : {
6521         fn: this.onMouseOver
6522         scope: this
6523     },
6524     'mouseout' : {
6525         fn: this.onMouseOut
6526         scope: this
6527     }
6528 });</code></pre>
6529      * <p>
6530      * Or a shorthand syntax:<br>
6531      * Code:<pre><code>
6532 el.on({
6533     'click' : this.onClick,
6534     'mouseover' : this.onMouseOver,
6535     'mouseout' : this.onMouseOut
6536     scope: this
6537 });</code></pre>
6538      */
6539     pub.on = pub.addListener;
6540     pub.un = pub.removeListener;
6541
6542     pub.stoppedMouseDownEvent = new Roo.util.Event();
6543     return pub;
6544 }();
6545 /**
6546   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6547   * @param {Function} fn        The method the event invokes
6548   * @param {Object}   scope    An  object that becomes the scope of the handler
6549   * @param {boolean}  override If true, the obj passed in becomes
6550   *                             the execution scope of the listener
6551   * @member Roo
6552   * @method onReady
6553  */
6554 Roo.onReady = Roo.EventManager.onDocumentReady;
6555
6556 Roo.onReady(function(){
6557     var bd = Roo.get(document.body);
6558     if(!bd){ return; }
6559
6560     var cls = [
6561             Roo.isIE ? "roo-ie"
6562             : Roo.isGecko ? "roo-gecko"
6563             : Roo.isOpera ? "roo-opera"
6564             : Roo.isSafari ? "roo-safari" : ""];
6565
6566     if(Roo.isMac){
6567         cls.push("roo-mac");
6568     }
6569     if(Roo.isLinux){
6570         cls.push("roo-linux");
6571     }
6572     if(Roo.isBorderBox){
6573         cls.push('roo-border-box');
6574     }
6575     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6576         var p = bd.dom.parentNode;
6577         if(p){
6578             p.className += ' roo-strict';
6579         }
6580     }
6581     bd.addClass(cls.join(' '));
6582 });
6583
6584 /**
6585  * @class Roo.EventObject
6586  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6587  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6588  * Example:
6589  * <pre><code>
6590  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6591     e.preventDefault();
6592     var target = e.getTarget();
6593     ...
6594  }
6595  var myDiv = Roo.get("myDiv");
6596  myDiv.on("click", handleClick);
6597  //or
6598  Roo.EventManager.on("myDiv", 'click', handleClick);
6599  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6600  </code></pre>
6601  * @singleton
6602  */
6603 Roo.EventObject = function(){
6604     
6605     var E = Roo.lib.Event;
6606     
6607     // safari keypress events for special keys return bad keycodes
6608     var safariKeys = {
6609         63234 : 37, // left
6610         63235 : 39, // right
6611         63232 : 38, // up
6612         63233 : 40, // down
6613         63276 : 33, // page up
6614         63277 : 34, // page down
6615         63272 : 46, // delete
6616         63273 : 36, // home
6617         63275 : 35  // end
6618     };
6619
6620     // normalize button clicks
6621     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6622                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6623
6624     Roo.EventObjectImpl = function(e){
6625         if(e){
6626             this.setEvent(e.browserEvent || e);
6627         }
6628     };
6629     Roo.EventObjectImpl.prototype = {
6630         /**
6631          * Used to fix doc tools.
6632          * @scope Roo.EventObject.prototype
6633          */
6634             
6635
6636         
6637         
6638         /** The normal browser event */
6639         browserEvent : null,
6640         /** The button pressed in a mouse event */
6641         button : -1,
6642         /** True if the shift key was down during the event */
6643         shiftKey : false,
6644         /** True if the control key was down during the event */
6645         ctrlKey : false,
6646         /** True if the alt key was down during the event */
6647         altKey : false,
6648
6649         /** Key constant 
6650         * @type Number */
6651         BACKSPACE : 8,
6652         /** Key constant 
6653         * @type Number */
6654         TAB : 9,
6655         /** Key constant 
6656         * @type Number */
6657         RETURN : 13,
6658         /** Key constant 
6659         * @type Number */
6660         ENTER : 13,
6661         /** Key constant 
6662         * @type Number */
6663         SHIFT : 16,
6664         /** Key constant 
6665         * @type Number */
6666         CONTROL : 17,
6667         /** Key constant 
6668         * @type Number */
6669         ESC : 27,
6670         /** Key constant 
6671         * @type Number */
6672         SPACE : 32,
6673         /** Key constant 
6674         * @type Number */
6675         PAGEUP : 33,
6676         /** Key constant 
6677         * @type Number */
6678         PAGEDOWN : 34,
6679         /** Key constant 
6680         * @type Number */
6681         END : 35,
6682         /** Key constant 
6683         * @type Number */
6684         HOME : 36,
6685         /** Key constant 
6686         * @type Number */
6687         LEFT : 37,
6688         /** Key constant 
6689         * @type Number */
6690         UP : 38,
6691         /** Key constant 
6692         * @type Number */
6693         RIGHT : 39,
6694         /** Key constant 
6695         * @type Number */
6696         DOWN : 40,
6697         /** Key constant 
6698         * @type Number */
6699         DELETE : 46,
6700         /** Key constant 
6701         * @type Number */
6702         F5 : 116,
6703
6704            /** @private */
6705         setEvent : function(e){
6706             if(e == this || (e && e.browserEvent)){ // already wrapped
6707                 return e;
6708             }
6709             this.browserEvent = e;
6710             if(e){
6711                 // normalize buttons
6712                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6713                 if(e.type == 'click' && this.button == -1){
6714                     this.button = 0;
6715                 }
6716                 this.type = e.type;
6717                 this.shiftKey = e.shiftKey;
6718                 // mac metaKey behaves like ctrlKey
6719                 this.ctrlKey = e.ctrlKey || e.metaKey;
6720                 this.altKey = e.altKey;
6721                 // in getKey these will be normalized for the mac
6722                 this.keyCode = e.keyCode;
6723                 // keyup warnings on firefox.
6724                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6725                 // cache the target for the delayed and or buffered events
6726                 this.target = E.getTarget(e);
6727                 // same for XY
6728                 this.xy = E.getXY(e);
6729             }else{
6730                 this.button = -1;
6731                 this.shiftKey = false;
6732                 this.ctrlKey = false;
6733                 this.altKey = false;
6734                 this.keyCode = 0;
6735                 this.charCode =0;
6736                 this.target = null;
6737                 this.xy = [0, 0];
6738             }
6739             return this;
6740         },
6741
6742         /**
6743          * Stop the event (preventDefault and stopPropagation)
6744          */
6745         stopEvent : function(){
6746             if(this.browserEvent){
6747                 if(this.browserEvent.type == 'mousedown'){
6748                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6749                 }
6750                 E.stopEvent(this.browserEvent);
6751             }
6752         },
6753
6754         /**
6755          * Prevents the browsers default handling of the event.
6756          */
6757         preventDefault : function(){
6758             if(this.browserEvent){
6759                 E.preventDefault(this.browserEvent);
6760             }
6761         },
6762
6763         /** @private */
6764         isNavKeyPress : function(){
6765             var k = this.keyCode;
6766             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6767             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6768         },
6769
6770         isSpecialKey : function(){
6771             var k = this.keyCode;
6772             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6773             (k == 16) || (k == 17) ||
6774             (k >= 18 && k <= 20) ||
6775             (k >= 33 && k <= 35) ||
6776             (k >= 36 && k <= 39) ||
6777             (k >= 44 && k <= 45);
6778         },
6779         /**
6780          * Cancels bubbling of the event.
6781          */
6782         stopPropagation : function(){
6783             if(this.browserEvent){
6784                 if(this.type == 'mousedown'){
6785                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6786                 }
6787                 E.stopPropagation(this.browserEvent);
6788             }
6789         },
6790
6791         /**
6792          * Gets the key code for the event.
6793          * @return {Number}
6794          */
6795         getCharCode : function(){
6796             return this.charCode || this.keyCode;
6797         },
6798
6799         /**
6800          * Returns a normalized keyCode for the event.
6801          * @return {Number} The key code
6802          */
6803         getKey : function(){
6804             var k = this.keyCode || this.charCode;
6805             return Roo.isSafari ? (safariKeys[k] || k) : k;
6806         },
6807
6808         /**
6809          * Gets the x coordinate of the event.
6810          * @return {Number}
6811          */
6812         getPageX : function(){
6813             return this.xy[0];
6814         },
6815
6816         /**
6817          * Gets the y coordinate of the event.
6818          * @return {Number}
6819          */
6820         getPageY : function(){
6821             return this.xy[1];
6822         },
6823
6824         /**
6825          * Gets the time of the event.
6826          * @return {Number}
6827          */
6828         getTime : function(){
6829             if(this.browserEvent){
6830                 return E.getTime(this.browserEvent);
6831             }
6832             return null;
6833         },
6834
6835         /**
6836          * Gets the page coordinates of the event.
6837          * @return {Array} The xy values like [x, y]
6838          */
6839         getXY : function(){
6840             return this.xy;
6841         },
6842
6843         /**
6844          * Gets the target for the event.
6845          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6846          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6847                 search as a number or element (defaults to 10 || document.body)
6848          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6849          * @return {HTMLelement}
6850          */
6851         getTarget : function(selector, maxDepth, returnEl){
6852             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6853         },
6854         /**
6855          * Gets the related target.
6856          * @return {HTMLElement}
6857          */
6858         getRelatedTarget : function(){
6859             if(this.browserEvent){
6860                 return E.getRelatedTarget(this.browserEvent);
6861             }
6862             return null;
6863         },
6864
6865         /**
6866          * Normalizes mouse wheel delta across browsers
6867          * @return {Number} The delta
6868          */
6869         getWheelDelta : function(){
6870             var e = this.browserEvent;
6871             var delta = 0;
6872             if(e.wheelDelta){ /* IE/Opera. */
6873                 delta = e.wheelDelta/120;
6874             }else if(e.detail){ /* Mozilla case. */
6875                 delta = -e.detail/3;
6876             }
6877             return delta;
6878         },
6879
6880         /**
6881          * Returns true if the control, meta, shift or alt key was pressed during this event.
6882          * @return {Boolean}
6883          */
6884         hasModifier : function(){
6885             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6886         },
6887
6888         /**
6889          * Returns true if the target of this event equals el or is a child of el
6890          * @param {String/HTMLElement/Element} el
6891          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6892          * @return {Boolean}
6893          */
6894         within : function(el, related){
6895             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6896             return t && Roo.fly(el).contains(t);
6897         },
6898
6899         getPoint : function(){
6900             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6901         }
6902     };
6903
6904     return new Roo.EventObjectImpl();
6905 }();
6906             
6907     /*
6908  * Based on:
6909  * Ext JS Library 1.1.1
6910  * Copyright(c) 2006-2007, Ext JS, LLC.
6911  *
6912  * Originally Released Under LGPL - original licence link has changed is not relivant.
6913  *
6914  * Fork - LGPL
6915  * <script type="text/javascript">
6916  */
6917
6918  
6919 // was in Composite Element!??!?!
6920  
6921 (function(){
6922     var D = Roo.lib.Dom;
6923     var E = Roo.lib.Event;
6924     var A = Roo.lib.Anim;
6925
6926     // local style camelizing for speed
6927     var propCache = {};
6928     var camelRe = /(-[a-z])/gi;
6929     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6930     var view = document.defaultView;
6931
6932 /**
6933  * @class Roo.Element
6934  * Represents an Element in the DOM.<br><br>
6935  * Usage:<br>
6936 <pre><code>
6937 var el = Roo.get("my-div");
6938
6939 // or with getEl
6940 var el = getEl("my-div");
6941
6942 // or with a DOM element
6943 var el = Roo.get(myDivElement);
6944 </code></pre>
6945  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6946  * each call instead of constructing a new one.<br><br>
6947  * <b>Animations</b><br />
6948  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6949  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6950 <pre>
6951 Option    Default   Description
6952 --------- --------  ---------------------------------------------
6953 duration  .35       The duration of the animation in seconds
6954 easing    easeOut   The YUI easing method
6955 callback  none      A function to execute when the anim completes
6956 scope     this      The scope (this) of the callback function
6957 </pre>
6958 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6959 * manipulate the animation. Here's an example:
6960 <pre><code>
6961 var el = Roo.get("my-div");
6962
6963 // no animation
6964 el.setWidth(100);
6965
6966 // default animation
6967 el.setWidth(100, true);
6968
6969 // animation with some options set
6970 el.setWidth(100, {
6971     duration: 1,
6972     callback: this.foo,
6973     scope: this
6974 });
6975
6976 // using the "anim" property to get the Anim object
6977 var opt = {
6978     duration: 1,
6979     callback: this.foo,
6980     scope: this
6981 };
6982 el.setWidth(100, opt);
6983 ...
6984 if(opt.anim.isAnimated()){
6985     opt.anim.stop();
6986 }
6987 </code></pre>
6988 * <b> Composite (Collections of) Elements</b><br />
6989  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
6990  * @constructor Create a new Element directly.
6991  * @param {String/HTMLElement} element
6992  * @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).
6993  */
6994     Roo.Element = function(element, forceNew){
6995         var dom = typeof element == "string" ?
6996                 document.getElementById(element) : element;
6997         if(!dom){ // invalid id/element
6998             return null;
6999         }
7000         var id = dom.id;
7001         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7002             return Roo.Element.cache[id];
7003         }
7004
7005         /**
7006          * The DOM element
7007          * @type HTMLElement
7008          */
7009         this.dom = dom;
7010
7011         /**
7012          * The DOM element ID
7013          * @type String
7014          */
7015         this.id = id || Roo.id(dom);
7016     };
7017
7018     var El = Roo.Element;
7019
7020     El.prototype = {
7021         /**
7022          * The element's default display mode  (defaults to "")
7023          * @type String
7024          */
7025         originalDisplay : "",
7026
7027         visibilityMode : 1,
7028         /**
7029          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7030          * @type String
7031          */
7032         defaultUnit : "px",
7033         /**
7034          * Sets the element's visibility mode. When setVisible() is called it
7035          * will use this to determine whether to set the visibility or the display property.
7036          * @param visMode Element.VISIBILITY or Element.DISPLAY
7037          * @return {Roo.Element} this
7038          */
7039         setVisibilityMode : function(visMode){
7040             this.visibilityMode = visMode;
7041             return this;
7042         },
7043         /**
7044          * Convenience method for setVisibilityMode(Element.DISPLAY)
7045          * @param {String} display (optional) What to set display to when visible
7046          * @return {Roo.Element} this
7047          */
7048         enableDisplayMode : function(display){
7049             this.setVisibilityMode(El.DISPLAY);
7050             if(typeof display != "undefined") this.originalDisplay = display;
7051             return this;
7052         },
7053
7054         /**
7055          * 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)
7056          * @param {String} selector The simple selector to test
7057          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7058                 search as a number or element (defaults to 10 || document.body)
7059          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7060          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7061          */
7062         findParent : function(simpleSelector, maxDepth, returnEl){
7063             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7064             maxDepth = maxDepth || 50;
7065             if(typeof maxDepth != "number"){
7066                 stopEl = Roo.getDom(maxDepth);
7067                 maxDepth = 10;
7068             }
7069             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7070                 if(dq.is(p, simpleSelector)){
7071                     return returnEl ? Roo.get(p) : p;
7072                 }
7073                 depth++;
7074                 p = p.parentNode;
7075             }
7076             return null;
7077         },
7078
7079
7080         /**
7081          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7082          * @param {String} selector The simple selector to test
7083          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7084                 search as a number or element (defaults to 10 || document.body)
7085          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7086          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7087          */
7088         findParentNode : function(simpleSelector, maxDepth, returnEl){
7089             var p = Roo.fly(this.dom.parentNode, '_internal');
7090             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7091         },
7092
7093         /**
7094          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7095          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7096          * @param {String} selector The simple selector to test
7097          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7098                 search as a number or element (defaults to 10 || document.body)
7099          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7100          */
7101         up : function(simpleSelector, maxDepth){
7102             return this.findParentNode(simpleSelector, maxDepth, true);
7103         },
7104
7105
7106
7107         /**
7108          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7109          * @param {String} selector The simple selector to test
7110          * @return {Boolean} True if this element matches the selector, else false
7111          */
7112         is : function(simpleSelector){
7113             return Roo.DomQuery.is(this.dom, simpleSelector);
7114         },
7115
7116         /**
7117          * Perform animation on this element.
7118          * @param {Object} args The YUI animation control args
7119          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7120          * @param {Function} onComplete (optional) Function to call when animation completes
7121          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7122          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7123          * @return {Roo.Element} this
7124          */
7125         animate : function(args, duration, onComplete, easing, animType){
7126             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7127             return this;
7128         },
7129
7130         /*
7131          * @private Internal animation call
7132          */
7133         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7134             animType = animType || 'run';
7135             opt = opt || {};
7136             var anim = Roo.lib.Anim[animType](
7137                 this.dom, args,
7138                 (opt.duration || defaultDur) || .35,
7139                 (opt.easing || defaultEase) || 'easeOut',
7140                 function(){
7141                     Roo.callback(cb, this);
7142                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7143                 },
7144                 this
7145             );
7146             opt.anim = anim;
7147             return anim;
7148         },
7149
7150         // private legacy anim prep
7151         preanim : function(a, i){
7152             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7153         },
7154
7155         /**
7156          * Removes worthless text nodes
7157          * @param {Boolean} forceReclean (optional) By default the element
7158          * keeps track if it has been cleaned already so
7159          * you can call this over and over. However, if you update the element and
7160          * need to force a reclean, you can pass true.
7161          */
7162         clean : function(forceReclean){
7163             if(this.isCleaned && forceReclean !== true){
7164                 return this;
7165             }
7166             var ns = /\S/;
7167             var d = this.dom, n = d.firstChild, ni = -1;
7168             while(n){
7169                 var nx = n.nextSibling;
7170                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7171                     d.removeChild(n);
7172                 }else{
7173                     n.nodeIndex = ++ni;
7174                 }
7175                 n = nx;
7176             }
7177             this.isCleaned = true;
7178             return this;
7179         },
7180
7181         // private
7182         calcOffsetsTo : function(el){
7183             el = Roo.get(el);
7184             var d = el.dom;
7185             var restorePos = false;
7186             if(el.getStyle('position') == 'static'){
7187                 el.position('relative');
7188                 restorePos = true;
7189             }
7190             var x = 0, y =0;
7191             var op = this.dom;
7192             while(op && op != d && op.tagName != 'HTML'){
7193                 x+= op.offsetLeft;
7194                 y+= op.offsetTop;
7195                 op = op.offsetParent;
7196             }
7197             if(restorePos){
7198                 el.position('static');
7199             }
7200             return [x, y];
7201         },
7202
7203         /**
7204          * Scrolls this element into view within the passed container.
7205          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7206          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7207          * @return {Roo.Element} this
7208          */
7209         scrollIntoView : function(container, hscroll){
7210             var c = Roo.getDom(container) || document.body;
7211             var el = this.dom;
7212
7213             var o = this.calcOffsetsTo(c),
7214                 l = o[0],
7215                 t = o[1],
7216                 b = t+el.offsetHeight,
7217                 r = l+el.offsetWidth;
7218
7219             var ch = c.clientHeight;
7220             var ct = parseInt(c.scrollTop, 10);
7221             var cl = parseInt(c.scrollLeft, 10);
7222             var cb = ct + ch;
7223             var cr = cl + c.clientWidth;
7224
7225             if(t < ct){
7226                 c.scrollTop = t;
7227             }else if(b > cb){
7228                 c.scrollTop = b-ch;
7229             }
7230
7231             if(hscroll !== false){
7232                 if(l < cl){
7233                     c.scrollLeft = l;
7234                 }else if(r > cr){
7235                     c.scrollLeft = r-c.clientWidth;
7236                 }
7237             }
7238             return this;
7239         },
7240
7241         // private
7242         scrollChildIntoView : function(child, hscroll){
7243             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7244         },
7245
7246         /**
7247          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7248          * the new height may not be available immediately.
7249          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7250          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7251          * @param {Function} onComplete (optional) Function to call when animation completes
7252          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7253          * @return {Roo.Element} this
7254          */
7255         autoHeight : function(animate, duration, onComplete, easing){
7256             var oldHeight = this.getHeight();
7257             this.clip();
7258             this.setHeight(1); // force clipping
7259             setTimeout(function(){
7260                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7261                 if(!animate){
7262                     this.setHeight(height);
7263                     this.unclip();
7264                     if(typeof onComplete == "function"){
7265                         onComplete();
7266                     }
7267                 }else{
7268                     this.setHeight(oldHeight); // restore original height
7269                     this.setHeight(height, animate, duration, function(){
7270                         this.unclip();
7271                         if(typeof onComplete == "function") onComplete();
7272                     }.createDelegate(this), easing);
7273                 }
7274             }.createDelegate(this), 0);
7275             return this;
7276         },
7277
7278         /**
7279          * Returns true if this element is an ancestor of the passed element
7280          * @param {HTMLElement/String} el The element to check
7281          * @return {Boolean} True if this element is an ancestor of el, else false
7282          */
7283         contains : function(el){
7284             if(!el){return false;}
7285             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7286         },
7287
7288         /**
7289          * Checks whether the element is currently visible using both visibility and display properties.
7290          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7291          * @return {Boolean} True if the element is currently visible, else false
7292          */
7293         isVisible : function(deep) {
7294             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7295             if(deep !== true || !vis){
7296                 return vis;
7297             }
7298             var p = this.dom.parentNode;
7299             while(p && p.tagName.toLowerCase() != "body"){
7300                 if(!Roo.fly(p, '_isVisible').isVisible()){
7301                     return false;
7302                 }
7303                 p = p.parentNode;
7304             }
7305             return true;
7306         },
7307
7308         /**
7309          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7310          * @param {String} selector The CSS selector
7311          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7312          * @return {CompositeElement/CompositeElementLite} The composite element
7313          */
7314         select : function(selector, unique){
7315             return El.select(selector, unique, this.dom);
7316         },
7317
7318         /**
7319          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7320          * @param {String} selector The CSS selector
7321          * @return {Array} An array of the matched nodes
7322          */
7323         query : function(selector, unique){
7324             return Roo.DomQuery.select(selector, this.dom);
7325         },
7326
7327         /**
7328          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7329          * @param {String} selector The CSS selector
7330          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7331          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7332          */
7333         child : function(selector, returnDom){
7334             var n = Roo.DomQuery.selectNode(selector, this.dom);
7335             return returnDom ? n : Roo.get(n);
7336         },
7337
7338         /**
7339          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7340          * @param {String} selector The CSS selector
7341          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7342          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7343          */
7344         down : function(selector, returnDom){
7345             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7346             return returnDom ? n : Roo.get(n);
7347         },
7348
7349         /**
7350          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7351          * @param {String} group The group the DD object is member of
7352          * @param {Object} config The DD config object
7353          * @param {Object} overrides An object containing methods to override/implement on the DD object
7354          * @return {Roo.dd.DD} The DD object
7355          */
7356         initDD : function(group, config, overrides){
7357             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7358             return Roo.apply(dd, overrides);
7359         },
7360
7361         /**
7362          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7363          * @param {String} group The group the DDProxy object is member of
7364          * @param {Object} config The DDProxy config object
7365          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7366          * @return {Roo.dd.DDProxy} The DDProxy object
7367          */
7368         initDDProxy : function(group, config, overrides){
7369             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7370             return Roo.apply(dd, overrides);
7371         },
7372
7373         /**
7374          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7375          * @param {String} group The group the DDTarget object is member of
7376          * @param {Object} config The DDTarget config object
7377          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7378          * @return {Roo.dd.DDTarget} The DDTarget object
7379          */
7380         initDDTarget : function(group, config, overrides){
7381             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7382             return Roo.apply(dd, overrides);
7383         },
7384
7385         /**
7386          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7387          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7388          * @param {Boolean} visible Whether the element is visible
7389          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7390          * @return {Roo.Element} this
7391          */
7392          setVisible : function(visible, animate){
7393             if(!animate || !A){
7394                 if(this.visibilityMode == El.DISPLAY){
7395                     this.setDisplayed(visible);
7396                 }else{
7397                     this.fixDisplay();
7398                     this.dom.style.visibility = visible ? "visible" : "hidden";
7399                 }
7400             }else{
7401                 // closure for composites
7402                 var dom = this.dom;
7403                 var visMode = this.visibilityMode;
7404                 if(visible){
7405                     this.setOpacity(.01);
7406                     this.setVisible(true);
7407                 }
7408                 this.anim({opacity: { to: (visible?1:0) }},
7409                       this.preanim(arguments, 1),
7410                       null, .35, 'easeIn', function(){
7411                          if(!visible){
7412                              if(visMode == El.DISPLAY){
7413                                  dom.style.display = "none";
7414                              }else{
7415                                  dom.style.visibility = "hidden";
7416                              }
7417                              Roo.get(dom).setOpacity(1);
7418                          }
7419                      });
7420             }
7421             return this;
7422         },
7423
7424         /**
7425          * Returns true if display is not "none"
7426          * @return {Boolean}
7427          */
7428         isDisplayed : function() {
7429             return this.getStyle("display") != "none";
7430         },
7431
7432         /**
7433          * Toggles the element's visibility or display, depending on visibility mode.
7434          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7435          * @return {Roo.Element} this
7436          */
7437         toggle : function(animate){
7438             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7439             return this;
7440         },
7441
7442         /**
7443          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7444          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7445          * @return {Roo.Element} this
7446          */
7447         setDisplayed : function(value) {
7448             if(typeof value == "boolean"){
7449                value = value ? this.originalDisplay : "none";
7450             }
7451             this.setStyle("display", value);
7452             return this;
7453         },
7454
7455         /**
7456          * Tries to focus the element. Any exceptions are caught and ignored.
7457          * @return {Roo.Element} this
7458          */
7459         focus : function() {
7460             try{
7461                 this.dom.focus();
7462             }catch(e){}
7463             return this;
7464         },
7465
7466         /**
7467          * Tries to blur the element. Any exceptions are caught and ignored.
7468          * @return {Roo.Element} this
7469          */
7470         blur : function() {
7471             try{
7472                 this.dom.blur();
7473             }catch(e){}
7474             return this;
7475         },
7476
7477         /**
7478          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7479          * @param {String/Array} className The CSS class to add, or an array of classes
7480          * @return {Roo.Element} this
7481          */
7482         addClass : function(className){
7483             if(className instanceof Array){
7484                 for(var i = 0, len = className.length; i < len; i++) {
7485                     this.addClass(className[i]);
7486                 }
7487             }else{
7488                 if(className && !this.hasClass(className)){
7489                     this.dom.className = this.dom.className + " " + className;
7490                 }
7491             }
7492             return this;
7493         },
7494
7495         /**
7496          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7497          * @param {String/Array} className The CSS class to add, or an array of classes
7498          * @return {Roo.Element} this
7499          */
7500         radioClass : function(className){
7501             var siblings = this.dom.parentNode.childNodes;
7502             for(var i = 0; i < siblings.length; i++) {
7503                 var s = siblings[i];
7504                 if(s.nodeType == 1){
7505                     Roo.get(s).removeClass(className);
7506                 }
7507             }
7508             this.addClass(className);
7509             return this;
7510         },
7511
7512         /**
7513          * Removes one or more CSS classes from the element.
7514          * @param {String/Array} className The CSS class to remove, or an array of classes
7515          * @return {Roo.Element} this
7516          */
7517         removeClass : function(className){
7518             if(!className || !this.dom.className){
7519                 return this;
7520             }
7521             if(className instanceof Array){
7522                 for(var i = 0, len = className.length; i < len; i++) {
7523                     this.removeClass(className[i]);
7524                 }
7525             }else{
7526                 if(this.hasClass(className)){
7527                     var re = this.classReCache[className];
7528                     if (!re) {
7529                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7530                        this.classReCache[className] = re;
7531                     }
7532                     this.dom.className =
7533                         this.dom.className.replace(re, " ");
7534                 }
7535             }
7536             return this;
7537         },
7538
7539         // private
7540         classReCache: {},
7541
7542         /**
7543          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7544          * @param {String} className The CSS class to toggle
7545          * @return {Roo.Element} this
7546          */
7547         toggleClass : function(className){
7548             if(this.hasClass(className)){
7549                 this.removeClass(className);
7550             }else{
7551                 this.addClass(className);
7552             }
7553             return this;
7554         },
7555
7556         /**
7557          * Checks if the specified CSS class exists on this element's DOM node.
7558          * @param {String} className The CSS class to check for
7559          * @return {Boolean} True if the class exists, else false
7560          */
7561         hasClass : function(className){
7562             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7563         },
7564
7565         /**
7566          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7567          * @param {String} oldClassName The CSS class to replace
7568          * @param {String} newClassName The replacement CSS class
7569          * @return {Roo.Element} this
7570          */
7571         replaceClass : function(oldClassName, newClassName){
7572             this.removeClass(oldClassName);
7573             this.addClass(newClassName);
7574             return this;
7575         },
7576
7577         /**
7578          * Returns an object with properties matching the styles requested.
7579          * For example, el.getStyles('color', 'font-size', 'width') might return
7580          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7581          * @param {String} style1 A style name
7582          * @param {String} style2 A style name
7583          * @param {String} etc.
7584          * @return {Object} The style object
7585          */
7586         getStyles : function(){
7587             var a = arguments, len = a.length, r = {};
7588             for(var i = 0; i < len; i++){
7589                 r[a[i]] = this.getStyle(a[i]);
7590             }
7591             return r;
7592         },
7593
7594         /**
7595          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7596          * @param {String} property The style property whose value is returned.
7597          * @return {String} The current value of the style property for this element.
7598          */
7599         getStyle : function(){
7600             return view && view.getComputedStyle ?
7601                 function(prop){
7602                     var el = this.dom, v, cs, camel;
7603                     if(prop == 'float'){
7604                         prop = "cssFloat";
7605                     }
7606                     if(el.style && (v = el.style[prop])){
7607                         return v;
7608                     }
7609                     if(cs = view.getComputedStyle(el, "")){
7610                         if(!(camel = propCache[prop])){
7611                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7612                         }
7613                         return cs[camel];
7614                     }
7615                     return null;
7616                 } :
7617                 function(prop){
7618                     var el = this.dom, v, cs, camel;
7619                     if(prop == 'opacity'){
7620                         if(typeof el.style.filter == 'string'){
7621                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7622                             if(m){
7623                                 var fv = parseFloat(m[1]);
7624                                 if(!isNaN(fv)){
7625                                     return fv ? fv / 100 : 0;
7626                                 }
7627                             }
7628                         }
7629                         return 1;
7630                     }else if(prop == 'float'){
7631                         prop = "styleFloat";
7632                     }
7633                     if(!(camel = propCache[prop])){
7634                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7635                     }
7636                     if(v = el.style[camel]){
7637                         return v;
7638                     }
7639                     if(cs = el.currentStyle){
7640                         return cs[camel];
7641                     }
7642                     return null;
7643                 };
7644         }(),
7645
7646         /**
7647          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7648          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7649          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7650          * @return {Roo.Element} this
7651          */
7652         setStyle : function(prop, value){
7653             if(typeof prop == "string"){
7654                 
7655                 if (prop == 'float') {
7656                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7657                     return this;
7658                 }
7659                 
7660                 var camel;
7661                 if(!(camel = propCache[prop])){
7662                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7663                 }
7664                 
7665                 if(camel == 'opacity') {
7666                     this.setOpacity(value);
7667                 }else{
7668                     this.dom.style[camel] = value;
7669                 }
7670             }else{
7671                 for(var style in prop){
7672                     if(typeof prop[style] != "function"){
7673                        this.setStyle(style, prop[style]);
7674                     }
7675                 }
7676             }
7677             return this;
7678         },
7679
7680         /**
7681          * More flexible version of {@link #setStyle} for setting style properties.
7682          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7683          * a function which returns such a specification.
7684          * @return {Roo.Element} this
7685          */
7686         applyStyles : function(style){
7687             Roo.DomHelper.applyStyles(this.dom, style);
7688             return this;
7689         },
7690
7691         /**
7692           * 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).
7693           * @return {Number} The X position of the element
7694           */
7695         getX : function(){
7696             return D.getX(this.dom);
7697         },
7698
7699         /**
7700           * 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).
7701           * @return {Number} The Y position of the element
7702           */
7703         getY : function(){
7704             return D.getY(this.dom);
7705         },
7706
7707         /**
7708           * 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).
7709           * @return {Array} The XY position of the element
7710           */
7711         getXY : function(){
7712             return D.getXY(this.dom);
7713         },
7714
7715         /**
7716          * 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).
7717          * @param {Number} The X position of the element
7718          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7719          * @return {Roo.Element} this
7720          */
7721         setX : function(x, animate){
7722             if(!animate || !A){
7723                 D.setX(this.dom, x);
7724             }else{
7725                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7726             }
7727             return this;
7728         },
7729
7730         /**
7731          * 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).
7732          * @param {Number} The Y position of the element
7733          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7734          * @return {Roo.Element} this
7735          */
7736         setY : function(y, animate){
7737             if(!animate || !A){
7738                 D.setY(this.dom, y);
7739             }else{
7740                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7741             }
7742             return this;
7743         },
7744
7745         /**
7746          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7747          * @param {String} left The left CSS property value
7748          * @return {Roo.Element} this
7749          */
7750         setLeft : function(left){
7751             this.setStyle("left", this.addUnits(left));
7752             return this;
7753         },
7754
7755         /**
7756          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7757          * @param {String} top The top CSS property value
7758          * @return {Roo.Element} this
7759          */
7760         setTop : function(top){
7761             this.setStyle("top", this.addUnits(top));
7762             return this;
7763         },
7764
7765         /**
7766          * Sets the element's CSS right style.
7767          * @param {String} right The right CSS property value
7768          * @return {Roo.Element} this
7769          */
7770         setRight : function(right){
7771             this.setStyle("right", this.addUnits(right));
7772             return this;
7773         },
7774
7775         /**
7776          * Sets the element's CSS bottom style.
7777          * @param {String} bottom The bottom CSS property value
7778          * @return {Roo.Element} this
7779          */
7780         setBottom : function(bottom){
7781             this.setStyle("bottom", this.addUnits(bottom));
7782             return this;
7783         },
7784
7785         /**
7786          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7787          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7788          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7789          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7790          * @return {Roo.Element} this
7791          */
7792         setXY : function(pos, animate){
7793             if(!animate || !A){
7794                 D.setXY(this.dom, pos);
7795             }else{
7796                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7797             }
7798             return this;
7799         },
7800
7801         /**
7802          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7803          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7804          * @param {Number} x X value for new position (coordinates are page-based)
7805          * @param {Number} y Y value for new position (coordinates are page-based)
7806          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7807          * @return {Roo.Element} this
7808          */
7809         setLocation : function(x, y, animate){
7810             this.setXY([x, y], this.preanim(arguments, 2));
7811             return this;
7812         },
7813
7814         /**
7815          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7816          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7817          * @param {Number} x X value for new position (coordinates are page-based)
7818          * @param {Number} y Y value for new position (coordinates are page-based)
7819          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7820          * @return {Roo.Element} this
7821          */
7822         moveTo : function(x, y, animate){
7823             this.setXY([x, y], this.preanim(arguments, 2));
7824             return this;
7825         },
7826
7827         /**
7828          * Returns the region of the given element.
7829          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7830          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7831          */
7832         getRegion : function(){
7833             return D.getRegion(this.dom);
7834         },
7835
7836         /**
7837          * Returns the offset height of the element
7838          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7839          * @return {Number} The element's height
7840          */
7841         getHeight : function(contentHeight){
7842             var h = this.dom.offsetHeight || 0;
7843             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7844         },
7845
7846         /**
7847          * Returns the offset width of the element
7848          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7849          * @return {Number} The element's width
7850          */
7851         getWidth : function(contentWidth){
7852             var w = this.dom.offsetWidth || 0;
7853             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7854         },
7855
7856         /**
7857          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7858          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7859          * if a height has not been set using CSS.
7860          * @return {Number}
7861          */
7862         getComputedHeight : function(){
7863             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7864             if(!h){
7865                 h = parseInt(this.getStyle('height'), 10) || 0;
7866                 if(!this.isBorderBox()){
7867                     h += this.getFrameWidth('tb');
7868                 }
7869             }
7870             return h;
7871         },
7872
7873         /**
7874          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7875          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7876          * if a width has not been set using CSS.
7877          * @return {Number}
7878          */
7879         getComputedWidth : function(){
7880             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7881             if(!w){
7882                 w = parseInt(this.getStyle('width'), 10) || 0;
7883                 if(!this.isBorderBox()){
7884                     w += this.getFrameWidth('lr');
7885                 }
7886             }
7887             return w;
7888         },
7889
7890         /**
7891          * Returns the size of the element.
7892          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7893          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7894          */
7895         getSize : function(contentSize){
7896             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7897         },
7898
7899         /**
7900          * Returns the width and height of the viewport.
7901          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7902          */
7903         getViewSize : function(){
7904             var d = this.dom, doc = document, aw = 0, ah = 0;
7905             if(d == doc || d == doc.body){
7906                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7907             }else{
7908                 return {
7909                     width : d.clientWidth,
7910                     height: d.clientHeight
7911                 };
7912             }
7913         },
7914
7915         /**
7916          * Returns the value of the "value" attribute
7917          * @param {Boolean} asNumber true to parse the value as a number
7918          * @return {String/Number}
7919          */
7920         getValue : function(asNumber){
7921             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7922         },
7923
7924         // private
7925         adjustWidth : function(width){
7926             if(typeof width == "number"){
7927                 if(this.autoBoxAdjust && !this.isBorderBox()){
7928                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7929                 }
7930                 if(width < 0){
7931                     width = 0;
7932                 }
7933             }
7934             return width;
7935         },
7936
7937         // private
7938         adjustHeight : function(height){
7939             if(typeof height == "number"){
7940                if(this.autoBoxAdjust && !this.isBorderBox()){
7941                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7942                }
7943                if(height < 0){
7944                    height = 0;
7945                }
7946             }
7947             return height;
7948         },
7949
7950         /**
7951          * Set the width of the element
7952          * @param {Number} width The new width
7953          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7954          * @return {Roo.Element} this
7955          */
7956         setWidth : function(width, animate){
7957             width = this.adjustWidth(width);
7958             if(!animate || !A){
7959                 this.dom.style.width = this.addUnits(width);
7960             }else{
7961                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7962             }
7963             return this;
7964         },
7965
7966         /**
7967          * Set the height of the element
7968          * @param {Number} height The new height
7969          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7970          * @return {Roo.Element} this
7971          */
7972          setHeight : function(height, animate){
7973             height = this.adjustHeight(height);
7974             if(!animate || !A){
7975                 this.dom.style.height = this.addUnits(height);
7976             }else{
7977                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7978             }
7979             return this;
7980         },
7981
7982         /**
7983          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7984          * @param {Number} width The new width
7985          * @param {Number} height The new height
7986          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7987          * @return {Roo.Element} this
7988          */
7989          setSize : function(width, height, animate){
7990             if(typeof width == "object"){ // in case of object from getSize()
7991                 height = width.height; width = width.width;
7992             }
7993             width = this.adjustWidth(width); height = this.adjustHeight(height);
7994             if(!animate || !A){
7995                 this.dom.style.width = this.addUnits(width);
7996                 this.dom.style.height = this.addUnits(height);
7997             }else{
7998                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
7999             }
8000             return this;
8001         },
8002
8003         /**
8004          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8005          * @param {Number} x X value for new position (coordinates are page-based)
8006          * @param {Number} y Y value for new position (coordinates are page-based)
8007          * @param {Number} width The new width
8008          * @param {Number} height The new height
8009          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8010          * @return {Roo.Element} this
8011          */
8012         setBounds : function(x, y, width, height, animate){
8013             if(!animate || !A){
8014                 this.setSize(width, height);
8015                 this.setLocation(x, y);
8016             }else{
8017                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8018                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8019                               this.preanim(arguments, 4), 'motion');
8020             }
8021             return this;
8022         },
8023
8024         /**
8025          * 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.
8026          * @param {Roo.lib.Region} region The region to fill
8027          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8028          * @return {Roo.Element} this
8029          */
8030         setRegion : function(region, animate){
8031             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8032             return this;
8033         },
8034
8035         /**
8036          * Appends an event handler
8037          *
8038          * @param {String}   eventName     The type of event to append
8039          * @param {Function} fn        The method the event invokes
8040          * @param {Object} scope       (optional) The scope (this object) of the fn
8041          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8042          */
8043         addListener : function(eventName, fn, scope, options){
8044             if (this.dom) {
8045                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8046             }
8047         },
8048
8049         /**
8050          * Removes an event handler from this element
8051          * @param {String} eventName the type of event to remove
8052          * @param {Function} fn the method the event invokes
8053          * @return {Roo.Element} this
8054          */
8055         removeListener : function(eventName, fn){
8056             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8057             return this;
8058         },
8059
8060         /**
8061          * Removes all previous added listeners from this element
8062          * @return {Roo.Element} this
8063          */
8064         removeAllListeners : function(){
8065             E.purgeElement(this.dom);
8066             return this;
8067         },
8068
8069         relayEvent : function(eventName, observable){
8070             this.on(eventName, function(e){
8071                 observable.fireEvent(eventName, e);
8072             });
8073         },
8074
8075         /**
8076          * Set the opacity of the element
8077          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8078          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8079          * @return {Roo.Element} this
8080          */
8081          setOpacity : function(opacity, animate){
8082             if(!animate || !A){
8083                 var s = this.dom.style;
8084                 if(Roo.isIE){
8085                     s.zoom = 1;
8086                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8087                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8088                 }else{
8089                     s.opacity = opacity;
8090                 }
8091             }else{
8092                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8093             }
8094             return this;
8095         },
8096
8097         /**
8098          * Gets the left X coordinate
8099          * @param {Boolean} local True to get the local css position instead of page coordinate
8100          * @return {Number}
8101          */
8102         getLeft : function(local){
8103             if(!local){
8104                 return this.getX();
8105             }else{
8106                 return parseInt(this.getStyle("left"), 10) || 0;
8107             }
8108         },
8109
8110         /**
8111          * Gets the right X coordinate of the element (element X position + element width)
8112          * @param {Boolean} local True to get the local css position instead of page coordinate
8113          * @return {Number}
8114          */
8115         getRight : function(local){
8116             if(!local){
8117                 return this.getX() + this.getWidth();
8118             }else{
8119                 return (this.getLeft(true) + this.getWidth()) || 0;
8120             }
8121         },
8122
8123         /**
8124          * Gets the top Y coordinate
8125          * @param {Boolean} local True to get the local css position instead of page coordinate
8126          * @return {Number}
8127          */
8128         getTop : function(local) {
8129             if(!local){
8130                 return this.getY();
8131             }else{
8132                 return parseInt(this.getStyle("top"), 10) || 0;
8133             }
8134         },
8135
8136         /**
8137          * Gets the bottom Y coordinate of the element (element Y position + element height)
8138          * @param {Boolean} local True to get the local css position instead of page coordinate
8139          * @return {Number}
8140          */
8141         getBottom : function(local){
8142             if(!local){
8143                 return this.getY() + this.getHeight();
8144             }else{
8145                 return (this.getTop(true) + this.getHeight()) || 0;
8146             }
8147         },
8148
8149         /**
8150         * Initializes positioning on this element. If a desired position is not passed, it will make the
8151         * the element positioned relative IF it is not already positioned.
8152         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8153         * @param {Number} zIndex (optional) The zIndex to apply
8154         * @param {Number} x (optional) Set the page X position
8155         * @param {Number} y (optional) Set the page Y position
8156         */
8157         position : function(pos, zIndex, x, y){
8158             if(!pos){
8159                if(this.getStyle('position') == 'static'){
8160                    this.setStyle('position', 'relative');
8161                }
8162             }else{
8163                 this.setStyle("position", pos);
8164             }
8165             if(zIndex){
8166                 this.setStyle("z-index", zIndex);
8167             }
8168             if(x !== undefined && y !== undefined){
8169                 this.setXY([x, y]);
8170             }else if(x !== undefined){
8171                 this.setX(x);
8172             }else if(y !== undefined){
8173                 this.setY(y);
8174             }
8175         },
8176
8177         /**
8178         * Clear positioning back to the default when the document was loaded
8179         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8180         * @return {Roo.Element} this
8181          */
8182         clearPositioning : function(value){
8183             value = value ||'';
8184             this.setStyle({
8185                 "left": value,
8186                 "right": value,
8187                 "top": value,
8188                 "bottom": value,
8189                 "z-index": "",
8190                 "position" : "static"
8191             });
8192             return this;
8193         },
8194
8195         /**
8196         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8197         * snapshot before performing an update and then restoring the element.
8198         * @return {Object}
8199         */
8200         getPositioning : function(){
8201             var l = this.getStyle("left");
8202             var t = this.getStyle("top");
8203             return {
8204                 "position" : this.getStyle("position"),
8205                 "left" : l,
8206                 "right" : l ? "" : this.getStyle("right"),
8207                 "top" : t,
8208                 "bottom" : t ? "" : this.getStyle("bottom"),
8209                 "z-index" : this.getStyle("z-index")
8210             };
8211         },
8212
8213         /**
8214          * Gets the width of the border(s) for the specified side(s)
8215          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8216          * passing lr would get the border (l)eft width + the border (r)ight width.
8217          * @return {Number} The width of the sides passed added together
8218          */
8219         getBorderWidth : function(side){
8220             return this.addStyles(side, El.borders);
8221         },
8222
8223         /**
8224          * Gets the width of the padding(s) for the specified side(s)
8225          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8226          * passing lr would get the padding (l)eft + the padding (r)ight.
8227          * @return {Number} The padding of the sides passed added together
8228          */
8229         getPadding : function(side){
8230             return this.addStyles(side, El.paddings);
8231         },
8232
8233         /**
8234         * Set positioning with an object returned by getPositioning().
8235         * @param {Object} posCfg
8236         * @return {Roo.Element} this
8237          */
8238         setPositioning : function(pc){
8239             this.applyStyles(pc);
8240             if(pc.right == "auto"){
8241                 this.dom.style.right = "";
8242             }
8243             if(pc.bottom == "auto"){
8244                 this.dom.style.bottom = "";
8245             }
8246             return this;
8247         },
8248
8249         // private
8250         fixDisplay : function(){
8251             if(this.getStyle("display") == "none"){
8252                 this.setStyle("visibility", "hidden");
8253                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8254                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8255                     this.setStyle("display", "block");
8256                 }
8257             }
8258         },
8259
8260         /**
8261          * Quick set left and top adding default units
8262          * @param {String} left The left CSS property value
8263          * @param {String} top The top CSS property value
8264          * @return {Roo.Element} this
8265          */
8266          setLeftTop : function(left, top){
8267             this.dom.style.left = this.addUnits(left);
8268             this.dom.style.top = this.addUnits(top);
8269             return this;
8270         },
8271
8272         /**
8273          * Move this element relative to its current position.
8274          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8275          * @param {Number} distance How far to move the element in pixels
8276          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8277          * @return {Roo.Element} this
8278          */
8279          move : function(direction, distance, animate){
8280             var xy = this.getXY();
8281             direction = direction.toLowerCase();
8282             switch(direction){
8283                 case "l":
8284                 case "left":
8285                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8286                     break;
8287                case "r":
8288                case "right":
8289                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8290                     break;
8291                case "t":
8292                case "top":
8293                case "up":
8294                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8295                     break;
8296                case "b":
8297                case "bottom":
8298                case "down":
8299                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8300                     break;
8301             }
8302             return this;
8303         },
8304
8305         /**
8306          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8307          * @return {Roo.Element} this
8308          */
8309         clip : function(){
8310             if(!this.isClipped){
8311                this.isClipped = true;
8312                this.originalClip = {
8313                    "o": this.getStyle("overflow"),
8314                    "x": this.getStyle("overflow-x"),
8315                    "y": this.getStyle("overflow-y")
8316                };
8317                this.setStyle("overflow", "hidden");
8318                this.setStyle("overflow-x", "hidden");
8319                this.setStyle("overflow-y", "hidden");
8320             }
8321             return this;
8322         },
8323
8324         /**
8325          *  Return clipping (overflow) to original clipping before clip() was called
8326          * @return {Roo.Element} this
8327          */
8328         unclip : function(){
8329             if(this.isClipped){
8330                 this.isClipped = false;
8331                 var o = this.originalClip;
8332                 if(o.o){this.setStyle("overflow", o.o);}
8333                 if(o.x){this.setStyle("overflow-x", o.x);}
8334                 if(o.y){this.setStyle("overflow-y", o.y);}
8335             }
8336             return this;
8337         },
8338
8339
8340         /**
8341          * Gets the x,y coordinates specified by the anchor position on the element.
8342          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8343          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8344          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8345          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8346          * @return {Array} [x, y] An array containing the element's x and y coordinates
8347          */
8348         getAnchorXY : function(anchor, local, s){
8349             //Passing a different size is useful for pre-calculating anchors,
8350             //especially for anchored animations that change the el size.
8351
8352             var w, h, vp = false;
8353             if(!s){
8354                 var d = this.dom;
8355                 if(d == document.body || d == document){
8356                     vp = true;
8357                     w = D.getViewWidth(); h = D.getViewHeight();
8358                 }else{
8359                     w = this.getWidth(); h = this.getHeight();
8360                 }
8361             }else{
8362                 w = s.width;  h = s.height;
8363             }
8364             var x = 0, y = 0, r = Math.round;
8365             switch((anchor || "tl").toLowerCase()){
8366                 case "c":
8367                     x = r(w*.5);
8368                     y = r(h*.5);
8369                 break;
8370                 case "t":
8371                     x = r(w*.5);
8372                     y = 0;
8373                 break;
8374                 case "l":
8375                     x = 0;
8376                     y = r(h*.5);
8377                 break;
8378                 case "r":
8379                     x = w;
8380                     y = r(h*.5);
8381                 break;
8382                 case "b":
8383                     x = r(w*.5);
8384                     y = h;
8385                 break;
8386                 case "tl":
8387                     x = 0;
8388                     y = 0;
8389                 break;
8390                 case "bl":
8391                     x = 0;
8392                     y = h;
8393                 break;
8394                 case "br":
8395                     x = w;
8396                     y = h;
8397                 break;
8398                 case "tr":
8399                     x = w;
8400                     y = 0;
8401                 break;
8402             }
8403             if(local === true){
8404                 return [x, y];
8405             }
8406             if(vp){
8407                 var sc = this.getScroll();
8408                 return [x + sc.left, y + sc.top];
8409             }
8410             //Add the element's offset xy
8411             var o = this.getXY();
8412             return [x+o[0], y+o[1]];
8413         },
8414
8415         /**
8416          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8417          * supported position values.
8418          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8419          * @param {String} position The position to align to.
8420          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8421          * @return {Array} [x, y]
8422          */
8423         getAlignToXY : function(el, p, o){
8424             el = Roo.get(el);
8425             var d = this.dom;
8426             if(!el.dom){
8427                 throw "Element.alignTo with an element that doesn't exist";
8428             }
8429             var c = false; //constrain to viewport
8430             var p1 = "", p2 = "";
8431             o = o || [0,0];
8432
8433             if(!p){
8434                 p = "tl-bl";
8435             }else if(p == "?"){
8436                 p = "tl-bl?";
8437             }else if(p.indexOf("-") == -1){
8438                 p = "tl-" + p;
8439             }
8440             p = p.toLowerCase();
8441             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8442             if(!m){
8443                throw "Element.alignTo with an invalid alignment " + p;
8444             }
8445             p1 = m[1]; p2 = m[2]; c = !!m[3];
8446
8447             //Subtract the aligned el's internal xy from the target's offset xy
8448             //plus custom offset to get the aligned el's new offset xy
8449             var a1 = this.getAnchorXY(p1, true);
8450             var a2 = el.getAnchorXY(p2, false);
8451             var x = a2[0] - a1[0] + o[0];
8452             var y = a2[1] - a1[1] + o[1];
8453             if(c){
8454                 //constrain the aligned el to viewport if necessary
8455                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8456                 // 5px of margin for ie
8457                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8458
8459                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8460                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8461                 //otherwise swap the aligned el to the opposite border of the target.
8462                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8463                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8464                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8465                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8466
8467                var doc = document;
8468                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8469                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8470
8471                if((x+w) > dw + scrollX){
8472                     x = swapX ? r.left-w : dw+scrollX-w;
8473                 }
8474                if(x < scrollX){
8475                    x = swapX ? r.right : scrollX;
8476                }
8477                if((y+h) > dh + scrollY){
8478                     y = swapY ? r.top-h : dh+scrollY-h;
8479                 }
8480                if (y < scrollY){
8481                    y = swapY ? r.bottom : scrollY;
8482                }
8483             }
8484             return [x,y];
8485         },
8486
8487         // private
8488         getConstrainToXY : function(){
8489             var os = {top:0, left:0, bottom:0, right: 0};
8490
8491             return function(el, local, offsets, proposedXY){
8492                 el = Roo.get(el);
8493                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8494
8495                 var vw, vh, vx = 0, vy = 0;
8496                 if(el.dom == document.body || el.dom == document){
8497                     vw = Roo.lib.Dom.getViewWidth();
8498                     vh = Roo.lib.Dom.getViewHeight();
8499                 }else{
8500                     vw = el.dom.clientWidth;
8501                     vh = el.dom.clientHeight;
8502                     if(!local){
8503                         var vxy = el.getXY();
8504                         vx = vxy[0];
8505                         vy = vxy[1];
8506                     }
8507                 }
8508
8509                 var s = el.getScroll();
8510
8511                 vx += offsets.left + s.left;
8512                 vy += offsets.top + s.top;
8513
8514                 vw -= offsets.right;
8515                 vh -= offsets.bottom;
8516
8517                 var vr = vx+vw;
8518                 var vb = vy+vh;
8519
8520                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8521                 var x = xy[0], y = xy[1];
8522                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8523
8524                 // only move it if it needs it
8525                 var moved = false;
8526
8527                 // first validate right/bottom
8528                 if((x + w) > vr){
8529                     x = vr - w;
8530                     moved = true;
8531                 }
8532                 if((y + h) > vb){
8533                     y = vb - h;
8534                     moved = true;
8535                 }
8536                 // then make sure top/left isn't negative
8537                 if(x < vx){
8538                     x = vx;
8539                     moved = true;
8540                 }
8541                 if(y < vy){
8542                     y = vy;
8543                     moved = true;
8544                 }
8545                 return moved ? [x, y] : false;
8546             };
8547         }(),
8548
8549         // private
8550         adjustForConstraints : function(xy, parent, offsets){
8551             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8552         },
8553
8554         /**
8555          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8556          * document it aligns it to the viewport.
8557          * The position parameter is optional, and can be specified in any one of the following formats:
8558          * <ul>
8559          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8560          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8561          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8562          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8563          *   <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
8564          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8565          * </ul>
8566          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8567          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8568          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8569          * that specified in order to enforce the viewport constraints.
8570          * Following are all of the supported anchor positions:
8571     <pre>
8572     Value  Description
8573     -----  -----------------------------
8574     tl     The top left corner (default)
8575     t      The center of the top edge
8576     tr     The top right corner
8577     l      The center of the left edge
8578     c      In the center of the element
8579     r      The center of the right edge
8580     bl     The bottom left corner
8581     b      The center of the bottom edge
8582     br     The bottom right corner
8583     </pre>
8584     Example Usage:
8585     <pre><code>
8586     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8587     el.alignTo("other-el");
8588
8589     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8590     el.alignTo("other-el", "tr?");
8591
8592     // align the bottom right corner of el with the center left edge of other-el
8593     el.alignTo("other-el", "br-l?");
8594
8595     // align the center of el with the bottom left corner of other-el and
8596     // adjust the x position by -6 pixels (and the y position by 0)
8597     el.alignTo("other-el", "c-bl", [-6, 0]);
8598     </code></pre>
8599          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8600          * @param {String} position The position to align to.
8601          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8602          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8603          * @return {Roo.Element} this
8604          */
8605         alignTo : function(element, position, offsets, animate){
8606             var xy = this.getAlignToXY(element, position, offsets);
8607             this.setXY(xy, this.preanim(arguments, 3));
8608             return this;
8609         },
8610
8611         /**
8612          * Anchors an element to another element and realigns it when the window is resized.
8613          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8614          * @param {String} position The position to align to.
8615          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8616          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8617          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8618          * is a number, it is used as the buffer delay (defaults to 50ms).
8619          * @param {Function} callback The function to call after the animation finishes
8620          * @return {Roo.Element} this
8621          */
8622         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8623             var action = function(){
8624                 this.alignTo(el, alignment, offsets, animate);
8625                 Roo.callback(callback, this);
8626             };
8627             Roo.EventManager.onWindowResize(action, this);
8628             var tm = typeof monitorScroll;
8629             if(tm != 'undefined'){
8630                 Roo.EventManager.on(window, 'scroll', action, this,
8631                     {buffer: tm == 'number' ? monitorScroll : 50});
8632             }
8633             action.call(this); // align immediately
8634             return this;
8635         },
8636         /**
8637          * Clears any opacity settings from this element. Required in some cases for IE.
8638          * @return {Roo.Element} this
8639          */
8640         clearOpacity : function(){
8641             if (window.ActiveXObject) {
8642                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8643                     this.dom.style.filter = "";
8644                 }
8645             } else {
8646                 this.dom.style.opacity = "";
8647                 this.dom.style["-moz-opacity"] = "";
8648                 this.dom.style["-khtml-opacity"] = "";
8649             }
8650             return this;
8651         },
8652
8653         /**
8654          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8655          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8656          * @return {Roo.Element} this
8657          */
8658         hide : function(animate){
8659             this.setVisible(false, this.preanim(arguments, 0));
8660             return this;
8661         },
8662
8663         /**
8664         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8665         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8666          * @return {Roo.Element} this
8667          */
8668         show : function(animate){
8669             this.setVisible(true, this.preanim(arguments, 0));
8670             return this;
8671         },
8672
8673         /**
8674          * @private Test if size has a unit, otherwise appends the default
8675          */
8676         addUnits : function(size){
8677             return Roo.Element.addUnits(size, this.defaultUnit);
8678         },
8679
8680         /**
8681          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8682          * @return {Roo.Element} this
8683          */
8684         beginMeasure : function(){
8685             var el = this.dom;
8686             if(el.offsetWidth || el.offsetHeight){
8687                 return this; // offsets work already
8688             }
8689             var changed = [];
8690             var p = this.dom, b = document.body; // start with this element
8691             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8692                 var pe = Roo.get(p);
8693                 if(pe.getStyle('display') == 'none'){
8694                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8695                     p.style.visibility = "hidden";
8696                     p.style.display = "block";
8697                 }
8698                 p = p.parentNode;
8699             }
8700             this._measureChanged = changed;
8701             return this;
8702
8703         },
8704
8705         /**
8706          * Restores displays to before beginMeasure was called
8707          * @return {Roo.Element} this
8708          */
8709         endMeasure : function(){
8710             var changed = this._measureChanged;
8711             if(changed){
8712                 for(var i = 0, len = changed.length; i < len; i++) {
8713                     var r = changed[i];
8714                     r.el.style.visibility = r.visibility;
8715                     r.el.style.display = "none";
8716                 }
8717                 this._measureChanged = null;
8718             }
8719             return this;
8720         },
8721
8722         /**
8723         * Update the innerHTML of this element, optionally searching for and processing scripts
8724         * @param {String} html The new HTML
8725         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8726         * @param {Function} callback For async script loading you can be noticed when the update completes
8727         * @return {Roo.Element} this
8728          */
8729         update : function(html, loadScripts, callback){
8730             if(typeof html == "undefined"){
8731                 html = "";
8732             }
8733             if(loadScripts !== true){
8734                 this.dom.innerHTML = html;
8735                 if(typeof callback == "function"){
8736                     callback();
8737                 }
8738                 return this;
8739             }
8740             var id = Roo.id();
8741             var dom = this.dom;
8742
8743             html += '<span id="' + id + '"></span>';
8744
8745             E.onAvailable(id, function(){
8746                 var hd = document.getElementsByTagName("head")[0];
8747                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8748                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8749                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8750
8751                 var match;
8752                 while(match = re.exec(html)){
8753                     var attrs = match[1];
8754                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8755                     if(srcMatch && srcMatch[2]){
8756                        var s = document.createElement("script");
8757                        s.src = srcMatch[2];
8758                        var typeMatch = attrs.match(typeRe);
8759                        if(typeMatch && typeMatch[2]){
8760                            s.type = typeMatch[2];
8761                        }
8762                        hd.appendChild(s);
8763                     }else if(match[2] && match[2].length > 0){
8764                         if(window.execScript) {
8765                            window.execScript(match[2]);
8766                         } else {
8767                             /**
8768                              * eval:var:id
8769                              * eval:var:dom
8770                              * eval:var:html
8771                              * 
8772                              */
8773                            window.eval(match[2]);
8774                         }
8775                     }
8776                 }
8777                 var el = document.getElementById(id);
8778                 if(el){el.parentNode.removeChild(el);}
8779                 if(typeof callback == "function"){
8780                     callback();
8781                 }
8782             });
8783             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8784             return this;
8785         },
8786
8787         /**
8788          * Direct access to the UpdateManager update() method (takes the same parameters).
8789          * @param {String/Function} url The url for this request or a function to call to get the url
8790          * @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}
8791          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8792          * @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.
8793          * @return {Roo.Element} this
8794          */
8795         load : function(){
8796             var um = this.getUpdateManager();
8797             um.update.apply(um, arguments);
8798             return this;
8799         },
8800
8801         /**
8802         * Gets this element's UpdateManager
8803         * @return {Roo.UpdateManager} The UpdateManager
8804         */
8805         getUpdateManager : function(){
8806             if(!this.updateManager){
8807                 this.updateManager = new Roo.UpdateManager(this);
8808             }
8809             return this.updateManager;
8810         },
8811
8812         /**
8813          * Disables text selection for this element (normalized across browsers)
8814          * @return {Roo.Element} this
8815          */
8816         unselectable : function(){
8817             this.dom.unselectable = "on";
8818             this.swallowEvent("selectstart", true);
8819             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8820             this.addClass("x-unselectable");
8821             return this;
8822         },
8823
8824         /**
8825         * Calculates the x, y to center this element on the screen
8826         * @return {Array} The x, y values [x, y]
8827         */
8828         getCenterXY : function(){
8829             return this.getAlignToXY(document, 'c-c');
8830         },
8831
8832         /**
8833         * Centers the Element in either the viewport, or another Element.
8834         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8835         */
8836         center : function(centerIn){
8837             this.alignTo(centerIn || document, 'c-c');
8838             return this;
8839         },
8840
8841         /**
8842          * Tests various css rules/browsers to determine if this element uses a border box
8843          * @return {Boolean}
8844          */
8845         isBorderBox : function(){
8846             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8847         },
8848
8849         /**
8850          * Return a box {x, y, width, height} that can be used to set another elements
8851          * size/location to match this element.
8852          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8853          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8854          * @return {Object} box An object in the format {x, y, width, height}
8855          */
8856         getBox : function(contentBox, local){
8857             var xy;
8858             if(!local){
8859                 xy = this.getXY();
8860             }else{
8861                 var left = parseInt(this.getStyle("left"), 10) || 0;
8862                 var top = parseInt(this.getStyle("top"), 10) || 0;
8863                 xy = [left, top];
8864             }
8865             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8866             if(!contentBox){
8867                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8868             }else{
8869                 var l = this.getBorderWidth("l")+this.getPadding("l");
8870                 var r = this.getBorderWidth("r")+this.getPadding("r");
8871                 var t = this.getBorderWidth("t")+this.getPadding("t");
8872                 var b = this.getBorderWidth("b")+this.getPadding("b");
8873                 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)};
8874             }
8875             bx.right = bx.x + bx.width;
8876             bx.bottom = bx.y + bx.height;
8877             return bx;
8878         },
8879
8880         /**
8881          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8882          for more information about the sides.
8883          * @param {String} sides
8884          * @return {Number}
8885          */
8886         getFrameWidth : function(sides, onlyContentBox){
8887             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8888         },
8889
8890         /**
8891          * 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.
8892          * @param {Object} box The box to fill {x, y, width, height}
8893          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8894          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8895          * @return {Roo.Element} this
8896          */
8897         setBox : function(box, adjust, animate){
8898             var w = box.width, h = box.height;
8899             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8900                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8901                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8902             }
8903             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8904             return this;
8905         },
8906
8907         /**
8908          * Forces the browser to repaint this element
8909          * @return {Roo.Element} this
8910          */
8911          repaint : function(){
8912             var dom = this.dom;
8913             this.addClass("x-repaint");
8914             setTimeout(function(){
8915                 Roo.get(dom).removeClass("x-repaint");
8916             }, 1);
8917             return this;
8918         },
8919
8920         /**
8921          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8922          * then it returns the calculated width of the sides (see getPadding)
8923          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8924          * @return {Object/Number}
8925          */
8926         getMargins : function(side){
8927             if(!side){
8928                 return {
8929                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8930                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8931                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8932                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8933                 };
8934             }else{
8935                 return this.addStyles(side, El.margins);
8936              }
8937         },
8938
8939         // private
8940         addStyles : function(sides, styles){
8941             var val = 0, v, w;
8942             for(var i = 0, len = sides.length; i < len; i++){
8943                 v = this.getStyle(styles[sides.charAt(i)]);
8944                 if(v){
8945                      w = parseInt(v, 10);
8946                      if(w){ val += w; }
8947                 }
8948             }
8949             return val;
8950         },
8951
8952         /**
8953          * Creates a proxy element of this element
8954          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8955          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8956          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8957          * @return {Roo.Element} The new proxy element
8958          */
8959         createProxy : function(config, renderTo, matchBox){
8960             if(renderTo){
8961                 renderTo = Roo.getDom(renderTo);
8962             }else{
8963                 renderTo = document.body;
8964             }
8965             config = typeof config == "object" ?
8966                 config : {tag : "div", cls: config};
8967             var proxy = Roo.DomHelper.append(renderTo, config, true);
8968             if(matchBox){
8969                proxy.setBox(this.getBox());
8970             }
8971             return proxy;
8972         },
8973
8974         /**
8975          * Puts a mask over this element to disable user interaction. Requires core.css.
8976          * This method can only be applied to elements which accept child nodes.
8977          * @param {String} msg (optional) A message to display in the mask
8978          * @param {String} msgCls (optional) A css class to apply to the msg element
8979          * @return {Element} The mask  element
8980          */
8981         mask : function(msg, msgCls)
8982         {
8983             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8984                 this.setStyle("position", "relative");
8985             }
8986             if(!this._mask){
8987                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
8988             }
8989             this.addClass("x-masked");
8990             this._mask.setDisplayed(true);
8991             
8992             // we wander
8993             var z = 0;
8994             var dom = this.dom
8995             while (dom && dom.style) {
8996                 if (!isNaN(parseInt(dom.style.zIndex))) {
8997                     z = Math.max(z, parseInt(dom.style.zIndex));
8998                 }
8999                 dom = dom.parentNode;
9000             }
9001             // if we are masking the body - then it hides everything..
9002             if (this.dom == document.body) {
9003                 z = 1000000;
9004                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9005                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9006             }
9007            
9008             if(typeof msg == 'string'){
9009                 if(!this._maskMsg){
9010                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9011                 }
9012                 var mm = this._maskMsg;
9013                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9014                 if (mm.dom.firstChild) { // weird IE issue?
9015                     mm.dom.firstChild.innerHTML = msg;
9016                 }
9017                 mm.setDisplayed(true);
9018                 mm.center(this);
9019                 mm.setStyle('z-index', z + 102);
9020             }
9021             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9022                 this._mask.setHeight(this.getHeight());
9023             }
9024             this._mask.setStyle('z-index', z + 100);
9025             
9026             return this._mask;
9027         },
9028
9029         /**
9030          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9031          * it is cached for reuse.
9032          */
9033         unmask : function(removeEl){
9034             if(this._mask){
9035                 if(removeEl === true){
9036                     this._mask.remove();
9037                     delete this._mask;
9038                     if(this._maskMsg){
9039                         this._maskMsg.remove();
9040                         delete this._maskMsg;
9041                     }
9042                 }else{
9043                     this._mask.setDisplayed(false);
9044                     if(this._maskMsg){
9045                         this._maskMsg.setDisplayed(false);
9046                     }
9047                 }
9048             }
9049             this.removeClass("x-masked");
9050         },
9051
9052         /**
9053          * Returns true if this element is masked
9054          * @return {Boolean}
9055          */
9056         isMasked : function(){
9057             return this._mask && this._mask.isVisible();
9058         },
9059
9060         /**
9061          * Creates an iframe shim for this element to keep selects and other windowed objects from
9062          * showing through.
9063          * @return {Roo.Element} The new shim element
9064          */
9065         createShim : function(){
9066             var el = document.createElement('iframe');
9067             el.frameBorder = 'no';
9068             el.className = 'roo-shim';
9069             if(Roo.isIE && Roo.isSecure){
9070                 el.src = Roo.SSL_SECURE_URL;
9071             }
9072             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9073             shim.autoBoxAdjust = false;
9074             return shim;
9075         },
9076
9077         /**
9078          * Removes this element from the DOM and deletes it from the cache
9079          */
9080         remove : function(){
9081             if(this.dom.parentNode){
9082                 this.dom.parentNode.removeChild(this.dom);
9083             }
9084             delete El.cache[this.dom.id];
9085         },
9086
9087         /**
9088          * Sets up event handlers to add and remove a css class when the mouse is over this element
9089          * @param {String} className
9090          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9091          * mouseout events for children elements
9092          * @return {Roo.Element} this
9093          */
9094         addClassOnOver : function(className, preventFlicker){
9095             this.on("mouseover", function(){
9096                 Roo.fly(this, '_internal').addClass(className);
9097             }, this.dom);
9098             var removeFn = function(e){
9099                 if(preventFlicker !== true || !e.within(this, true)){
9100                     Roo.fly(this, '_internal').removeClass(className);
9101                 }
9102             };
9103             this.on("mouseout", removeFn, this.dom);
9104             return this;
9105         },
9106
9107         /**
9108          * Sets up event handlers to add and remove a css class when this element has the focus
9109          * @param {String} className
9110          * @return {Roo.Element} this
9111          */
9112         addClassOnFocus : function(className){
9113             this.on("focus", function(){
9114                 Roo.fly(this, '_internal').addClass(className);
9115             }, this.dom);
9116             this.on("blur", function(){
9117                 Roo.fly(this, '_internal').removeClass(className);
9118             }, this.dom);
9119             return this;
9120         },
9121         /**
9122          * 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)
9123          * @param {String} className
9124          * @return {Roo.Element} this
9125          */
9126         addClassOnClick : function(className){
9127             var dom = this.dom;
9128             this.on("mousedown", function(){
9129                 Roo.fly(dom, '_internal').addClass(className);
9130                 var d = Roo.get(document);
9131                 var fn = function(){
9132                     Roo.fly(dom, '_internal').removeClass(className);
9133                     d.removeListener("mouseup", fn);
9134                 };
9135                 d.on("mouseup", fn);
9136             });
9137             return this;
9138         },
9139
9140         /**
9141          * Stops the specified event from bubbling and optionally prevents the default action
9142          * @param {String} eventName
9143          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9144          * @return {Roo.Element} this
9145          */
9146         swallowEvent : function(eventName, preventDefault){
9147             var fn = function(e){
9148                 e.stopPropagation();
9149                 if(preventDefault){
9150                     e.preventDefault();
9151                 }
9152             };
9153             if(eventName instanceof Array){
9154                 for(var i = 0, len = eventName.length; i < len; i++){
9155                      this.on(eventName[i], fn);
9156                 }
9157                 return this;
9158             }
9159             this.on(eventName, fn);
9160             return this;
9161         },
9162
9163         /**
9164          * @private
9165          */
9166       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9167
9168         /**
9169          * Sizes this element to its parent element's dimensions performing
9170          * neccessary box adjustments.
9171          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9172          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9173          * @return {Roo.Element} this
9174          */
9175         fitToParent : function(monitorResize, targetParent) {
9176           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9177           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9178           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9179             return;
9180           }
9181           var p = Roo.get(targetParent || this.dom.parentNode);
9182           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9183           if (monitorResize === true) {
9184             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9185             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9186           }
9187           return this;
9188         },
9189
9190         /**
9191          * Gets the next sibling, skipping text nodes
9192          * @return {HTMLElement} The next sibling or null
9193          */
9194         getNextSibling : function(){
9195             var n = this.dom.nextSibling;
9196             while(n && n.nodeType != 1){
9197                 n = n.nextSibling;
9198             }
9199             return n;
9200         },
9201
9202         /**
9203          * Gets the previous sibling, skipping text nodes
9204          * @return {HTMLElement} The previous sibling or null
9205          */
9206         getPrevSibling : function(){
9207             var n = this.dom.previousSibling;
9208             while(n && n.nodeType != 1){
9209                 n = n.previousSibling;
9210             }
9211             return n;
9212         },
9213
9214
9215         /**
9216          * Appends the passed element(s) to this element
9217          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9218          * @return {Roo.Element} this
9219          */
9220         appendChild: function(el){
9221             el = Roo.get(el);
9222             el.appendTo(this);
9223             return this;
9224         },
9225
9226         /**
9227          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9228          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9229          * automatically generated with the specified attributes.
9230          * @param {HTMLElement} insertBefore (optional) a child element of this element
9231          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9232          * @return {Roo.Element} The new child element
9233          */
9234         createChild: function(config, insertBefore, returnDom){
9235             config = config || {tag:'div'};
9236             if(insertBefore){
9237                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9238             }
9239             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9240         },
9241
9242         /**
9243          * Appends this element to the passed element
9244          * @param {String/HTMLElement/Element} el The new parent element
9245          * @return {Roo.Element} this
9246          */
9247         appendTo: function(el){
9248             el = Roo.getDom(el);
9249             el.appendChild(this.dom);
9250             return this;
9251         },
9252
9253         /**
9254          * Inserts this element before the passed element in the DOM
9255          * @param {String/HTMLElement/Element} el The element to insert before
9256          * @return {Roo.Element} this
9257          */
9258         insertBefore: function(el){
9259             el = Roo.getDom(el);
9260             el.parentNode.insertBefore(this.dom, el);
9261             return this;
9262         },
9263
9264         /**
9265          * Inserts this element after the passed element in the DOM
9266          * @param {String/HTMLElement/Element} el The element to insert after
9267          * @return {Roo.Element} this
9268          */
9269         insertAfter: function(el){
9270             el = Roo.getDom(el);
9271             el.parentNode.insertBefore(this.dom, el.nextSibling);
9272             return this;
9273         },
9274
9275         /**
9276          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9277          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9278          * @return {Roo.Element} The new child
9279          */
9280         insertFirst: function(el, returnDom){
9281             el = el || {};
9282             if(typeof el == 'object' && !el.nodeType){ // dh config
9283                 return this.createChild(el, this.dom.firstChild, returnDom);
9284             }else{
9285                 el = Roo.getDom(el);
9286                 this.dom.insertBefore(el, this.dom.firstChild);
9287                 return !returnDom ? Roo.get(el) : el;
9288             }
9289         },
9290
9291         /**
9292          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9293          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9294          * @param {String} where (optional) 'before' or 'after' defaults to before
9295          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9296          * @return {Roo.Element} the inserted Element
9297          */
9298         insertSibling: function(el, where, returnDom){
9299             where = where ? where.toLowerCase() : 'before';
9300             el = el || {};
9301             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9302
9303             if(typeof el == 'object' && !el.nodeType){ // dh config
9304                 if(where == 'after' && !this.dom.nextSibling){
9305                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9306                 }else{
9307                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9308                 }
9309
9310             }else{
9311                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9312                             where == 'before' ? this.dom : this.dom.nextSibling);
9313                 if(!returnDom){
9314                     rt = Roo.get(rt);
9315                 }
9316             }
9317             return rt;
9318         },
9319
9320         /**
9321          * Creates and wraps this element with another element
9322          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9323          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9324          * @return {HTMLElement/Element} The newly created wrapper element
9325          */
9326         wrap: function(config, returnDom){
9327             if(!config){
9328                 config = {tag: "div"};
9329             }
9330             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9331             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9332             return newEl;
9333         },
9334
9335         /**
9336          * Replaces the passed element with this element
9337          * @param {String/HTMLElement/Element} el The element to replace
9338          * @return {Roo.Element} this
9339          */
9340         replace: function(el){
9341             el = Roo.get(el);
9342             this.insertBefore(el);
9343             el.remove();
9344             return this;
9345         },
9346
9347         /**
9348          * Inserts an html fragment into this element
9349          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9350          * @param {String} html The HTML fragment
9351          * @param {Boolean} returnEl True to return an Roo.Element
9352          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9353          */
9354         insertHtml : function(where, html, returnEl){
9355             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9356             return returnEl ? Roo.get(el) : el;
9357         },
9358
9359         /**
9360          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9361          * @param {Object} o The object with the attributes
9362          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9363          * @return {Roo.Element} this
9364          */
9365         set : function(o, useSet){
9366             var el = this.dom;
9367             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9368             for(var attr in o){
9369                 if(attr == "style" || typeof o[attr] == "function") continue;
9370                 if(attr=="cls"){
9371                     el.className = o["cls"];
9372                 }else{
9373                     if(useSet) el.setAttribute(attr, o[attr]);
9374                     else el[attr] = o[attr];
9375                 }
9376             }
9377             if(o.style){
9378                 Roo.DomHelper.applyStyles(el, o.style);
9379             }
9380             return this;
9381         },
9382
9383         /**
9384          * Convenience method for constructing a KeyMap
9385          * @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:
9386          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9387          * @param {Function} fn The function to call
9388          * @param {Object} scope (optional) The scope of the function
9389          * @return {Roo.KeyMap} The KeyMap created
9390          */
9391         addKeyListener : function(key, fn, scope){
9392             var config;
9393             if(typeof key != "object" || key instanceof Array){
9394                 config = {
9395                     key: key,
9396                     fn: fn,
9397                     scope: scope
9398                 };
9399             }else{
9400                 config = {
9401                     key : key.key,
9402                     shift : key.shift,
9403                     ctrl : key.ctrl,
9404                     alt : key.alt,
9405                     fn: fn,
9406                     scope: scope
9407                 };
9408             }
9409             return new Roo.KeyMap(this, config);
9410         },
9411
9412         /**
9413          * Creates a KeyMap for this element
9414          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9415          * @return {Roo.KeyMap} The KeyMap created
9416          */
9417         addKeyMap : function(config){
9418             return new Roo.KeyMap(this, config);
9419         },
9420
9421         /**
9422          * Returns true if this element is scrollable.
9423          * @return {Boolean}
9424          */
9425          isScrollable : function(){
9426             var dom = this.dom;
9427             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9428         },
9429
9430         /**
9431          * 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().
9432          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9433          * @param {Number} value The new scroll value
9434          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9435          * @return {Element} this
9436          */
9437
9438         scrollTo : function(side, value, animate){
9439             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9440             if(!animate || !A){
9441                 this.dom[prop] = value;
9442             }else{
9443                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9444                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9445             }
9446             return this;
9447         },
9448
9449         /**
9450          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9451          * within this element's scrollable range.
9452          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9453          * @param {Number} distance How far to scroll the element in pixels
9454          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9455          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9456          * was scrolled as far as it could go.
9457          */
9458          scroll : function(direction, distance, animate){
9459              if(!this.isScrollable()){
9460                  return;
9461              }
9462              var el = this.dom;
9463              var l = el.scrollLeft, t = el.scrollTop;
9464              var w = el.scrollWidth, h = el.scrollHeight;
9465              var cw = el.clientWidth, ch = el.clientHeight;
9466              direction = direction.toLowerCase();
9467              var scrolled = false;
9468              var a = this.preanim(arguments, 2);
9469              switch(direction){
9470                  case "l":
9471                  case "left":
9472                      if(w - l > cw){
9473                          var v = Math.min(l + distance, w-cw);
9474                          this.scrollTo("left", v, a);
9475                          scrolled = true;
9476                      }
9477                      break;
9478                 case "r":
9479                 case "right":
9480                      if(l > 0){
9481                          var v = Math.max(l - distance, 0);
9482                          this.scrollTo("left", v, a);
9483                          scrolled = true;
9484                      }
9485                      break;
9486                 case "t":
9487                 case "top":
9488                 case "up":
9489                      if(t > 0){
9490                          var v = Math.max(t - distance, 0);
9491                          this.scrollTo("top", v, a);
9492                          scrolled = true;
9493                      }
9494                      break;
9495                 case "b":
9496                 case "bottom":
9497                 case "down":
9498                      if(h - t > ch){
9499                          var v = Math.min(t + distance, h-ch);
9500                          this.scrollTo("top", v, a);
9501                          scrolled = true;
9502                      }
9503                      break;
9504              }
9505              return scrolled;
9506         },
9507
9508         /**
9509          * Translates the passed page coordinates into left/top css values for this element
9510          * @param {Number/Array} x The page x or an array containing [x, y]
9511          * @param {Number} y The page y
9512          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9513          */
9514         translatePoints : function(x, y){
9515             if(typeof x == 'object' || x instanceof Array){
9516                 y = x[1]; x = x[0];
9517             }
9518             var p = this.getStyle('position');
9519             var o = this.getXY();
9520
9521             var l = parseInt(this.getStyle('left'), 10);
9522             var t = parseInt(this.getStyle('top'), 10);
9523
9524             if(isNaN(l)){
9525                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9526             }
9527             if(isNaN(t)){
9528                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9529             }
9530
9531             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9532         },
9533
9534         /**
9535          * Returns the current scroll position of the element.
9536          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9537          */
9538         getScroll : function(){
9539             var d = this.dom, doc = document;
9540             if(d == doc || d == doc.body){
9541                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9542                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9543                 return {left: l, top: t};
9544             }else{
9545                 return {left: d.scrollLeft, top: d.scrollTop};
9546             }
9547         },
9548
9549         /**
9550          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9551          * are convert to standard 6 digit hex color.
9552          * @param {String} attr The css attribute
9553          * @param {String} defaultValue The default value to use when a valid color isn't found
9554          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9555          * YUI color anims.
9556          */
9557         getColor : function(attr, defaultValue, prefix){
9558             var v = this.getStyle(attr);
9559             if(!v || v == "transparent" || v == "inherit") {
9560                 return defaultValue;
9561             }
9562             var color = typeof prefix == "undefined" ? "#" : prefix;
9563             if(v.substr(0, 4) == "rgb("){
9564                 var rvs = v.slice(4, v.length -1).split(",");
9565                 for(var i = 0; i < 3; i++){
9566                     var h = parseInt(rvs[i]).toString(16);
9567                     if(h < 16){
9568                         h = "0" + h;
9569                     }
9570                     color += h;
9571                 }
9572             } else {
9573                 if(v.substr(0, 1) == "#"){
9574                     if(v.length == 4) {
9575                         for(var i = 1; i < 4; i++){
9576                             var c = v.charAt(i);
9577                             color +=  c + c;
9578                         }
9579                     }else if(v.length == 7){
9580                         color += v.substr(1);
9581                     }
9582                 }
9583             }
9584             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9585         },
9586
9587         /**
9588          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9589          * gradient background, rounded corners and a 4-way shadow.
9590          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9591          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9592          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9593          * @return {Roo.Element} this
9594          */
9595         boxWrap : function(cls){
9596             cls = cls || 'x-box';
9597             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9598             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9599             return el;
9600         },
9601
9602         /**
9603          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9604          * @param {String} namespace The namespace in which to look for the attribute
9605          * @param {String} name The attribute name
9606          * @return {String} The attribute value
9607          */
9608         getAttributeNS : Roo.isIE ? function(ns, name){
9609             var d = this.dom;
9610             var type = typeof d[ns+":"+name];
9611             if(type != 'undefined' && type != 'unknown'){
9612                 return d[ns+":"+name];
9613             }
9614             return d[name];
9615         } : function(ns, name){
9616             var d = this.dom;
9617             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9618         },
9619         
9620         
9621         /**
9622          * Sets or Returns the value the dom attribute value
9623          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9624          * @param {String} value (optional) The value to set the attribute to
9625          * @return {String} The attribute value
9626          */
9627         attr : function(name){
9628             if (arguments.length > 1) {
9629                 this.dom.setAttribute(name, arguments[1]);
9630                 return arguments[1];
9631             }
9632             if (typeof(name) == 'object') {
9633                 for(var i in name) {
9634                     this.attr(i, name[i]);
9635                 }
9636                 return name;
9637             }
9638             
9639             
9640             if (!this.dom.hasAttribute(name)) {
9641                 return undefined;
9642             }
9643             return this.dom.getAttribute(name);
9644         }
9645         
9646         
9647         
9648     };
9649
9650     var ep = El.prototype;
9651
9652     /**
9653      * Appends an event handler (Shorthand for addListener)
9654      * @param {String}   eventName     The type of event to append
9655      * @param {Function} fn        The method the event invokes
9656      * @param {Object} scope       (optional) The scope (this object) of the fn
9657      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9658      * @method
9659      */
9660     ep.on = ep.addListener;
9661         // backwards compat
9662     ep.mon = ep.addListener;
9663
9664     /**
9665      * Removes an event handler from this element (shorthand for removeListener)
9666      * @param {String} eventName the type of event to remove
9667      * @param {Function} fn the method the event invokes
9668      * @return {Roo.Element} this
9669      * @method
9670      */
9671     ep.un = ep.removeListener;
9672
9673     /**
9674      * true to automatically adjust width and height settings for box-model issues (default to true)
9675      */
9676     ep.autoBoxAdjust = true;
9677
9678     // private
9679     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9680
9681     // private
9682     El.addUnits = function(v, defaultUnit){
9683         if(v === "" || v == "auto"){
9684             return v;
9685         }
9686         if(v === undefined){
9687             return '';
9688         }
9689         if(typeof v == "number" || !El.unitPattern.test(v)){
9690             return v + (defaultUnit || 'px');
9691         }
9692         return v;
9693     };
9694
9695     // special markup used throughout Roo when box wrapping elements
9696     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>';
9697     /**
9698      * Visibility mode constant - Use visibility to hide element
9699      * @static
9700      * @type Number
9701      */
9702     El.VISIBILITY = 1;
9703     /**
9704      * Visibility mode constant - Use display to hide element
9705      * @static
9706      * @type Number
9707      */
9708     El.DISPLAY = 2;
9709
9710     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9711     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9712     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9713
9714
9715
9716     /**
9717      * @private
9718      */
9719     El.cache = {};
9720
9721     var docEl;
9722
9723     /**
9724      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9725      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9726      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9727      * @return {Element} The Element object
9728      * @static
9729      */
9730     El.get = function(el){
9731         var ex, elm, id;
9732         if(!el){ return null; }
9733         if(typeof el == "string"){ // element id
9734             if(!(elm = document.getElementById(el))){
9735                 return null;
9736             }
9737             if(ex = El.cache[el]){
9738                 ex.dom = elm;
9739             }else{
9740                 ex = El.cache[el] = new El(elm);
9741             }
9742             return ex;
9743         }else if(el.tagName){ // dom element
9744             if(!(id = el.id)){
9745                 id = Roo.id(el);
9746             }
9747             if(ex = El.cache[id]){
9748                 ex.dom = el;
9749             }else{
9750                 ex = El.cache[id] = new El(el);
9751             }
9752             return ex;
9753         }else if(el instanceof El){
9754             if(el != docEl){
9755                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9756                                                               // catch case where it hasn't been appended
9757                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9758             }
9759             return el;
9760         }else if(el.isComposite){
9761             return el;
9762         }else if(el instanceof Array){
9763             return El.select(el);
9764         }else if(el == document){
9765             // create a bogus element object representing the document object
9766             if(!docEl){
9767                 var f = function(){};
9768                 f.prototype = El.prototype;
9769                 docEl = new f();
9770                 docEl.dom = document;
9771             }
9772             return docEl;
9773         }
9774         return null;
9775     };
9776
9777     // private
9778     El.uncache = function(el){
9779         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9780             if(a[i]){
9781                 delete El.cache[a[i].id || a[i]];
9782             }
9783         }
9784     };
9785
9786     // private
9787     // Garbage collection - uncache elements/purge listeners on orphaned elements
9788     // so we don't hold a reference and cause the browser to retain them
9789     El.garbageCollect = function(){
9790         if(!Roo.enableGarbageCollector){
9791             clearInterval(El.collectorThread);
9792             return;
9793         }
9794         for(var eid in El.cache){
9795             var el = El.cache[eid], d = el.dom;
9796             // -------------------------------------------------------
9797             // Determining what is garbage:
9798             // -------------------------------------------------------
9799             // !d
9800             // dom node is null, definitely garbage
9801             // -------------------------------------------------------
9802             // !d.parentNode
9803             // no parentNode == direct orphan, definitely garbage
9804             // -------------------------------------------------------
9805             // !d.offsetParent && !document.getElementById(eid)
9806             // display none elements have no offsetParent so we will
9807             // also try to look it up by it's id. However, check
9808             // offsetParent first so we don't do unneeded lookups.
9809             // This enables collection of elements that are not orphans
9810             // directly, but somewhere up the line they have an orphan
9811             // parent.
9812             // -------------------------------------------------------
9813             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9814                 delete El.cache[eid];
9815                 if(d && Roo.enableListenerCollection){
9816                     E.purgeElement(d);
9817                 }
9818             }
9819         }
9820     }
9821     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9822
9823
9824     // dom is optional
9825     El.Flyweight = function(dom){
9826         this.dom = dom;
9827     };
9828     El.Flyweight.prototype = El.prototype;
9829
9830     El._flyweights = {};
9831     /**
9832      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9833      * the dom node can be overwritten by other code.
9834      * @param {String/HTMLElement} el The dom node or id
9835      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9836      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9837      * @static
9838      * @return {Element} The shared Element object
9839      */
9840     El.fly = function(el, named){
9841         named = named || '_global';
9842         el = Roo.getDom(el);
9843         if(!el){
9844             return null;
9845         }
9846         if(!El._flyweights[named]){
9847             El._flyweights[named] = new El.Flyweight();
9848         }
9849         El._flyweights[named].dom = el;
9850         return El._flyweights[named];
9851     };
9852
9853     /**
9854      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9855      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9856      * Shorthand of {@link Roo.Element#get}
9857      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9858      * @return {Element} The Element object
9859      * @member Roo
9860      * @method get
9861      */
9862     Roo.get = El.get;
9863     /**
9864      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9865      * the dom node can be overwritten by other code.
9866      * Shorthand of {@link Roo.Element#fly}
9867      * @param {String/HTMLElement} el The dom node or id
9868      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9869      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9870      * @static
9871      * @return {Element} The shared Element object
9872      * @member Roo
9873      * @method fly
9874      */
9875     Roo.fly = El.fly;
9876
9877     // speedy lookup for elements never to box adjust
9878     var noBoxAdjust = Roo.isStrict ? {
9879         select:1
9880     } : {
9881         input:1, select:1, textarea:1
9882     };
9883     if(Roo.isIE || Roo.isGecko){
9884         noBoxAdjust['button'] = 1;
9885     }
9886
9887
9888     Roo.EventManager.on(window, 'unload', function(){
9889         delete El.cache;
9890         delete El._flyweights;
9891     });
9892 })();
9893
9894
9895
9896
9897 if(Roo.DomQuery){
9898     Roo.Element.selectorFunction = Roo.DomQuery.select;
9899 }
9900
9901 Roo.Element.select = function(selector, unique, root){
9902     var els;
9903     if(typeof selector == "string"){
9904         els = Roo.Element.selectorFunction(selector, root);
9905     }else if(selector.length !== undefined){
9906         els = selector;
9907     }else{
9908         throw "Invalid selector";
9909     }
9910     if(unique === true){
9911         return new Roo.CompositeElement(els);
9912     }else{
9913         return new Roo.CompositeElementLite(els);
9914     }
9915 };
9916 /**
9917  * Selects elements based on the passed CSS selector to enable working on them as 1.
9918  * @param {String/Array} selector The CSS selector or an array of elements
9919  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9920  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9921  * @return {CompositeElementLite/CompositeElement}
9922  * @member Roo
9923  * @method select
9924  */
9925 Roo.select = Roo.Element.select;
9926
9927
9928
9929
9930
9931
9932
9933
9934
9935
9936
9937
9938
9939
9940 /*
9941  * Based on:
9942  * Ext JS Library 1.1.1
9943  * Copyright(c) 2006-2007, Ext JS, LLC.
9944  *
9945  * Originally Released Under LGPL - original licence link has changed is not relivant.
9946  *
9947  * Fork - LGPL
9948  * <script type="text/javascript">
9949  */
9950
9951
9952
9953 //Notifies Element that fx methods are available
9954 Roo.enableFx = true;
9955
9956 /**
9957  * @class Roo.Fx
9958  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9959  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9960  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9961  * Element effects to work.</p><br/>
9962  *
9963  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9964  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9965  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9966  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9967  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9968  * expected results and should be done with care.</p><br/>
9969  *
9970  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9971  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9972 <pre>
9973 Value  Description
9974 -----  -----------------------------
9975 tl     The top left corner
9976 t      The center of the top edge
9977 tr     The top right corner
9978 l      The center of the left edge
9979 r      The center of the right edge
9980 bl     The bottom left corner
9981 b      The center of the bottom edge
9982 br     The bottom right corner
9983 </pre>
9984  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9985  * below are common options that can be passed to any Fx method.</b>
9986  * @cfg {Function} callback A function called when the effect is finished
9987  * @cfg {Object} scope The scope of the effect function
9988  * @cfg {String} easing A valid Easing value for the effect
9989  * @cfg {String} afterCls A css class to apply after the effect
9990  * @cfg {Number} duration The length of time (in seconds) that the effect should last
9991  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
9992  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
9993  * effects that end with the element being visually hidden, ignored otherwise)
9994  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
9995  * a function which returns such a specification that will be applied to the Element after the effect finishes
9996  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
9997  * @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
9998  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
9999  */
10000 Roo.Fx = {
10001         /**
10002          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10003          * origin for the slide effect.  This function automatically handles wrapping the element with
10004          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10005          * Usage:
10006          *<pre><code>
10007 // default: slide the element in from the top
10008 el.slideIn();
10009
10010 // custom: slide the element in from the right with a 2-second duration
10011 el.slideIn('r', { duration: 2 });
10012
10013 // common config options shown with default values
10014 el.slideIn('t', {
10015     easing: 'easeOut',
10016     duration: .5
10017 });
10018 </code></pre>
10019          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10020          * @param {Object} options (optional) Object literal with any of the Fx config options
10021          * @return {Roo.Element} The Element
10022          */
10023     slideIn : function(anchor, o){
10024         var el = this.getFxEl();
10025         o = o || {};
10026
10027         el.queueFx(o, function(){
10028
10029             anchor = anchor || "t";
10030
10031             // fix display to visibility
10032             this.fixDisplay();
10033
10034             // restore values after effect
10035             var r = this.getFxRestore();
10036             var b = this.getBox();
10037             // fixed size for slide
10038             this.setSize(b);
10039
10040             // wrap if needed
10041             var wrap = this.fxWrap(r.pos, o, "hidden");
10042
10043             var st = this.dom.style;
10044             st.visibility = "visible";
10045             st.position = "absolute";
10046
10047             // clear out temp styles after slide and unwrap
10048             var after = function(){
10049                 el.fxUnwrap(wrap, r.pos, o);
10050                 st.width = r.width;
10051                 st.height = r.height;
10052                 el.afterFx(o);
10053             };
10054             // time to calc the positions
10055             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10056
10057             switch(anchor.toLowerCase()){
10058                 case "t":
10059                     wrap.setSize(b.width, 0);
10060                     st.left = st.bottom = "0";
10061                     a = {height: bh};
10062                 break;
10063                 case "l":
10064                     wrap.setSize(0, b.height);
10065                     st.right = st.top = "0";
10066                     a = {width: bw};
10067                 break;
10068                 case "r":
10069                     wrap.setSize(0, b.height);
10070                     wrap.setX(b.right);
10071                     st.left = st.top = "0";
10072                     a = {width: bw, points: pt};
10073                 break;
10074                 case "b":
10075                     wrap.setSize(b.width, 0);
10076                     wrap.setY(b.bottom);
10077                     st.left = st.top = "0";
10078                     a = {height: bh, points: pt};
10079                 break;
10080                 case "tl":
10081                     wrap.setSize(0, 0);
10082                     st.right = st.bottom = "0";
10083                     a = {width: bw, height: bh};
10084                 break;
10085                 case "bl":
10086                     wrap.setSize(0, 0);
10087                     wrap.setY(b.y+b.height);
10088                     st.right = st.top = "0";
10089                     a = {width: bw, height: bh, points: pt};
10090                 break;
10091                 case "br":
10092                     wrap.setSize(0, 0);
10093                     wrap.setXY([b.right, b.bottom]);
10094                     st.left = st.top = "0";
10095                     a = {width: bw, height: bh, points: pt};
10096                 break;
10097                 case "tr":
10098                     wrap.setSize(0, 0);
10099                     wrap.setX(b.x+b.width);
10100                     st.left = st.bottom = "0";
10101                     a = {width: bw, height: bh, points: pt};
10102                 break;
10103             }
10104             this.dom.style.visibility = "visible";
10105             wrap.show();
10106
10107             arguments.callee.anim = wrap.fxanim(a,
10108                 o,
10109                 'motion',
10110                 .5,
10111                 'easeOut', after);
10112         });
10113         return this;
10114     },
10115     
10116         /**
10117          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10118          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10119          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10120          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10121          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10122          * Usage:
10123          *<pre><code>
10124 // default: slide the element out to the top
10125 el.slideOut();
10126
10127 // custom: slide the element out to the right with a 2-second duration
10128 el.slideOut('r', { duration: 2 });
10129
10130 // common config options shown with default values
10131 el.slideOut('t', {
10132     easing: 'easeOut',
10133     duration: .5,
10134     remove: false,
10135     useDisplay: false
10136 });
10137 </code></pre>
10138          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10139          * @param {Object} options (optional) Object literal with any of the Fx config options
10140          * @return {Roo.Element} The Element
10141          */
10142     slideOut : function(anchor, o){
10143         var el = this.getFxEl();
10144         o = o || {};
10145
10146         el.queueFx(o, function(){
10147
10148             anchor = anchor || "t";
10149
10150             // restore values after effect
10151             var r = this.getFxRestore();
10152             
10153             var b = this.getBox();
10154             // fixed size for slide
10155             this.setSize(b);
10156
10157             // wrap if needed
10158             var wrap = this.fxWrap(r.pos, o, "visible");
10159
10160             var st = this.dom.style;
10161             st.visibility = "visible";
10162             st.position = "absolute";
10163
10164             wrap.setSize(b);
10165
10166             var after = function(){
10167                 if(o.useDisplay){
10168                     el.setDisplayed(false);
10169                 }else{
10170                     el.hide();
10171                 }
10172
10173                 el.fxUnwrap(wrap, r.pos, o);
10174
10175                 st.width = r.width;
10176                 st.height = r.height;
10177
10178                 el.afterFx(o);
10179             };
10180
10181             var a, zero = {to: 0};
10182             switch(anchor.toLowerCase()){
10183                 case "t":
10184                     st.left = st.bottom = "0";
10185                     a = {height: zero};
10186                 break;
10187                 case "l":
10188                     st.right = st.top = "0";
10189                     a = {width: zero};
10190                 break;
10191                 case "r":
10192                     st.left = st.top = "0";
10193                     a = {width: zero, points: {to:[b.right, b.y]}};
10194                 break;
10195                 case "b":
10196                     st.left = st.top = "0";
10197                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10198                 break;
10199                 case "tl":
10200                     st.right = st.bottom = "0";
10201                     a = {width: zero, height: zero};
10202                 break;
10203                 case "bl":
10204                     st.right = st.top = "0";
10205                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10206                 break;
10207                 case "br":
10208                     st.left = st.top = "0";
10209                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10210                 break;
10211                 case "tr":
10212                     st.left = st.bottom = "0";
10213                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10214                 break;
10215             }
10216
10217             arguments.callee.anim = wrap.fxanim(a,
10218                 o,
10219                 'motion',
10220                 .5,
10221                 "easeOut", after);
10222         });
10223         return this;
10224     },
10225
10226         /**
10227          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10228          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10229          * The element must be removed from the DOM using the 'remove' config option if desired.
10230          * Usage:
10231          *<pre><code>
10232 // default
10233 el.puff();
10234
10235 // common config options shown with default values
10236 el.puff({
10237     easing: 'easeOut',
10238     duration: .5,
10239     remove: false,
10240     useDisplay: false
10241 });
10242 </code></pre>
10243          * @param {Object} options (optional) Object literal with any of the Fx config options
10244          * @return {Roo.Element} The Element
10245          */
10246     puff : function(o){
10247         var el = this.getFxEl();
10248         o = o || {};
10249
10250         el.queueFx(o, function(){
10251             this.clearOpacity();
10252             this.show();
10253
10254             // restore values after effect
10255             var r = this.getFxRestore();
10256             var st = this.dom.style;
10257
10258             var after = function(){
10259                 if(o.useDisplay){
10260                     el.setDisplayed(false);
10261                 }else{
10262                     el.hide();
10263                 }
10264
10265                 el.clearOpacity();
10266
10267                 el.setPositioning(r.pos);
10268                 st.width = r.width;
10269                 st.height = r.height;
10270                 st.fontSize = '';
10271                 el.afterFx(o);
10272             };
10273
10274             var width = this.getWidth();
10275             var height = this.getHeight();
10276
10277             arguments.callee.anim = this.fxanim({
10278                     width : {to: this.adjustWidth(width * 2)},
10279                     height : {to: this.adjustHeight(height * 2)},
10280                     points : {by: [-(width * .5), -(height * .5)]},
10281                     opacity : {to: 0},
10282                     fontSize: {to:200, unit: "%"}
10283                 },
10284                 o,
10285                 'motion',
10286                 .5,
10287                 "easeOut", after);
10288         });
10289         return this;
10290     },
10291
10292         /**
10293          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10294          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10295          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10296          * Usage:
10297          *<pre><code>
10298 // default
10299 el.switchOff();
10300
10301 // all config options shown with default values
10302 el.switchOff({
10303     easing: 'easeIn',
10304     duration: .3,
10305     remove: false,
10306     useDisplay: false
10307 });
10308 </code></pre>
10309          * @param {Object} options (optional) Object literal with any of the Fx config options
10310          * @return {Roo.Element} The Element
10311          */
10312     switchOff : function(o){
10313         var el = this.getFxEl();
10314         o = o || {};
10315
10316         el.queueFx(o, function(){
10317             this.clearOpacity();
10318             this.clip();
10319
10320             // restore values after effect
10321             var r = this.getFxRestore();
10322             var st = this.dom.style;
10323
10324             var after = function(){
10325                 if(o.useDisplay){
10326                     el.setDisplayed(false);
10327                 }else{
10328                     el.hide();
10329                 }
10330
10331                 el.clearOpacity();
10332                 el.setPositioning(r.pos);
10333                 st.width = r.width;
10334                 st.height = r.height;
10335
10336                 el.afterFx(o);
10337             };
10338
10339             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10340                 this.clearOpacity();
10341                 (function(){
10342                     this.fxanim({
10343                         height:{to:1},
10344                         points:{by:[0, this.getHeight() * .5]}
10345                     }, o, 'motion', 0.3, 'easeIn', after);
10346                 }).defer(100, this);
10347             });
10348         });
10349         return this;
10350     },
10351
10352     /**
10353      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10354      * changed using the "attr" config option) and then fading back to the original color. If no original
10355      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10356      * Usage:
10357 <pre><code>
10358 // default: highlight background to yellow
10359 el.highlight();
10360
10361 // custom: highlight foreground text to blue for 2 seconds
10362 el.highlight("0000ff", { attr: 'color', duration: 2 });
10363
10364 // common config options shown with default values
10365 el.highlight("ffff9c", {
10366     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10367     endColor: (current color) or "ffffff",
10368     easing: 'easeIn',
10369     duration: 1
10370 });
10371 </code></pre>
10372      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10373      * @param {Object} options (optional) Object literal with any of the Fx config options
10374      * @return {Roo.Element} The Element
10375      */ 
10376     highlight : function(color, o){
10377         var el = this.getFxEl();
10378         o = o || {};
10379
10380         el.queueFx(o, function(){
10381             color = color || "ffff9c";
10382             attr = o.attr || "backgroundColor";
10383
10384             this.clearOpacity();
10385             this.show();
10386
10387             var origColor = this.getColor(attr);
10388             var restoreColor = this.dom.style[attr];
10389             endColor = (o.endColor || origColor) || "ffffff";
10390
10391             var after = function(){
10392                 el.dom.style[attr] = restoreColor;
10393                 el.afterFx(o);
10394             };
10395
10396             var a = {};
10397             a[attr] = {from: color, to: endColor};
10398             arguments.callee.anim = this.fxanim(a,
10399                 o,
10400                 'color',
10401                 1,
10402                 'easeIn', after);
10403         });
10404         return this;
10405     },
10406
10407    /**
10408     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10409     * Usage:
10410 <pre><code>
10411 // default: a single light blue ripple
10412 el.frame();
10413
10414 // custom: 3 red ripples lasting 3 seconds total
10415 el.frame("ff0000", 3, { duration: 3 });
10416
10417 // common config options shown with default values
10418 el.frame("C3DAF9", 1, {
10419     duration: 1 //duration of entire animation (not each individual ripple)
10420     // Note: Easing is not configurable and will be ignored if included
10421 });
10422 </code></pre>
10423     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10424     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10425     * @param {Object} options (optional) Object literal with any of the Fx config options
10426     * @return {Roo.Element} The Element
10427     */
10428     frame : function(color, count, o){
10429         var el = this.getFxEl();
10430         o = o || {};
10431
10432         el.queueFx(o, function(){
10433             color = color || "#C3DAF9";
10434             if(color.length == 6){
10435                 color = "#" + color;
10436             }
10437             count = count || 1;
10438             duration = o.duration || 1;
10439             this.show();
10440
10441             var b = this.getBox();
10442             var animFn = function(){
10443                 var proxy = this.createProxy({
10444
10445                      style:{
10446                         visbility:"hidden",
10447                         position:"absolute",
10448                         "z-index":"35000", // yee haw
10449                         border:"0px solid " + color
10450                      }
10451                   });
10452                 var scale = Roo.isBorderBox ? 2 : 1;
10453                 proxy.animate({
10454                     top:{from:b.y, to:b.y - 20},
10455                     left:{from:b.x, to:b.x - 20},
10456                     borderWidth:{from:0, to:10},
10457                     opacity:{from:1, to:0},
10458                     height:{from:b.height, to:(b.height + (20*scale))},
10459                     width:{from:b.width, to:(b.width + (20*scale))}
10460                 }, duration, function(){
10461                     proxy.remove();
10462                 });
10463                 if(--count > 0){
10464                      animFn.defer((duration/2)*1000, this);
10465                 }else{
10466                     el.afterFx(o);
10467                 }
10468             };
10469             animFn.call(this);
10470         });
10471         return this;
10472     },
10473
10474    /**
10475     * Creates a pause before any subsequent queued effects begin.  If there are
10476     * no effects queued after the pause it will have no effect.
10477     * Usage:
10478 <pre><code>
10479 el.pause(1);
10480 </code></pre>
10481     * @param {Number} seconds The length of time to pause (in seconds)
10482     * @return {Roo.Element} The Element
10483     */
10484     pause : function(seconds){
10485         var el = this.getFxEl();
10486         var o = {};
10487
10488         el.queueFx(o, function(){
10489             setTimeout(function(){
10490                 el.afterFx(o);
10491             }, seconds * 1000);
10492         });
10493         return this;
10494     },
10495
10496    /**
10497     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10498     * using the "endOpacity" config option.
10499     * Usage:
10500 <pre><code>
10501 // default: fade in from opacity 0 to 100%
10502 el.fadeIn();
10503
10504 // custom: fade in from opacity 0 to 75% over 2 seconds
10505 el.fadeIn({ endOpacity: .75, duration: 2});
10506
10507 // common config options shown with default values
10508 el.fadeIn({
10509     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10510     easing: 'easeOut',
10511     duration: .5
10512 });
10513 </code></pre>
10514     * @param {Object} options (optional) Object literal with any of the Fx config options
10515     * @return {Roo.Element} The Element
10516     */
10517     fadeIn : function(o){
10518         var el = this.getFxEl();
10519         o = o || {};
10520         el.queueFx(o, function(){
10521             this.setOpacity(0);
10522             this.fixDisplay();
10523             this.dom.style.visibility = 'visible';
10524             var to = o.endOpacity || 1;
10525             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10526                 o, null, .5, "easeOut", function(){
10527                 if(to == 1){
10528                     this.clearOpacity();
10529                 }
10530                 el.afterFx(o);
10531             });
10532         });
10533         return this;
10534     },
10535
10536    /**
10537     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10538     * using the "endOpacity" config option.
10539     * Usage:
10540 <pre><code>
10541 // default: fade out from the element's current opacity to 0
10542 el.fadeOut();
10543
10544 // custom: fade out from the element's current opacity to 25% over 2 seconds
10545 el.fadeOut({ endOpacity: .25, duration: 2});
10546
10547 // common config options shown with default values
10548 el.fadeOut({
10549     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10550     easing: 'easeOut',
10551     duration: .5
10552     remove: false,
10553     useDisplay: false
10554 });
10555 </code></pre>
10556     * @param {Object} options (optional) Object literal with any of the Fx config options
10557     * @return {Roo.Element} The Element
10558     */
10559     fadeOut : function(o){
10560         var el = this.getFxEl();
10561         o = o || {};
10562         el.queueFx(o, function(){
10563             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10564                 o, null, .5, "easeOut", function(){
10565                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10566                      this.dom.style.display = "none";
10567                 }else{
10568                      this.dom.style.visibility = "hidden";
10569                 }
10570                 this.clearOpacity();
10571                 el.afterFx(o);
10572             });
10573         });
10574         return this;
10575     },
10576
10577    /**
10578     * Animates the transition of an element's dimensions from a starting height/width
10579     * to an ending height/width.
10580     * Usage:
10581 <pre><code>
10582 // change height and width to 100x100 pixels
10583 el.scale(100, 100);
10584
10585 // common config options shown with default values.  The height and width will default to
10586 // the element's existing values if passed as null.
10587 el.scale(
10588     [element's width],
10589     [element's height], {
10590     easing: 'easeOut',
10591     duration: .35
10592 });
10593 </code></pre>
10594     * @param {Number} width  The new width (pass undefined to keep the original width)
10595     * @param {Number} height  The new height (pass undefined to keep the original height)
10596     * @param {Object} options (optional) Object literal with any of the Fx config options
10597     * @return {Roo.Element} The Element
10598     */
10599     scale : function(w, h, o){
10600         this.shift(Roo.apply({}, o, {
10601             width: w,
10602             height: h
10603         }));
10604         return this;
10605     },
10606
10607    /**
10608     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10609     * Any of these properties not specified in the config object will not be changed.  This effect 
10610     * requires that at least one new dimension, position or opacity setting must be passed in on
10611     * the config object in order for the function to have any effect.
10612     * Usage:
10613 <pre><code>
10614 // slide the element horizontally to x position 200 while changing the height and opacity
10615 el.shift({ x: 200, height: 50, opacity: .8 });
10616
10617 // common config options shown with default values.
10618 el.shift({
10619     width: [element's width],
10620     height: [element's height],
10621     x: [element's x position],
10622     y: [element's y position],
10623     opacity: [element's opacity],
10624     easing: 'easeOut',
10625     duration: .35
10626 });
10627 </code></pre>
10628     * @param {Object} options  Object literal with any of the Fx config options
10629     * @return {Roo.Element} The Element
10630     */
10631     shift : function(o){
10632         var el = this.getFxEl();
10633         o = o || {};
10634         el.queueFx(o, function(){
10635             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10636             if(w !== undefined){
10637                 a.width = {to: this.adjustWidth(w)};
10638             }
10639             if(h !== undefined){
10640                 a.height = {to: this.adjustHeight(h)};
10641             }
10642             if(x !== undefined || y !== undefined){
10643                 a.points = {to: [
10644                     x !== undefined ? x : this.getX(),
10645                     y !== undefined ? y : this.getY()
10646                 ]};
10647             }
10648             if(op !== undefined){
10649                 a.opacity = {to: op};
10650             }
10651             if(o.xy !== undefined){
10652                 a.points = {to: o.xy};
10653             }
10654             arguments.callee.anim = this.fxanim(a,
10655                 o, 'motion', .35, "easeOut", function(){
10656                 el.afterFx(o);
10657             });
10658         });
10659         return this;
10660     },
10661
10662         /**
10663          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10664          * ending point of the effect.
10665          * Usage:
10666          *<pre><code>
10667 // default: slide the element downward while fading out
10668 el.ghost();
10669
10670 // custom: slide the element out to the right with a 2-second duration
10671 el.ghost('r', { duration: 2 });
10672
10673 // common config options shown with default values
10674 el.ghost('b', {
10675     easing: 'easeOut',
10676     duration: .5
10677     remove: false,
10678     useDisplay: false
10679 });
10680 </code></pre>
10681          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10682          * @param {Object} options (optional) Object literal with any of the Fx config options
10683          * @return {Roo.Element} The Element
10684          */
10685     ghost : function(anchor, o){
10686         var el = this.getFxEl();
10687         o = o || {};
10688
10689         el.queueFx(o, function(){
10690             anchor = anchor || "b";
10691
10692             // restore values after effect
10693             var r = this.getFxRestore();
10694             var w = this.getWidth(),
10695                 h = this.getHeight();
10696
10697             var st = this.dom.style;
10698
10699             var after = function(){
10700                 if(o.useDisplay){
10701                     el.setDisplayed(false);
10702                 }else{
10703                     el.hide();
10704                 }
10705
10706                 el.clearOpacity();
10707                 el.setPositioning(r.pos);
10708                 st.width = r.width;
10709                 st.height = r.height;
10710
10711                 el.afterFx(o);
10712             };
10713
10714             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10715             switch(anchor.toLowerCase()){
10716                 case "t":
10717                     pt.by = [0, -h];
10718                 break;
10719                 case "l":
10720                     pt.by = [-w, 0];
10721                 break;
10722                 case "r":
10723                     pt.by = [w, 0];
10724                 break;
10725                 case "b":
10726                     pt.by = [0, h];
10727                 break;
10728                 case "tl":
10729                     pt.by = [-w, -h];
10730                 break;
10731                 case "bl":
10732                     pt.by = [-w, h];
10733                 break;
10734                 case "br":
10735                     pt.by = [w, h];
10736                 break;
10737                 case "tr":
10738                     pt.by = [w, -h];
10739                 break;
10740             }
10741
10742             arguments.callee.anim = this.fxanim(a,
10743                 o,
10744                 'motion',
10745                 .5,
10746                 "easeOut", after);
10747         });
10748         return this;
10749     },
10750
10751         /**
10752          * Ensures that all effects queued after syncFx is called on the element are
10753          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10754          * @return {Roo.Element} The Element
10755          */
10756     syncFx : function(){
10757         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10758             block : false,
10759             concurrent : true,
10760             stopFx : false
10761         });
10762         return this;
10763     },
10764
10765         /**
10766          * Ensures that all effects queued after sequenceFx is called on the element are
10767          * run in sequence.  This is the opposite of {@link #syncFx}.
10768          * @return {Roo.Element} The Element
10769          */
10770     sequenceFx : function(){
10771         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10772             block : false,
10773             concurrent : false,
10774             stopFx : false
10775         });
10776         return this;
10777     },
10778
10779         /* @private */
10780     nextFx : function(){
10781         var ef = this.fxQueue[0];
10782         if(ef){
10783             ef.call(this);
10784         }
10785     },
10786
10787         /**
10788          * Returns true if the element has any effects actively running or queued, else returns false.
10789          * @return {Boolean} True if element has active effects, else false
10790          */
10791     hasActiveFx : function(){
10792         return this.fxQueue && this.fxQueue[0];
10793     },
10794
10795         /**
10796          * Stops any running effects and clears the element's internal effects queue if it contains
10797          * any additional effects that haven't started yet.
10798          * @return {Roo.Element} The Element
10799          */
10800     stopFx : function(){
10801         if(this.hasActiveFx()){
10802             var cur = this.fxQueue[0];
10803             if(cur && cur.anim && cur.anim.isAnimated()){
10804                 this.fxQueue = [cur]; // clear out others
10805                 cur.anim.stop(true);
10806             }
10807         }
10808         return this;
10809     },
10810
10811         /* @private */
10812     beforeFx : function(o){
10813         if(this.hasActiveFx() && !o.concurrent){
10814            if(o.stopFx){
10815                this.stopFx();
10816                return true;
10817            }
10818            return false;
10819         }
10820         return true;
10821     },
10822
10823         /**
10824          * Returns true if the element is currently blocking so that no other effect can be queued
10825          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10826          * used to ensure that an effect initiated by a user action runs to completion prior to the
10827          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10828          * @return {Boolean} True if blocking, else false
10829          */
10830     hasFxBlock : function(){
10831         var q = this.fxQueue;
10832         return q && q[0] && q[0].block;
10833     },
10834
10835         /* @private */
10836     queueFx : function(o, fn){
10837         if(!this.fxQueue){
10838             this.fxQueue = [];
10839         }
10840         if(!this.hasFxBlock()){
10841             Roo.applyIf(o, this.fxDefaults);
10842             if(!o.concurrent){
10843                 var run = this.beforeFx(o);
10844                 fn.block = o.block;
10845                 this.fxQueue.push(fn);
10846                 if(run){
10847                     this.nextFx();
10848                 }
10849             }else{
10850                 fn.call(this);
10851             }
10852         }
10853         return this;
10854     },
10855
10856         /* @private */
10857     fxWrap : function(pos, o, vis){
10858         var wrap;
10859         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10860             var wrapXY;
10861             if(o.fixPosition){
10862                 wrapXY = this.getXY();
10863             }
10864             var div = document.createElement("div");
10865             div.style.visibility = vis;
10866             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10867             wrap.setPositioning(pos);
10868             if(wrap.getStyle("position") == "static"){
10869                 wrap.position("relative");
10870             }
10871             this.clearPositioning('auto');
10872             wrap.clip();
10873             wrap.dom.appendChild(this.dom);
10874             if(wrapXY){
10875                 wrap.setXY(wrapXY);
10876             }
10877         }
10878         return wrap;
10879     },
10880
10881         /* @private */
10882     fxUnwrap : function(wrap, pos, o){
10883         this.clearPositioning();
10884         this.setPositioning(pos);
10885         if(!o.wrap){
10886             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10887             wrap.remove();
10888         }
10889     },
10890
10891         /* @private */
10892     getFxRestore : function(){
10893         var st = this.dom.style;
10894         return {pos: this.getPositioning(), width: st.width, height : st.height};
10895     },
10896
10897         /* @private */
10898     afterFx : function(o){
10899         if(o.afterStyle){
10900             this.applyStyles(o.afterStyle);
10901         }
10902         if(o.afterCls){
10903             this.addClass(o.afterCls);
10904         }
10905         if(o.remove === true){
10906             this.remove();
10907         }
10908         Roo.callback(o.callback, o.scope, [this]);
10909         if(!o.concurrent){
10910             this.fxQueue.shift();
10911             this.nextFx();
10912         }
10913     },
10914
10915         /* @private */
10916     getFxEl : function(){ // support for composite element fx
10917         return Roo.get(this.dom);
10918     },
10919
10920         /* @private */
10921     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10922         animType = animType || 'run';
10923         opt = opt || {};
10924         var anim = Roo.lib.Anim[animType](
10925             this.dom, args,
10926             (opt.duration || defaultDur) || .35,
10927             (opt.easing || defaultEase) || 'easeOut',
10928             function(){
10929                 Roo.callback(cb, this);
10930             },
10931             this
10932         );
10933         opt.anim = anim;
10934         return anim;
10935     }
10936 };
10937
10938 // backwords compat
10939 Roo.Fx.resize = Roo.Fx.scale;
10940
10941 //When included, Roo.Fx is automatically applied to Element so that all basic
10942 //effects are available directly via the Element API
10943 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10944  * Based on:
10945  * Ext JS Library 1.1.1
10946  * Copyright(c) 2006-2007, Ext JS, LLC.
10947  *
10948  * Originally Released Under LGPL - original licence link has changed is not relivant.
10949  *
10950  * Fork - LGPL
10951  * <script type="text/javascript">
10952  */
10953
10954
10955 /**
10956  * @class Roo.CompositeElement
10957  * Standard composite class. Creates a Roo.Element for every element in the collection.
10958  * <br><br>
10959  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10960  * actions will be performed on all the elements in this collection.</b>
10961  * <br><br>
10962  * All methods return <i>this</i> and can be chained.
10963  <pre><code>
10964  var els = Roo.select("#some-el div.some-class", true);
10965  // or select directly from an existing element
10966  var el = Roo.get('some-el');
10967  el.select('div.some-class', true);
10968
10969  els.setWidth(100); // all elements become 100 width
10970  els.hide(true); // all elements fade out and hide
10971  // or
10972  els.setWidth(100).hide(true);
10973  </code></pre>
10974  */
10975 Roo.CompositeElement = function(els){
10976     this.elements = [];
10977     this.addElements(els);
10978 };
10979 Roo.CompositeElement.prototype = {
10980     isComposite: true,
10981     addElements : function(els){
10982         if(!els) return this;
10983         if(typeof els == "string"){
10984             els = Roo.Element.selectorFunction(els);
10985         }
10986         var yels = this.elements;
10987         var index = yels.length-1;
10988         for(var i = 0, len = els.length; i < len; i++) {
10989                 yels[++index] = Roo.get(els[i]);
10990         }
10991         return this;
10992     },
10993
10994     /**
10995     * Clears this composite and adds the elements returned by the passed selector.
10996     * @param {String/Array} els A string CSS selector, an array of elements or an element
10997     * @return {CompositeElement} this
10998     */
10999     fill : function(els){
11000         this.elements = [];
11001         this.add(els);
11002         return this;
11003     },
11004
11005     /**
11006     * Filters this composite to only elements that match the passed selector.
11007     * @param {String} selector A string CSS selector
11008     * @param {Boolean} inverse return inverse filter (not matches)
11009     * @return {CompositeElement} this
11010     */
11011     filter : function(selector, inverse){
11012         var els = [];
11013         inverse = inverse || false;
11014         this.each(function(el){
11015             var match = inverse ? !el.is(selector) : el.is(selector);
11016             if(match){
11017                 els[els.length] = el.dom;
11018             }
11019         });
11020         this.fill(els);
11021         return this;
11022     },
11023
11024     invoke : function(fn, args){
11025         var els = this.elements;
11026         for(var i = 0, len = els.length; i < len; i++) {
11027                 Roo.Element.prototype[fn].apply(els[i], args);
11028         }
11029         return this;
11030     },
11031     /**
11032     * Adds elements to this composite.
11033     * @param {String/Array} els A string CSS selector, an array of elements or an element
11034     * @return {CompositeElement} this
11035     */
11036     add : function(els){
11037         if(typeof els == "string"){
11038             this.addElements(Roo.Element.selectorFunction(els));
11039         }else if(els.length !== undefined){
11040             this.addElements(els);
11041         }else{
11042             this.addElements([els]);
11043         }
11044         return this;
11045     },
11046     /**
11047     * Calls the passed function passing (el, this, index) for each element in this composite.
11048     * @param {Function} fn The function to call
11049     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11050     * @return {CompositeElement} this
11051     */
11052     each : function(fn, scope){
11053         var els = this.elements;
11054         for(var i = 0, len = els.length; i < len; i++){
11055             if(fn.call(scope || els[i], els[i], this, i) === false) {
11056                 break;
11057             }
11058         }
11059         return this;
11060     },
11061
11062     /**
11063      * Returns the Element object at the specified index
11064      * @param {Number} index
11065      * @return {Roo.Element}
11066      */
11067     item : function(index){
11068         return this.elements[index] || null;
11069     },
11070
11071     /**
11072      * Returns the first Element
11073      * @return {Roo.Element}
11074      */
11075     first : function(){
11076         return this.item(0);
11077     },
11078
11079     /**
11080      * Returns the last Element
11081      * @return {Roo.Element}
11082      */
11083     last : function(){
11084         return this.item(this.elements.length-1);
11085     },
11086
11087     /**
11088      * Returns the number of elements in this composite
11089      * @return Number
11090      */
11091     getCount : function(){
11092         return this.elements.length;
11093     },
11094
11095     /**
11096      * Returns true if this composite contains the passed element
11097      * @return Boolean
11098      */
11099     contains : function(el){
11100         return this.indexOf(el) !== -1;
11101     },
11102
11103     /**
11104      * Returns true if this composite contains the passed element
11105      * @return Boolean
11106      */
11107     indexOf : function(el){
11108         return this.elements.indexOf(Roo.get(el));
11109     },
11110
11111
11112     /**
11113     * Removes the specified element(s).
11114     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11115     * or an array of any of those.
11116     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11117     * @return {CompositeElement} this
11118     */
11119     removeElement : function(el, removeDom){
11120         if(el instanceof Array){
11121             for(var i = 0, len = el.length; i < len; i++){
11122                 this.removeElement(el[i]);
11123             }
11124             return this;
11125         }
11126         var index = typeof el == 'number' ? el : this.indexOf(el);
11127         if(index !== -1){
11128             if(removeDom){
11129                 var d = this.elements[index];
11130                 if(d.dom){
11131                     d.remove();
11132                 }else{
11133                     d.parentNode.removeChild(d);
11134                 }
11135             }
11136             this.elements.splice(index, 1);
11137         }
11138         return this;
11139     },
11140
11141     /**
11142     * Replaces the specified element with the passed element.
11143     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11144     * to replace.
11145     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11146     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11147     * @return {CompositeElement} this
11148     */
11149     replaceElement : function(el, replacement, domReplace){
11150         var index = typeof el == 'number' ? el : this.indexOf(el);
11151         if(index !== -1){
11152             if(domReplace){
11153                 this.elements[index].replaceWith(replacement);
11154             }else{
11155                 this.elements.splice(index, 1, Roo.get(replacement))
11156             }
11157         }
11158         return this;
11159     },
11160
11161     /**
11162      * Removes all elements.
11163      */
11164     clear : function(){
11165         this.elements = [];
11166     }
11167 };
11168 (function(){
11169     Roo.CompositeElement.createCall = function(proto, fnName){
11170         if(!proto[fnName]){
11171             proto[fnName] = function(){
11172                 return this.invoke(fnName, arguments);
11173             };
11174         }
11175     };
11176     for(var fnName in Roo.Element.prototype){
11177         if(typeof Roo.Element.prototype[fnName] == "function"){
11178             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11179         }
11180     };
11181 })();
11182 /*
11183  * Based on:
11184  * Ext JS Library 1.1.1
11185  * Copyright(c) 2006-2007, Ext JS, LLC.
11186  *
11187  * Originally Released Under LGPL - original licence link has changed is not relivant.
11188  *
11189  * Fork - LGPL
11190  * <script type="text/javascript">
11191  */
11192
11193 /**
11194  * @class Roo.CompositeElementLite
11195  * @extends Roo.CompositeElement
11196  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11197  <pre><code>
11198  var els = Roo.select("#some-el div.some-class");
11199  // or select directly from an existing element
11200  var el = Roo.get('some-el');
11201  el.select('div.some-class');
11202
11203  els.setWidth(100); // all elements become 100 width
11204  els.hide(true); // all elements fade out and hide
11205  // or
11206  els.setWidth(100).hide(true);
11207  </code></pre><br><br>
11208  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11209  * actions will be performed on all the elements in this collection.</b>
11210  */
11211 Roo.CompositeElementLite = function(els){
11212     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11213     this.el = new Roo.Element.Flyweight();
11214 };
11215 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11216     addElements : function(els){
11217         if(els){
11218             if(els instanceof Array){
11219                 this.elements = this.elements.concat(els);
11220             }else{
11221                 var yels = this.elements;
11222                 var index = yels.length-1;
11223                 for(var i = 0, len = els.length; i < len; i++) {
11224                     yels[++index] = els[i];
11225                 }
11226             }
11227         }
11228         return this;
11229     },
11230     invoke : function(fn, args){
11231         var els = this.elements;
11232         var el = this.el;
11233         for(var i = 0, len = els.length; i < len; i++) {
11234             el.dom = els[i];
11235                 Roo.Element.prototype[fn].apply(el, args);
11236         }
11237         return this;
11238     },
11239     /**
11240      * Returns a flyweight Element of the dom element object at the specified index
11241      * @param {Number} index
11242      * @return {Roo.Element}
11243      */
11244     item : function(index){
11245         if(!this.elements[index]){
11246             return null;
11247         }
11248         this.el.dom = this.elements[index];
11249         return this.el;
11250     },
11251
11252     // fixes scope with flyweight
11253     addListener : function(eventName, handler, scope, opt){
11254         var els = this.elements;
11255         for(var i = 0, len = els.length; i < len; i++) {
11256             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11257         }
11258         return this;
11259     },
11260
11261     /**
11262     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11263     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11264     * a reference to the dom node, use el.dom.</b>
11265     * @param {Function} fn The function to call
11266     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11267     * @return {CompositeElement} this
11268     */
11269     each : function(fn, scope){
11270         var els = this.elements;
11271         var el = this.el;
11272         for(var i = 0, len = els.length; i < len; i++){
11273             el.dom = els[i];
11274                 if(fn.call(scope || el, el, this, i) === false){
11275                 break;
11276             }
11277         }
11278         return this;
11279     },
11280
11281     indexOf : function(el){
11282         return this.elements.indexOf(Roo.getDom(el));
11283     },
11284
11285     replaceElement : function(el, replacement, domReplace){
11286         var index = typeof el == 'number' ? el : this.indexOf(el);
11287         if(index !== -1){
11288             replacement = Roo.getDom(replacement);
11289             if(domReplace){
11290                 var d = this.elements[index];
11291                 d.parentNode.insertBefore(replacement, d);
11292                 d.parentNode.removeChild(d);
11293             }
11294             this.elements.splice(index, 1, replacement);
11295         }
11296         return this;
11297     }
11298 });
11299 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11300
11301 /*
11302  * Based on:
11303  * Ext JS Library 1.1.1
11304  * Copyright(c) 2006-2007, Ext JS, LLC.
11305  *
11306  * Originally Released Under LGPL - original licence link has changed is not relivant.
11307  *
11308  * Fork - LGPL
11309  * <script type="text/javascript">
11310  */
11311
11312  
11313
11314 /**
11315  * @class Roo.data.Connection
11316  * @extends Roo.util.Observable
11317  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11318  * either to a configured URL, or to a URL specified at request time.<br><br>
11319  * <p>
11320  * Requests made by this class are asynchronous, and will return immediately. No data from
11321  * the server will be available to the statement immediately following the {@link #request} call.
11322  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11323  * <p>
11324  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11325  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11326  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11327  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11328  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11329  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11330  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11331  * standard DOM methods.
11332  * @constructor
11333  * @param {Object} config a configuration object.
11334  */
11335 Roo.data.Connection = function(config){
11336     Roo.apply(this, config);
11337     this.addEvents({
11338         /**
11339          * @event beforerequest
11340          * Fires before a network request is made to retrieve a data object.
11341          * @param {Connection} conn This Connection object.
11342          * @param {Object} options The options config object passed to the {@link #request} method.
11343          */
11344         "beforerequest" : true,
11345         /**
11346          * @event requestcomplete
11347          * Fires if the request was successfully completed.
11348          * @param {Connection} conn This Connection object.
11349          * @param {Object} response The XHR object containing the response data.
11350          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11351          * @param {Object} options The options config object passed to the {@link #request} method.
11352          */
11353         "requestcomplete" : true,
11354         /**
11355          * @event requestexception
11356          * Fires if an error HTTP status was returned from the server.
11357          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11358          * @param {Connection} conn This Connection object.
11359          * @param {Object} response The XHR object containing the response data.
11360          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11361          * @param {Object} options The options config object passed to the {@link #request} method.
11362          */
11363         "requestexception" : true
11364     });
11365     Roo.data.Connection.superclass.constructor.call(this);
11366 };
11367
11368 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11369     /**
11370      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11371      */
11372     /**
11373      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11374      * extra parameters to each request made by this object. (defaults to undefined)
11375      */
11376     /**
11377      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11378      *  to each request made by this object. (defaults to undefined)
11379      */
11380     /**
11381      * @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)
11382      */
11383     /**
11384      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11385      */
11386     timeout : 30000,
11387     /**
11388      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11389      * @type Boolean
11390      */
11391     autoAbort:false,
11392
11393     /**
11394      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11395      * @type Boolean
11396      */
11397     disableCaching: true,
11398
11399     /**
11400      * Sends an HTTP request to a remote server.
11401      * @param {Object} options An object which may contain the following properties:<ul>
11402      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11403      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11404      * request, a url encoded string or a function to call to get either.</li>
11405      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11406      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11407      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11408      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11409      * <li>options {Object} The parameter to the request call.</li>
11410      * <li>success {Boolean} True if the request succeeded.</li>
11411      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11412      * </ul></li>
11413      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11414      * The callback is passed the following parameters:<ul>
11415      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11416      * <li>options {Object} The parameter to the request call.</li>
11417      * </ul></li>
11418      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11419      * The callback is passed the following parameters:<ul>
11420      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11421      * <li>options {Object} The parameter to the request call.</li>
11422      * </ul></li>
11423      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11424      * for the callback function. Defaults to the browser window.</li>
11425      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11426      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11427      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11428      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11429      * params for the post data. Any params will be appended to the URL.</li>
11430      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11431      * </ul>
11432      * @return {Number} transactionId
11433      */
11434     request : function(o){
11435         if(this.fireEvent("beforerequest", this, o) !== false){
11436             var p = o.params;
11437
11438             if(typeof p == "function"){
11439                 p = p.call(o.scope||window, o);
11440             }
11441             if(typeof p == "object"){
11442                 p = Roo.urlEncode(o.params);
11443             }
11444             if(this.extraParams){
11445                 var extras = Roo.urlEncode(this.extraParams);
11446                 p = p ? (p + '&' + extras) : extras;
11447             }
11448
11449             var url = o.url || this.url;
11450             if(typeof url == 'function'){
11451                 url = url.call(o.scope||window, o);
11452             }
11453
11454             if(o.form){
11455                 var form = Roo.getDom(o.form);
11456                 url = url || form.action;
11457
11458                 var enctype = form.getAttribute("enctype");
11459                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11460                     return this.doFormUpload(o, p, url);
11461                 }
11462                 var f = Roo.lib.Ajax.serializeForm(form);
11463                 p = p ? (p + '&' + f) : f;
11464             }
11465
11466             var hs = o.headers;
11467             if(this.defaultHeaders){
11468                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11469                 if(!o.headers){
11470                     o.headers = hs;
11471                 }
11472             }
11473
11474             var cb = {
11475                 success: this.handleResponse,
11476                 failure: this.handleFailure,
11477                 scope: this,
11478                 argument: {options: o},
11479                 timeout : o.timeout || this.timeout
11480             };
11481
11482             var method = o.method||this.method||(p ? "POST" : "GET");
11483
11484             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11485                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11486             }
11487
11488             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11489                 if(o.autoAbort){
11490                     this.abort();
11491                 }
11492             }else if(this.autoAbort !== false){
11493                 this.abort();
11494             }
11495
11496             if((method == 'GET' && p) || o.xmlData){
11497                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11498                 p = '';
11499             }
11500             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11501             return this.transId;
11502         }else{
11503             Roo.callback(o.callback, o.scope, [o, null, null]);
11504             return null;
11505         }
11506     },
11507
11508     /**
11509      * Determine whether this object has a request outstanding.
11510      * @param {Number} transactionId (Optional) defaults to the last transaction
11511      * @return {Boolean} True if there is an outstanding request.
11512      */
11513     isLoading : function(transId){
11514         if(transId){
11515             return Roo.lib.Ajax.isCallInProgress(transId);
11516         }else{
11517             return this.transId ? true : false;
11518         }
11519     },
11520
11521     /**
11522      * Aborts any outstanding request.
11523      * @param {Number} transactionId (Optional) defaults to the last transaction
11524      */
11525     abort : function(transId){
11526         if(transId || this.isLoading()){
11527             Roo.lib.Ajax.abort(transId || this.transId);
11528         }
11529     },
11530
11531     // private
11532     handleResponse : function(response){
11533         this.transId = false;
11534         var options = response.argument.options;
11535         response.argument = options ? options.argument : null;
11536         this.fireEvent("requestcomplete", this, response, options);
11537         Roo.callback(options.success, options.scope, [response, options]);
11538         Roo.callback(options.callback, options.scope, [options, true, response]);
11539     },
11540
11541     // private
11542     handleFailure : function(response, e){
11543         this.transId = false;
11544         var options = response.argument.options;
11545         response.argument = options ? options.argument : null;
11546         this.fireEvent("requestexception", this, response, options, e);
11547         Roo.callback(options.failure, options.scope, [response, options]);
11548         Roo.callback(options.callback, options.scope, [options, false, response]);
11549     },
11550
11551     // private
11552     doFormUpload : function(o, ps, url){
11553         var id = Roo.id();
11554         var frame = document.createElement('iframe');
11555         frame.id = id;
11556         frame.name = id;
11557         frame.className = 'x-hidden';
11558         if(Roo.isIE){
11559             frame.src = Roo.SSL_SECURE_URL;
11560         }
11561         document.body.appendChild(frame);
11562
11563         if(Roo.isIE){
11564            document.frames[id].name = id;
11565         }
11566
11567         var form = Roo.getDom(o.form);
11568         form.target = id;
11569         form.method = 'POST';
11570         form.enctype = form.encoding = 'multipart/form-data';
11571         if(url){
11572             form.action = url;
11573         }
11574
11575         var hiddens, hd;
11576         if(ps){ // add dynamic params
11577             hiddens = [];
11578             ps = Roo.urlDecode(ps, false);
11579             for(var k in ps){
11580                 if(ps.hasOwnProperty(k)){
11581                     hd = document.createElement('input');
11582                     hd.type = 'hidden';
11583                     hd.name = k;
11584                     hd.value = ps[k];
11585                     form.appendChild(hd);
11586                     hiddens.push(hd);
11587                 }
11588             }
11589         }
11590
11591         function cb(){
11592             var r = {  // bogus response object
11593                 responseText : '',
11594                 responseXML : null
11595             };
11596
11597             r.argument = o ? o.argument : null;
11598
11599             try { //
11600                 var doc;
11601                 if(Roo.isIE){
11602                     doc = frame.contentWindow.document;
11603                 }else {
11604                     doc = (frame.contentDocument || window.frames[id].document);
11605                 }
11606                 if(doc && doc.body){
11607                     r.responseText = doc.body.innerHTML;
11608                 }
11609                 if(doc && doc.XMLDocument){
11610                     r.responseXML = doc.XMLDocument;
11611                 }else {
11612                     r.responseXML = doc;
11613                 }
11614             }
11615             catch(e) {
11616                 // ignore
11617             }
11618
11619             Roo.EventManager.removeListener(frame, 'load', cb, this);
11620
11621             this.fireEvent("requestcomplete", this, r, o);
11622             Roo.callback(o.success, o.scope, [r, o]);
11623             Roo.callback(o.callback, o.scope, [o, true, r]);
11624
11625             setTimeout(function(){document.body.removeChild(frame);}, 100);
11626         }
11627
11628         Roo.EventManager.on(frame, 'load', cb, this);
11629         form.submit();
11630
11631         if(hiddens){ // remove dynamic params
11632             for(var i = 0, len = hiddens.length; i < len; i++){
11633                 form.removeChild(hiddens[i]);
11634             }
11635         }
11636     }
11637 });
11638 /*
11639  * Based on:
11640  * Ext JS Library 1.1.1
11641  * Copyright(c) 2006-2007, Ext JS, LLC.
11642  *
11643  * Originally Released Under LGPL - original licence link has changed is not relivant.
11644  *
11645  * Fork - LGPL
11646  * <script type="text/javascript">
11647  */
11648  
11649 /**
11650  * Global Ajax request class.
11651  * 
11652  * @class Roo.Ajax
11653  * @extends Roo.data.Connection
11654  * @static
11655  * 
11656  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11657  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11658  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11659  * @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)
11660  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11661  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11662  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11663  */
11664 Roo.Ajax = new Roo.data.Connection({
11665     // fix up the docs
11666     /**
11667      * @scope Roo.Ajax
11668      * @type {Boolear} 
11669      */
11670     autoAbort : false,
11671
11672     /**
11673      * Serialize the passed form into a url encoded string
11674      * @scope Roo.Ajax
11675      * @param {String/HTMLElement} form
11676      * @return {String}
11677      */
11678     serializeForm : function(form){
11679         return Roo.lib.Ajax.serializeForm(form);
11680     }
11681 });/*
11682  * Based on:
11683  * Ext JS Library 1.1.1
11684  * Copyright(c) 2006-2007, Ext JS, LLC.
11685  *
11686  * Originally Released Under LGPL - original licence link has changed is not relivant.
11687  *
11688  * Fork - LGPL
11689  * <script type="text/javascript">
11690  */
11691
11692  
11693 /**
11694  * @class Roo.UpdateManager
11695  * @extends Roo.util.Observable
11696  * Provides AJAX-style update for Element object.<br><br>
11697  * Usage:<br>
11698  * <pre><code>
11699  * // Get it from a Roo.Element object
11700  * var el = Roo.get("foo");
11701  * var mgr = el.getUpdateManager();
11702  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11703  * ...
11704  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11705  * <br>
11706  * // or directly (returns the same UpdateManager instance)
11707  * var mgr = new Roo.UpdateManager("myElementId");
11708  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11709  * mgr.on("update", myFcnNeedsToKnow);
11710  * <br>
11711    // short handed call directly from the element object
11712    Roo.get("foo").load({
11713         url: "bar.php",
11714         scripts:true,
11715         params: "for=bar",
11716         text: "Loading Foo..."
11717    });
11718  * </code></pre>
11719  * @constructor
11720  * Create new UpdateManager directly.
11721  * @param {String/HTMLElement/Roo.Element} el The element to update
11722  * @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).
11723  */
11724 Roo.UpdateManager = function(el, forceNew){
11725     el = Roo.get(el);
11726     if(!forceNew && el.updateManager){
11727         return el.updateManager;
11728     }
11729     /**
11730      * The Element object
11731      * @type Roo.Element
11732      */
11733     this.el = el;
11734     /**
11735      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11736      * @type String
11737      */
11738     this.defaultUrl = null;
11739
11740     this.addEvents({
11741         /**
11742          * @event beforeupdate
11743          * Fired before an update is made, return false from your handler and the update is cancelled.
11744          * @param {Roo.Element} el
11745          * @param {String/Object/Function} url
11746          * @param {String/Object} params
11747          */
11748         "beforeupdate": true,
11749         /**
11750          * @event update
11751          * Fired after successful update is made.
11752          * @param {Roo.Element} el
11753          * @param {Object} oResponseObject The response Object
11754          */
11755         "update": true,
11756         /**
11757          * @event failure
11758          * Fired on update failure.
11759          * @param {Roo.Element} el
11760          * @param {Object} oResponseObject The response Object
11761          */
11762         "failure": true
11763     });
11764     var d = Roo.UpdateManager.defaults;
11765     /**
11766      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11767      * @type String
11768      */
11769     this.sslBlankUrl = d.sslBlankUrl;
11770     /**
11771      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11772      * @type Boolean
11773      */
11774     this.disableCaching = d.disableCaching;
11775     /**
11776      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11777      * @type String
11778      */
11779     this.indicatorText = d.indicatorText;
11780     /**
11781      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11782      * @type String
11783      */
11784     this.showLoadIndicator = d.showLoadIndicator;
11785     /**
11786      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11787      * @type Number
11788      */
11789     this.timeout = d.timeout;
11790
11791     /**
11792      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11793      * @type Boolean
11794      */
11795     this.loadScripts = d.loadScripts;
11796
11797     /**
11798      * Transaction object of current executing transaction
11799      */
11800     this.transaction = null;
11801
11802     /**
11803      * @private
11804      */
11805     this.autoRefreshProcId = null;
11806     /**
11807      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11808      * @type Function
11809      */
11810     this.refreshDelegate = this.refresh.createDelegate(this);
11811     /**
11812      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11813      * @type Function
11814      */
11815     this.updateDelegate = this.update.createDelegate(this);
11816     /**
11817      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11818      * @type Function
11819      */
11820     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11821     /**
11822      * @private
11823      */
11824     this.successDelegate = this.processSuccess.createDelegate(this);
11825     /**
11826      * @private
11827      */
11828     this.failureDelegate = this.processFailure.createDelegate(this);
11829
11830     if(!this.renderer){
11831      /**
11832       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11833       */
11834     this.renderer = new Roo.UpdateManager.BasicRenderer();
11835     }
11836     
11837     Roo.UpdateManager.superclass.constructor.call(this);
11838 };
11839
11840 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11841     /**
11842      * Get the Element this UpdateManager is bound to
11843      * @return {Roo.Element} The element
11844      */
11845     getEl : function(){
11846         return this.el;
11847     },
11848     /**
11849      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11850      * @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:
11851 <pre><code>
11852 um.update({<br/>
11853     url: "your-url.php",<br/>
11854     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11855     callback: yourFunction,<br/>
11856     scope: yourObject, //(optional scope)  <br/>
11857     discardUrl: false, <br/>
11858     nocache: false,<br/>
11859     text: "Loading...",<br/>
11860     timeout: 30,<br/>
11861     scripts: false<br/>
11862 });
11863 </code></pre>
11864      * The only required property is url. The optional properties nocache, text and scripts
11865      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11866      * @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}
11867      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11868      * @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.
11869      */
11870     update : function(url, params, callback, discardUrl){
11871         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11872             var method = this.method,
11873                 cfg;
11874             if(typeof url == "object"){ // must be config object
11875                 cfg = url;
11876                 url = cfg.url;
11877                 params = params || cfg.params;
11878                 callback = callback || cfg.callback;
11879                 discardUrl = discardUrl || cfg.discardUrl;
11880                 if(callback && cfg.scope){
11881                     callback = callback.createDelegate(cfg.scope);
11882                 }
11883                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11884                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11885                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11886                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11887                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11888             }
11889             this.showLoading();
11890             if(!discardUrl){
11891                 this.defaultUrl = url;
11892             }
11893             if(typeof url == "function"){
11894                 url = url.call(this);
11895             }
11896
11897             method = method || (params ? "POST" : "GET");
11898             if(method == "GET"){
11899                 url = this.prepareUrl(url);
11900             }
11901
11902             var o = Roo.apply(cfg ||{}, {
11903                 url : url,
11904                 params: params,
11905                 success: this.successDelegate,
11906                 failure: this.failureDelegate,
11907                 callback: undefined,
11908                 timeout: (this.timeout*1000),
11909                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11910             });
11911             Roo.log("updated manager called with timeout of " + o.timeout);
11912             this.transaction = Roo.Ajax.request(o);
11913         }
11914     },
11915
11916     /**
11917      * 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.
11918      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11919      * @param {String/HTMLElement} form The form Id or form element
11920      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11921      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11922      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11923      */
11924     formUpdate : function(form, url, reset, callback){
11925         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11926             if(typeof url == "function"){
11927                 url = url.call(this);
11928             }
11929             form = Roo.getDom(form);
11930             this.transaction = Roo.Ajax.request({
11931                 form: form,
11932                 url:url,
11933                 success: this.successDelegate,
11934                 failure: this.failureDelegate,
11935                 timeout: (this.timeout*1000),
11936                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11937             });
11938             this.showLoading.defer(1, this);
11939         }
11940     },
11941
11942     /**
11943      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11944      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11945      */
11946     refresh : function(callback){
11947         if(this.defaultUrl == null){
11948             return;
11949         }
11950         this.update(this.defaultUrl, null, callback, true);
11951     },
11952
11953     /**
11954      * Set this element to auto refresh.
11955      * @param {Number} interval How often to update (in seconds).
11956      * @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)
11957      * @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}
11958      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11959      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11960      */
11961     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11962         if(refreshNow){
11963             this.update(url || this.defaultUrl, params, callback, true);
11964         }
11965         if(this.autoRefreshProcId){
11966             clearInterval(this.autoRefreshProcId);
11967         }
11968         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11969     },
11970
11971     /**
11972      * Stop auto refresh on this element.
11973      */
11974      stopAutoRefresh : function(){
11975         if(this.autoRefreshProcId){
11976             clearInterval(this.autoRefreshProcId);
11977             delete this.autoRefreshProcId;
11978         }
11979     },
11980
11981     isAutoRefreshing : function(){
11982        return this.autoRefreshProcId ? true : false;
11983     },
11984     /**
11985      * Called to update the element to "Loading" state. Override to perform custom action.
11986      */
11987     showLoading : function(){
11988         if(this.showLoadIndicator){
11989             this.el.update(this.indicatorText);
11990         }
11991     },
11992
11993     /**
11994      * Adds unique parameter to query string if disableCaching = true
11995      * @private
11996      */
11997     prepareUrl : function(url){
11998         if(this.disableCaching){
11999             var append = "_dc=" + (new Date().getTime());
12000             if(url.indexOf("?") !== -1){
12001                 url += "&" + append;
12002             }else{
12003                 url += "?" + append;
12004             }
12005         }
12006         return url;
12007     },
12008
12009     /**
12010      * @private
12011      */
12012     processSuccess : function(response){
12013         this.transaction = null;
12014         if(response.argument.form && response.argument.reset){
12015             try{ // put in try/catch since some older FF releases had problems with this
12016                 response.argument.form.reset();
12017             }catch(e){}
12018         }
12019         if(this.loadScripts){
12020             this.renderer.render(this.el, response, this,
12021                 this.updateComplete.createDelegate(this, [response]));
12022         }else{
12023             this.renderer.render(this.el, response, this);
12024             this.updateComplete(response);
12025         }
12026     },
12027
12028     updateComplete : function(response){
12029         this.fireEvent("update", this.el, response);
12030         if(typeof response.argument.callback == "function"){
12031             response.argument.callback(this.el, true, response);
12032         }
12033     },
12034
12035     /**
12036      * @private
12037      */
12038     processFailure : function(response){
12039         this.transaction = null;
12040         this.fireEvent("failure", this.el, response);
12041         if(typeof response.argument.callback == "function"){
12042             response.argument.callback(this.el, false, response);
12043         }
12044     },
12045
12046     /**
12047      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12048      * @param {Object} renderer The object implementing the render() method
12049      */
12050     setRenderer : function(renderer){
12051         this.renderer = renderer;
12052     },
12053
12054     getRenderer : function(){
12055        return this.renderer;
12056     },
12057
12058     /**
12059      * Set the defaultUrl used for updates
12060      * @param {String/Function} defaultUrl The url or a function to call to get the url
12061      */
12062     setDefaultUrl : function(defaultUrl){
12063         this.defaultUrl = defaultUrl;
12064     },
12065
12066     /**
12067      * Aborts the executing transaction
12068      */
12069     abort : function(){
12070         if(this.transaction){
12071             Roo.Ajax.abort(this.transaction);
12072         }
12073     },
12074
12075     /**
12076      * Returns true if an update is in progress
12077      * @return {Boolean}
12078      */
12079     isUpdating : function(){
12080         if(this.transaction){
12081             return Roo.Ajax.isLoading(this.transaction);
12082         }
12083         return false;
12084     }
12085 });
12086
12087 /**
12088  * @class Roo.UpdateManager.defaults
12089  * @static (not really - but it helps the doc tool)
12090  * The defaults collection enables customizing the default properties of UpdateManager
12091  */
12092    Roo.UpdateManager.defaults = {
12093        /**
12094          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12095          * @type Number
12096          */
12097          timeout : 30,
12098
12099          /**
12100          * True to process scripts by default (Defaults to false).
12101          * @type Boolean
12102          */
12103         loadScripts : false,
12104
12105         /**
12106         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12107         * @type String
12108         */
12109         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12110         /**
12111          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12112          * @type Boolean
12113          */
12114         disableCaching : false,
12115         /**
12116          * Whether to show indicatorText when loading (Defaults to true).
12117          * @type Boolean
12118          */
12119         showLoadIndicator : true,
12120         /**
12121          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12122          * @type String
12123          */
12124         indicatorText : '<div class="loading-indicator">Loading...</div>'
12125    };
12126
12127 /**
12128  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12129  *Usage:
12130  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12131  * @param {String/HTMLElement/Roo.Element} el The element to update
12132  * @param {String} url The url
12133  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12134  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12135  * @static
12136  * @deprecated
12137  * @member Roo.UpdateManager
12138  */
12139 Roo.UpdateManager.updateElement = function(el, url, params, options){
12140     var um = Roo.get(el, true).getUpdateManager();
12141     Roo.apply(um, options);
12142     um.update(url, params, options ? options.callback : null);
12143 };
12144 // alias for backwards compat
12145 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12146 /**
12147  * @class Roo.UpdateManager.BasicRenderer
12148  * Default Content renderer. Updates the elements innerHTML with the responseText.
12149  */
12150 Roo.UpdateManager.BasicRenderer = function(){};
12151
12152 Roo.UpdateManager.BasicRenderer.prototype = {
12153     /**
12154      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12155      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12156      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12157      * @param {Roo.Element} el The element being rendered
12158      * @param {Object} response The YUI Connect response object
12159      * @param {UpdateManager} updateManager The calling update manager
12160      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12161      */
12162      render : function(el, response, updateManager, callback){
12163         el.update(response.responseText, updateManager.loadScripts, callback);
12164     }
12165 };
12166 /*
12167  * Based on:
12168  * Roo JS
12169  * (c)) Alan Knowles
12170  * Licence : LGPL
12171  */
12172
12173
12174 /**
12175  * @class Roo.DomTemplate
12176  * @extends Roo.Template
12177  * An effort at a dom based template engine..
12178  *
12179  * Similar to XTemplate, except it uses dom parsing to create the template..
12180  *
12181  * Supported features:
12182  *
12183  *  Tags:
12184
12185 <pre><code>
12186       {a_variable} - output encoded.
12187       {a_variable.format:("Y-m-d")} - call a method on the variable
12188       {a_variable:raw} - unencoded output
12189       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12190       {a_variable:this.method_on_template(...)} - call a method on the template object.
12191  
12192 </code></pre>
12193  *  The tpl tag:
12194 <pre><code>
12195         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12196         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12197         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12198         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12199   
12200 </code></pre>
12201  *      
12202  */
12203 Roo.DomTemplate = function()
12204 {
12205      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12206      if (this.html) {
12207         this.compile();
12208      }
12209 };
12210
12211
12212 Roo.extend(Roo.DomTemplate, Roo.Template, {
12213     /**
12214      * id counter for sub templates.
12215      */
12216     id : 0,
12217     /**
12218      * flag to indicate if dom parser is inside a pre,
12219      * it will strip whitespace if not.
12220      */
12221     inPre : false,
12222     
12223     /**
12224      * The various sub templates
12225      */
12226     tpls : false,
12227     
12228     
12229     
12230     /**
12231      *
12232      * basic tag replacing syntax
12233      * WORD:WORD()
12234      *
12235      * // you can fake an object call by doing this
12236      *  x.t:(test,tesT) 
12237      * 
12238      */
12239     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12240     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12241     
12242     iterChild : function (node, method) {
12243         
12244         var oldPre = this.inPre;
12245         if (node.tagName == 'PRE') {
12246             this.inPre = true;
12247         }
12248         for( var i = 0; i < node.childNodes.length; i++) {
12249             method.call(this, node.childNodes[i]);
12250         }
12251         this.inPre = oldPre;
12252     },
12253     
12254     
12255     
12256     /**
12257      * compile the template
12258      *
12259      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12260      *
12261      */
12262     compile: function()
12263     {
12264         var s = this.html;
12265         
12266         // covert the html into DOM...
12267         var doc = false;
12268         var div =false;
12269         try {
12270             doc = document.implementation.createHTMLDocument("");
12271             doc.documentElement.innerHTML =   this.html  ;
12272             div = doc.documentElement;
12273         } catch (e) {
12274             // old IE... - nasty -- it causes all sorts of issues.. with
12275             // images getting pulled from server..
12276             div = document.createElement('div');
12277             div.innerHTML = this.html;
12278         }
12279         //doc.documentElement.innerHTML = htmlBody
12280          
12281         
12282         
12283         this.tpls = [];
12284         var _t = this;
12285         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12286         
12287         var tpls = this.tpls;
12288         
12289         // create a top level template from the snippet..
12290         
12291         //Roo.log(div.innerHTML);
12292         
12293         var tpl = {
12294             uid : 'master',
12295             id : this.id++,
12296             attr : false,
12297             value : false,
12298             body : div.innerHTML,
12299             
12300             forCall : false,
12301             execCall : false,
12302             dom : div,
12303             isTop : true
12304             
12305         };
12306         tpls.unshift(tpl);
12307         
12308         
12309         // compile them...
12310         this.tpls = [];
12311         Roo.each(tpls, function(tp){
12312             this.compileTpl(tp);
12313             this.tpls[tp.id] = tp;
12314         }, this);
12315         
12316         this.master = tpls[0];
12317         return this;
12318         
12319         
12320     },
12321     
12322     compileNode : function(node, istop) {
12323         // test for
12324         //Roo.log(node);
12325         
12326         
12327         // skip anything not a tag..
12328         if (node.nodeType != 1) {
12329             if (node.nodeType == 3 && !this.inPre) {
12330                 // reduce white space..
12331                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12332                 
12333             }
12334             return;
12335         }
12336         
12337         var tpl = {
12338             uid : false,
12339             id : false,
12340             attr : false,
12341             value : false,
12342             body : '',
12343             
12344             forCall : false,
12345             execCall : false,
12346             dom : false,
12347             isTop : istop
12348             
12349             
12350         };
12351         
12352         
12353         switch(true) {
12354             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12355             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12356             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12357             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12358             // no default..
12359         }
12360         
12361         
12362         if (!tpl.attr) {
12363             // just itterate children..
12364             this.iterChild(node,this.compileNode);
12365             return;
12366         }
12367         tpl.uid = this.id++;
12368         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12369         node.removeAttribute('roo-'+ tpl.attr);
12370         if (tpl.attr != 'name') {
12371             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12372             node.parentNode.replaceChild(placeholder,  node);
12373         } else {
12374             
12375             var placeholder =  document.createElement('span');
12376             placeholder.className = 'roo-tpl-' + tpl.value;
12377             node.parentNode.replaceChild(placeholder,  node);
12378         }
12379         
12380         // parent now sees '{domtplXXXX}
12381         this.iterChild(node,this.compileNode);
12382         
12383         // we should now have node body...
12384         var div = document.createElement('div');
12385         div.appendChild(node);
12386         tpl.dom = node;
12387         // this has the unfortunate side effect of converting tagged attributes
12388         // eg. href="{...}" into %7C...%7D
12389         // this has been fixed by searching for those combo's although it's a bit hacky..
12390         
12391         
12392         tpl.body = div.innerHTML;
12393         
12394         
12395          
12396         tpl.id = tpl.uid;
12397         switch(tpl.attr) {
12398             case 'for' :
12399                 switch (tpl.value) {
12400                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12401                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12402                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12403                 }
12404                 break;
12405             
12406             case 'exec':
12407                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12408                 break;
12409             
12410             case 'if':     
12411                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12412                 break;
12413             
12414             case 'name':
12415                 tpl.id  = tpl.value; // replace non characters???
12416                 break;
12417             
12418         }
12419         
12420         
12421         this.tpls.push(tpl);
12422         
12423         
12424         
12425     },
12426     
12427     
12428     
12429     
12430     /**
12431      * Compile a segment of the template into a 'sub-template'
12432      *
12433      * 
12434      * 
12435      *
12436      */
12437     compileTpl : function(tpl)
12438     {
12439         var fm = Roo.util.Format;
12440         var useF = this.disableFormats !== true;
12441         
12442         var sep = Roo.isGecko ? "+\n" : ",\n";
12443         
12444         var undef = function(str) {
12445             Roo.debug && Roo.log("Property not found :"  + str);
12446             return '';
12447         };
12448           
12449         //Roo.log(tpl.body);
12450         
12451         
12452         
12453         var fn = function(m, lbrace, name, format, args)
12454         {
12455             //Roo.log("ARGS");
12456             //Roo.log(arguments);
12457             args = args ? args.replace(/\\'/g,"'") : args;
12458             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12459             if (typeof(format) == 'undefined') {
12460                 format =  'htmlEncode'; 
12461             }
12462             if (format == 'raw' ) {
12463                 format = false;
12464             }
12465             
12466             if(name.substr(0, 6) == 'domtpl'){
12467                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12468             }
12469             
12470             // build an array of options to determine if value is undefined..
12471             
12472             // basically get 'xxxx.yyyy' then do
12473             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12474             //    (function () { Roo.log("Property not found"); return ''; })() :
12475             //    ......
12476             
12477             var udef_ar = [];
12478             var lookfor = '';
12479             Roo.each(name.split('.'), function(st) {
12480                 lookfor += (lookfor.length ? '.': '') + st;
12481                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12482             });
12483             
12484             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12485             
12486             
12487             if(format && useF){
12488                 
12489                 args = args ? ',' + args : "";
12490                  
12491                 if(format.substr(0, 5) != "this."){
12492                     format = "fm." + format + '(';
12493                 }else{
12494                     format = 'this.call("'+ format.substr(5) + '", ';
12495                     args = ", values";
12496                 }
12497                 
12498                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12499             }
12500              
12501             if (args && args.length) {
12502                 // called with xxyx.yuu:(test,test)
12503                 // change to ()
12504                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12505             }
12506             // raw.. - :raw modifier..
12507             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12508             
12509         };
12510         var body;
12511         // branched to use + in gecko and [].join() in others
12512         if(Roo.isGecko){
12513             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12514                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12515                     "';};};";
12516         }else{
12517             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12518             body.push(tpl.body.replace(/(\r\n|\n)/g,
12519                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12520             body.push("'].join('');};};");
12521             body = body.join('');
12522         }
12523         
12524         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12525        
12526         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12527         eval(body);
12528         
12529         return this;
12530     },
12531      
12532     /**
12533      * same as applyTemplate, except it's done to one of the subTemplates
12534      * when using named templates, you can do:
12535      *
12536      * var str = pl.applySubTemplate('your-name', values);
12537      *
12538      * 
12539      * @param {Number} id of the template
12540      * @param {Object} values to apply to template
12541      * @param {Object} parent (normaly the instance of this object)
12542      */
12543     applySubTemplate : function(id, values, parent)
12544     {
12545         
12546         
12547         var t = this.tpls[id];
12548         
12549         
12550         try { 
12551             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12552                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12553                 return '';
12554             }
12555         } catch(e) {
12556             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12557             Roo.log(values);
12558           
12559             return '';
12560         }
12561         try { 
12562             
12563             if(t.execCall && t.execCall.call(this, values, parent)){
12564                 return '';
12565             }
12566         } catch(e) {
12567             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12568             Roo.log(values);
12569             return '';
12570         }
12571         
12572         try {
12573             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12574             parent = t.target ? values : parent;
12575             if(t.forCall && vs instanceof Array){
12576                 var buf = [];
12577                 for(var i = 0, len = vs.length; i < len; i++){
12578                     try {
12579                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12580                     } catch (e) {
12581                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12582                         Roo.log(e.body);
12583                         //Roo.log(t.compiled);
12584                         Roo.log(vs[i]);
12585                     }   
12586                 }
12587                 return buf.join('');
12588             }
12589         } catch (e) {
12590             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12591             Roo.log(values);
12592             return '';
12593         }
12594         try {
12595             return t.compiled.call(this, vs, parent);
12596         } catch (e) {
12597             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12598             Roo.log(e.body);
12599             //Roo.log(t.compiled);
12600             Roo.log(values);
12601             return '';
12602         }
12603     },
12604
12605    
12606
12607     applyTemplate : function(values){
12608         return this.master.compiled.call(this, values, {});
12609         //var s = this.subs;
12610     },
12611
12612     apply : function(){
12613         return this.applyTemplate.apply(this, arguments);
12614     }
12615
12616  });
12617
12618 Roo.DomTemplate.from = function(el){
12619     el = Roo.getDom(el);
12620     return new Roo.Domtemplate(el.value || el.innerHTML);
12621 };/*
12622  * Based on:
12623  * Ext JS Library 1.1.1
12624  * Copyright(c) 2006-2007, Ext JS, LLC.
12625  *
12626  * Originally Released Under LGPL - original licence link has changed is not relivant.
12627  *
12628  * Fork - LGPL
12629  * <script type="text/javascript">
12630  */
12631
12632 /**
12633  * @class Roo.util.DelayedTask
12634  * Provides a convenient method of performing setTimeout where a new
12635  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12636  * You can use this class to buffer
12637  * the keypress events for a certain number of milliseconds, and perform only if they stop
12638  * for that amount of time.
12639  * @constructor The parameters to this constructor serve as defaults and are not required.
12640  * @param {Function} fn (optional) The default function to timeout
12641  * @param {Object} scope (optional) The default scope of that timeout
12642  * @param {Array} args (optional) The default Array of arguments
12643  */
12644 Roo.util.DelayedTask = function(fn, scope, args){
12645     var id = null, d, t;
12646
12647     var call = function(){
12648         var now = new Date().getTime();
12649         if(now - t >= d){
12650             clearInterval(id);
12651             id = null;
12652             fn.apply(scope, args || []);
12653         }
12654     };
12655     /**
12656      * Cancels any pending timeout and queues a new one
12657      * @param {Number} delay The milliseconds to delay
12658      * @param {Function} newFn (optional) Overrides function passed to constructor
12659      * @param {Object} newScope (optional) Overrides scope passed to constructor
12660      * @param {Array} newArgs (optional) Overrides args passed to constructor
12661      */
12662     this.delay = function(delay, newFn, newScope, newArgs){
12663         if(id && delay != d){
12664             this.cancel();
12665         }
12666         d = delay;
12667         t = new Date().getTime();
12668         fn = newFn || fn;
12669         scope = newScope || scope;
12670         args = newArgs || args;
12671         if(!id){
12672             id = setInterval(call, d);
12673         }
12674     };
12675
12676     /**
12677      * Cancel the last queued timeout
12678      */
12679     this.cancel = function(){
12680         if(id){
12681             clearInterval(id);
12682             id = null;
12683         }
12684     };
12685 };/*
12686  * Based on:
12687  * Ext JS Library 1.1.1
12688  * Copyright(c) 2006-2007, Ext JS, LLC.
12689  *
12690  * Originally Released Under LGPL - original licence link has changed is not relivant.
12691  *
12692  * Fork - LGPL
12693  * <script type="text/javascript">
12694  */
12695  
12696  
12697 Roo.util.TaskRunner = function(interval){
12698     interval = interval || 10;
12699     var tasks = [], removeQueue = [];
12700     var id = 0;
12701     var running = false;
12702
12703     var stopThread = function(){
12704         running = false;
12705         clearInterval(id);
12706         id = 0;
12707     };
12708
12709     var startThread = function(){
12710         if(!running){
12711             running = true;
12712             id = setInterval(runTasks, interval);
12713         }
12714     };
12715
12716     var removeTask = function(task){
12717         removeQueue.push(task);
12718         if(task.onStop){
12719             task.onStop();
12720         }
12721     };
12722
12723     var runTasks = function(){
12724         if(removeQueue.length > 0){
12725             for(var i = 0, len = removeQueue.length; i < len; i++){
12726                 tasks.remove(removeQueue[i]);
12727             }
12728             removeQueue = [];
12729             if(tasks.length < 1){
12730                 stopThread();
12731                 return;
12732             }
12733         }
12734         var now = new Date().getTime();
12735         for(var i = 0, len = tasks.length; i < len; ++i){
12736             var t = tasks[i];
12737             var itime = now - t.taskRunTime;
12738             if(t.interval <= itime){
12739                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12740                 t.taskRunTime = now;
12741                 if(rt === false || t.taskRunCount === t.repeat){
12742                     removeTask(t);
12743                     return;
12744                 }
12745             }
12746             if(t.duration && t.duration <= (now - t.taskStartTime)){
12747                 removeTask(t);
12748             }
12749         }
12750     };
12751
12752     /**
12753      * Queues a new task.
12754      * @param {Object} task
12755      */
12756     this.start = function(task){
12757         tasks.push(task);
12758         task.taskStartTime = new Date().getTime();
12759         task.taskRunTime = 0;
12760         task.taskRunCount = 0;
12761         startThread();
12762         return task;
12763     };
12764
12765     this.stop = function(task){
12766         removeTask(task);
12767         return task;
12768     };
12769
12770     this.stopAll = function(){
12771         stopThread();
12772         for(var i = 0, len = tasks.length; i < len; i++){
12773             if(tasks[i].onStop){
12774                 tasks[i].onStop();
12775             }
12776         }
12777         tasks = [];
12778         removeQueue = [];
12779     };
12780 };
12781
12782 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12783  * Based on:
12784  * Ext JS Library 1.1.1
12785  * Copyright(c) 2006-2007, Ext JS, LLC.
12786  *
12787  * Originally Released Under LGPL - original licence link has changed is not relivant.
12788  *
12789  * Fork - LGPL
12790  * <script type="text/javascript">
12791  */
12792
12793  
12794 /**
12795  * @class Roo.util.MixedCollection
12796  * @extends Roo.util.Observable
12797  * A Collection class that maintains both numeric indexes and keys and exposes events.
12798  * @constructor
12799  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12800  * collection (defaults to false)
12801  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12802  * and return the key value for that item.  This is used when available to look up the key on items that
12803  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12804  * equivalent to providing an implementation for the {@link #getKey} method.
12805  */
12806 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12807     this.items = [];
12808     this.map = {};
12809     this.keys = [];
12810     this.length = 0;
12811     this.addEvents({
12812         /**
12813          * @event clear
12814          * Fires when the collection is cleared.
12815          */
12816         "clear" : true,
12817         /**
12818          * @event add
12819          * Fires when an item is added to the collection.
12820          * @param {Number} index The index at which the item was added.
12821          * @param {Object} o The item added.
12822          * @param {String} key The key associated with the added item.
12823          */
12824         "add" : true,
12825         /**
12826          * @event replace
12827          * Fires when an item is replaced in the collection.
12828          * @param {String} key he key associated with the new added.
12829          * @param {Object} old The item being replaced.
12830          * @param {Object} new The new item.
12831          */
12832         "replace" : true,
12833         /**
12834          * @event remove
12835          * Fires when an item is removed from the collection.
12836          * @param {Object} o The item being removed.
12837          * @param {String} key (optional) The key associated with the removed item.
12838          */
12839         "remove" : true,
12840         "sort" : true
12841     });
12842     this.allowFunctions = allowFunctions === true;
12843     if(keyFn){
12844         this.getKey = keyFn;
12845     }
12846     Roo.util.MixedCollection.superclass.constructor.call(this);
12847 };
12848
12849 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12850     allowFunctions : false,
12851     
12852 /**
12853  * Adds an item to the collection.
12854  * @param {String} key The key to associate with the item
12855  * @param {Object} o The item to add.
12856  * @return {Object} The item added.
12857  */
12858     add : function(key, o){
12859         if(arguments.length == 1){
12860             o = arguments[0];
12861             key = this.getKey(o);
12862         }
12863         if(typeof key == "undefined" || key === null){
12864             this.length++;
12865             this.items.push(o);
12866             this.keys.push(null);
12867         }else{
12868             var old = this.map[key];
12869             if(old){
12870                 return this.replace(key, o);
12871             }
12872             this.length++;
12873             this.items.push(o);
12874             this.map[key] = o;
12875             this.keys.push(key);
12876         }
12877         this.fireEvent("add", this.length-1, o, key);
12878         return o;
12879     },
12880        
12881 /**
12882   * MixedCollection has a generic way to fetch keys if you implement getKey.
12883 <pre><code>
12884 // normal way
12885 var mc = new Roo.util.MixedCollection();
12886 mc.add(someEl.dom.id, someEl);
12887 mc.add(otherEl.dom.id, otherEl);
12888 //and so on
12889
12890 // using getKey
12891 var mc = new Roo.util.MixedCollection();
12892 mc.getKey = function(el){
12893    return el.dom.id;
12894 };
12895 mc.add(someEl);
12896 mc.add(otherEl);
12897
12898 // or via the constructor
12899 var mc = new Roo.util.MixedCollection(false, function(el){
12900    return el.dom.id;
12901 });
12902 mc.add(someEl);
12903 mc.add(otherEl);
12904 </code></pre>
12905  * @param o {Object} The item for which to find the key.
12906  * @return {Object} The key for the passed item.
12907  */
12908     getKey : function(o){
12909          return o.id; 
12910     },
12911    
12912 /**
12913  * Replaces an item in the collection.
12914  * @param {String} key The key associated with the item to replace, or the item to replace.
12915  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12916  * @return {Object}  The new item.
12917  */
12918     replace : function(key, o){
12919         if(arguments.length == 1){
12920             o = arguments[0];
12921             key = this.getKey(o);
12922         }
12923         var old = this.item(key);
12924         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12925              return this.add(key, o);
12926         }
12927         var index = this.indexOfKey(key);
12928         this.items[index] = o;
12929         this.map[key] = o;
12930         this.fireEvent("replace", key, old, o);
12931         return o;
12932     },
12933    
12934 /**
12935  * Adds all elements of an Array or an Object to the collection.
12936  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12937  * an Array of values, each of which are added to the collection.
12938  */
12939     addAll : function(objs){
12940         if(arguments.length > 1 || objs instanceof Array){
12941             var args = arguments.length > 1 ? arguments : objs;
12942             for(var i = 0, len = args.length; i < len; i++){
12943                 this.add(args[i]);
12944             }
12945         }else{
12946             for(var key in objs){
12947                 if(this.allowFunctions || typeof objs[key] != "function"){
12948                     this.add(key, objs[key]);
12949                 }
12950             }
12951         }
12952     },
12953    
12954 /**
12955  * Executes the specified function once for every item in the collection, passing each
12956  * item as the first and only parameter. returning false from the function will stop the iteration.
12957  * @param {Function} fn The function to execute for each item.
12958  * @param {Object} scope (optional) The scope in which to execute the function.
12959  */
12960     each : function(fn, scope){
12961         var items = [].concat(this.items); // each safe for removal
12962         for(var i = 0, len = items.length; i < len; i++){
12963             if(fn.call(scope || items[i], items[i], i, len) === false){
12964                 break;
12965             }
12966         }
12967     },
12968    
12969 /**
12970  * Executes the specified function once for every key in the collection, passing each
12971  * key, and its associated item as the first two parameters.
12972  * @param {Function} fn The function to execute for each item.
12973  * @param {Object} scope (optional) The scope in which to execute the function.
12974  */
12975     eachKey : function(fn, scope){
12976         for(var i = 0, len = this.keys.length; i < len; i++){
12977             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12978         }
12979     },
12980    
12981 /**
12982  * Returns the first item in the collection which elicits a true return value from the
12983  * passed selection function.
12984  * @param {Function} fn The selection function to execute for each item.
12985  * @param {Object} scope (optional) The scope in which to execute the function.
12986  * @return {Object} The first item in the collection which returned true from the selection function.
12987  */
12988     find : function(fn, scope){
12989         for(var i = 0, len = this.items.length; i < len; i++){
12990             if(fn.call(scope || window, this.items[i], this.keys[i])){
12991                 return this.items[i];
12992             }
12993         }
12994         return null;
12995     },
12996    
12997 /**
12998  * Inserts an item at the specified index in the collection.
12999  * @param {Number} index The index to insert the item at.
13000  * @param {String} key The key to associate with the new item, or the item itself.
13001  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13002  * @return {Object} The item inserted.
13003  */
13004     insert : function(index, key, o){
13005         if(arguments.length == 2){
13006             o = arguments[1];
13007             key = this.getKey(o);
13008         }
13009         if(index >= this.length){
13010             return this.add(key, o);
13011         }
13012         this.length++;
13013         this.items.splice(index, 0, o);
13014         if(typeof key != "undefined" && key != null){
13015             this.map[key] = o;
13016         }
13017         this.keys.splice(index, 0, key);
13018         this.fireEvent("add", index, o, key);
13019         return o;
13020     },
13021    
13022 /**
13023  * Removed an item from the collection.
13024  * @param {Object} o The item to remove.
13025  * @return {Object} The item removed.
13026  */
13027     remove : function(o){
13028         return this.removeAt(this.indexOf(o));
13029     },
13030    
13031 /**
13032  * Remove an item from a specified index in the collection.
13033  * @param {Number} index The index within the collection of the item to remove.
13034  */
13035     removeAt : function(index){
13036         if(index < this.length && index >= 0){
13037             this.length--;
13038             var o = this.items[index];
13039             this.items.splice(index, 1);
13040             var key = this.keys[index];
13041             if(typeof key != "undefined"){
13042                 delete this.map[key];
13043             }
13044             this.keys.splice(index, 1);
13045             this.fireEvent("remove", o, key);
13046         }
13047     },
13048    
13049 /**
13050  * Removed an item associated with the passed key fom the collection.
13051  * @param {String} key The key of the item to remove.
13052  */
13053     removeKey : function(key){
13054         return this.removeAt(this.indexOfKey(key));
13055     },
13056    
13057 /**
13058  * Returns the number of items in the collection.
13059  * @return {Number} the number of items in the collection.
13060  */
13061     getCount : function(){
13062         return this.length; 
13063     },
13064    
13065 /**
13066  * Returns index within the collection of the passed Object.
13067  * @param {Object} o The item to find the index of.
13068  * @return {Number} index of the item.
13069  */
13070     indexOf : function(o){
13071         if(!this.items.indexOf){
13072             for(var i = 0, len = this.items.length; i < len; i++){
13073                 if(this.items[i] == o) return i;
13074             }
13075             return -1;
13076         }else{
13077             return this.items.indexOf(o);
13078         }
13079     },
13080    
13081 /**
13082  * Returns index within the collection of the passed key.
13083  * @param {String} key The key to find the index of.
13084  * @return {Number} index of the key.
13085  */
13086     indexOfKey : function(key){
13087         if(!this.keys.indexOf){
13088             for(var i = 0, len = this.keys.length; i < len; i++){
13089                 if(this.keys[i] == key) return i;
13090             }
13091             return -1;
13092         }else{
13093             return this.keys.indexOf(key);
13094         }
13095     },
13096    
13097 /**
13098  * Returns the item associated with the passed key OR index. Key has priority over index.
13099  * @param {String/Number} key The key or index of the item.
13100  * @return {Object} The item associated with the passed key.
13101  */
13102     item : function(key){
13103         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13104         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13105     },
13106     
13107 /**
13108  * Returns the item at the specified index.
13109  * @param {Number} index The index of the item.
13110  * @return {Object}
13111  */
13112     itemAt : function(index){
13113         return this.items[index];
13114     },
13115     
13116 /**
13117  * Returns the item associated with the passed key.
13118  * @param {String/Number} key The key of the item.
13119  * @return {Object} The item associated with the passed key.
13120  */
13121     key : function(key){
13122         return this.map[key];
13123     },
13124    
13125 /**
13126  * Returns true if the collection contains the passed Object as an item.
13127  * @param {Object} o  The Object to look for in the collection.
13128  * @return {Boolean} True if the collection contains the Object as an item.
13129  */
13130     contains : function(o){
13131         return this.indexOf(o) != -1;
13132     },
13133    
13134 /**
13135  * Returns true if the collection contains the passed Object as a key.
13136  * @param {String} key The key to look for in the collection.
13137  * @return {Boolean} True if the collection contains the Object as a key.
13138  */
13139     containsKey : function(key){
13140         return typeof this.map[key] != "undefined";
13141     },
13142    
13143 /**
13144  * Removes all items from the collection.
13145  */
13146     clear : function(){
13147         this.length = 0;
13148         this.items = [];
13149         this.keys = [];
13150         this.map = {};
13151         this.fireEvent("clear");
13152     },
13153    
13154 /**
13155  * Returns the first item in the collection.
13156  * @return {Object} the first item in the collection..
13157  */
13158     first : function(){
13159         return this.items[0]; 
13160     },
13161    
13162 /**
13163  * Returns the last item in the collection.
13164  * @return {Object} the last item in the collection..
13165  */
13166     last : function(){
13167         return this.items[this.length-1];   
13168     },
13169     
13170     _sort : function(property, dir, fn){
13171         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13172         fn = fn || function(a, b){
13173             return a-b;
13174         };
13175         var c = [], k = this.keys, items = this.items;
13176         for(var i = 0, len = items.length; i < len; i++){
13177             c[c.length] = {key: k[i], value: items[i], index: i};
13178         }
13179         c.sort(function(a, b){
13180             var v = fn(a[property], b[property]) * dsc;
13181             if(v == 0){
13182                 v = (a.index < b.index ? -1 : 1);
13183             }
13184             return v;
13185         });
13186         for(var i = 0, len = c.length; i < len; i++){
13187             items[i] = c[i].value;
13188             k[i] = c[i].key;
13189         }
13190         this.fireEvent("sort", this);
13191     },
13192     
13193     /**
13194      * Sorts this collection with the passed comparison function
13195      * @param {String} direction (optional) "ASC" or "DESC"
13196      * @param {Function} fn (optional) comparison function
13197      */
13198     sort : function(dir, fn){
13199         this._sort("value", dir, fn);
13200     },
13201     
13202     /**
13203      * Sorts this collection by keys
13204      * @param {String} direction (optional) "ASC" or "DESC"
13205      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13206      */
13207     keySort : function(dir, fn){
13208         this._sort("key", dir, fn || function(a, b){
13209             return String(a).toUpperCase()-String(b).toUpperCase();
13210         });
13211     },
13212     
13213     /**
13214      * Returns a range of items in this collection
13215      * @param {Number} startIndex (optional) defaults to 0
13216      * @param {Number} endIndex (optional) default to the last item
13217      * @return {Array} An array of items
13218      */
13219     getRange : function(start, end){
13220         var items = this.items;
13221         if(items.length < 1){
13222             return [];
13223         }
13224         start = start || 0;
13225         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13226         var r = [];
13227         if(start <= end){
13228             for(var i = start; i <= end; i++) {
13229                     r[r.length] = items[i];
13230             }
13231         }else{
13232             for(var i = start; i >= end; i--) {
13233                     r[r.length] = items[i];
13234             }
13235         }
13236         return r;
13237     },
13238         
13239     /**
13240      * Filter the <i>objects</i> in this collection by a specific property. 
13241      * Returns a new collection that has been filtered.
13242      * @param {String} property A property on your objects
13243      * @param {String/RegExp} value Either string that the property values 
13244      * should start with or a RegExp to test against the property
13245      * @return {MixedCollection} The new filtered collection
13246      */
13247     filter : function(property, value){
13248         if(!value.exec){ // not a regex
13249             value = String(value);
13250             if(value.length == 0){
13251                 return this.clone();
13252             }
13253             value = new RegExp("^" + Roo.escapeRe(value), "i");
13254         }
13255         return this.filterBy(function(o){
13256             return o && value.test(o[property]);
13257         });
13258         },
13259     
13260     /**
13261      * Filter by a function. * Returns a new collection that has been filtered.
13262      * The passed function will be called with each 
13263      * object in the collection. If the function returns true, the value is included 
13264      * otherwise it is filtered.
13265      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13266      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13267      * @return {MixedCollection} The new filtered collection
13268      */
13269     filterBy : function(fn, scope){
13270         var r = new Roo.util.MixedCollection();
13271         r.getKey = this.getKey;
13272         var k = this.keys, it = this.items;
13273         for(var i = 0, len = it.length; i < len; i++){
13274             if(fn.call(scope||this, it[i], k[i])){
13275                                 r.add(k[i], it[i]);
13276                         }
13277         }
13278         return r;
13279     },
13280     
13281     /**
13282      * Creates a duplicate of this collection
13283      * @return {MixedCollection}
13284      */
13285     clone : function(){
13286         var r = new Roo.util.MixedCollection();
13287         var k = this.keys, it = this.items;
13288         for(var i = 0, len = it.length; i < len; i++){
13289             r.add(k[i], it[i]);
13290         }
13291         r.getKey = this.getKey;
13292         return r;
13293     }
13294 });
13295 /**
13296  * Returns the item associated with the passed key or index.
13297  * @method
13298  * @param {String/Number} key The key or index of the item.
13299  * @return {Object} The item associated with the passed key.
13300  */
13301 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13302  * Based on:
13303  * Ext JS Library 1.1.1
13304  * Copyright(c) 2006-2007, Ext JS, LLC.
13305  *
13306  * Originally Released Under LGPL - original licence link has changed is not relivant.
13307  *
13308  * Fork - LGPL
13309  * <script type="text/javascript">
13310  */
13311 /**
13312  * @class Roo.util.JSON
13313  * Modified version of Douglas Crockford"s json.js that doesn"t
13314  * mess with the Object prototype 
13315  * http://www.json.org/js.html
13316  * @singleton
13317  */
13318 Roo.util.JSON = new (function(){
13319     var useHasOwn = {}.hasOwnProperty ? true : false;
13320     
13321     // crashes Safari in some instances
13322     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13323     
13324     var pad = function(n) {
13325         return n < 10 ? "0" + n : n;
13326     };
13327     
13328     var m = {
13329         "\b": '\\b',
13330         "\t": '\\t',
13331         "\n": '\\n',
13332         "\f": '\\f',
13333         "\r": '\\r',
13334         '"' : '\\"',
13335         "\\": '\\\\'
13336     };
13337
13338     var encodeString = function(s){
13339         if (/["\\\x00-\x1f]/.test(s)) {
13340             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13341                 var c = m[b];
13342                 if(c){
13343                     return c;
13344                 }
13345                 c = b.charCodeAt();
13346                 return "\\u00" +
13347                     Math.floor(c / 16).toString(16) +
13348                     (c % 16).toString(16);
13349             }) + '"';
13350         }
13351         return '"' + s + '"';
13352     };
13353     
13354     var encodeArray = function(o){
13355         var a = ["["], b, i, l = o.length, v;
13356             for (i = 0; i < l; i += 1) {
13357                 v = o[i];
13358                 switch (typeof v) {
13359                     case "undefined":
13360                     case "function":
13361                     case "unknown":
13362                         break;
13363                     default:
13364                         if (b) {
13365                             a.push(',');
13366                         }
13367                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13368                         b = true;
13369                 }
13370             }
13371             a.push("]");
13372             return a.join("");
13373     };
13374     
13375     var encodeDate = function(o){
13376         return '"' + o.getFullYear() + "-" +
13377                 pad(o.getMonth() + 1) + "-" +
13378                 pad(o.getDate()) + "T" +
13379                 pad(o.getHours()) + ":" +
13380                 pad(o.getMinutes()) + ":" +
13381                 pad(o.getSeconds()) + '"';
13382     };
13383     
13384     /**
13385      * Encodes an Object, Array or other value
13386      * @param {Mixed} o The variable to encode
13387      * @return {String} The JSON string
13388      */
13389     this.encode = function(o)
13390     {
13391         // should this be extended to fully wrap stringify..
13392         
13393         if(typeof o == "undefined" || o === null){
13394             return "null";
13395         }else if(o instanceof Array){
13396             return encodeArray(o);
13397         }else if(o instanceof Date){
13398             return encodeDate(o);
13399         }else if(typeof o == "string"){
13400             return encodeString(o);
13401         }else if(typeof o == "number"){
13402             return isFinite(o) ? String(o) : "null";
13403         }else if(typeof o == "boolean"){
13404             return String(o);
13405         }else {
13406             var a = ["{"], b, i, v;
13407             for (i in o) {
13408                 if(!useHasOwn || o.hasOwnProperty(i)) {
13409                     v = o[i];
13410                     switch (typeof v) {
13411                     case "undefined":
13412                     case "function":
13413                     case "unknown":
13414                         break;
13415                     default:
13416                         if(b){
13417                             a.push(',');
13418                         }
13419                         a.push(this.encode(i), ":",
13420                                 v === null ? "null" : this.encode(v));
13421                         b = true;
13422                     }
13423                 }
13424             }
13425             a.push("}");
13426             return a.join("");
13427         }
13428     };
13429     
13430     /**
13431      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13432      * @param {String} json The JSON string
13433      * @return {Object} The resulting object
13434      */
13435     this.decode = function(json){
13436         
13437         return  /** eval:var:json */ eval("(" + json + ')');
13438     };
13439 })();
13440 /** 
13441  * Shorthand for {@link Roo.util.JSON#encode}
13442  * @member Roo encode 
13443  * @method */
13444 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13445 /** 
13446  * Shorthand for {@link Roo.util.JSON#decode}
13447  * @member Roo decode 
13448  * @method */
13449 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13450 /*
13451  * Based on:
13452  * Ext JS Library 1.1.1
13453  * Copyright(c) 2006-2007, Ext JS, LLC.
13454  *
13455  * Originally Released Under LGPL - original licence link has changed is not relivant.
13456  *
13457  * Fork - LGPL
13458  * <script type="text/javascript">
13459  */
13460  
13461 /**
13462  * @class Roo.util.Format
13463  * Reusable data formatting functions
13464  * @singleton
13465  */
13466 Roo.util.Format = function(){
13467     var trimRe = /^\s+|\s+$/g;
13468     return {
13469         /**
13470          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13471          * @param {String} value The string to truncate
13472          * @param {Number} length The maximum length to allow before truncating
13473          * @return {String} The converted text
13474          */
13475         ellipsis : function(value, len){
13476             if(value && value.length > len){
13477                 return value.substr(0, len-3)+"...";
13478             }
13479             return value;
13480         },
13481
13482         /**
13483          * Checks a reference and converts it to empty string if it is undefined
13484          * @param {Mixed} value Reference to check
13485          * @return {Mixed} Empty string if converted, otherwise the original value
13486          */
13487         undef : function(value){
13488             return typeof value != "undefined" ? value : "";
13489         },
13490
13491         /**
13492          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13493          * @param {String} value The string to encode
13494          * @return {String} The encoded text
13495          */
13496         htmlEncode : function(value){
13497             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13498         },
13499
13500         /**
13501          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13502          * @param {String} value The string to decode
13503          * @return {String} The decoded text
13504          */
13505         htmlDecode : function(value){
13506             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13507         },
13508
13509         /**
13510          * Trims any whitespace from either side of a string
13511          * @param {String} value The text to trim
13512          * @return {String} The trimmed text
13513          */
13514         trim : function(value){
13515             return String(value).replace(trimRe, "");
13516         },
13517
13518         /**
13519          * Returns a substring from within an original string
13520          * @param {String} value The original text
13521          * @param {Number} start The start index of the substring
13522          * @param {Number} length The length of the substring
13523          * @return {String} The substring
13524          */
13525         substr : function(value, start, length){
13526             return String(value).substr(start, length);
13527         },
13528
13529         /**
13530          * Converts a string to all lower case letters
13531          * @param {String} value The text to convert
13532          * @return {String} The converted text
13533          */
13534         lowercase : function(value){
13535             return String(value).toLowerCase();
13536         },
13537
13538         /**
13539          * Converts a string to all upper case letters
13540          * @param {String} value The text to convert
13541          * @return {String} The converted text
13542          */
13543         uppercase : function(value){
13544             return String(value).toUpperCase();
13545         },
13546
13547         /**
13548          * Converts the first character only of a string to upper case
13549          * @param {String} value The text to convert
13550          * @return {String} The converted text
13551          */
13552         capitalize : function(value){
13553             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13554         },
13555
13556         // private
13557         call : function(value, fn){
13558             if(arguments.length > 2){
13559                 var args = Array.prototype.slice.call(arguments, 2);
13560                 args.unshift(value);
13561                  
13562                 return /** eval:var:value */  eval(fn).apply(window, args);
13563             }else{
13564                 /** eval:var:value */
13565                 return /** eval:var:value */ eval(fn).call(window, value);
13566             }
13567         },
13568
13569        
13570         /**
13571          * safer version of Math.toFixed..??/
13572          * @param {Number/String} value The numeric value to format
13573          * @param {Number/String} value Decimal places 
13574          * @return {String} The formatted currency string
13575          */
13576         toFixed : function(v, n)
13577         {
13578             // why not use to fixed - precision is buggered???
13579             if (!n) {
13580                 return Math.round(v-0);
13581             }
13582             var fact = Math.pow(10,n+1);
13583             v = (Math.round((v-0)*fact))/fact;
13584             var z = (''+fact).substring(2);
13585             if (v == Math.floor(v)) {
13586                 return Math.floor(v) + '.' + z;
13587             }
13588             
13589             // now just padd decimals..
13590             var ps = String(v).split('.');
13591             var fd = (ps[1] + z);
13592             var r = fd.substring(0,n); 
13593             var rm = fd.substring(n); 
13594             if (rm < 5) {
13595                 return ps[0] + '.' + r;
13596             }
13597             r*=1; // turn it into a number;
13598             r++;
13599             if (String(r).length != n) {
13600                 ps[0]*=1;
13601                 ps[0]++;
13602                 r = String(r).substring(1); // chop the end off.
13603             }
13604             
13605             return ps[0] + '.' + r;
13606              
13607         },
13608         
13609         /**
13610          * Format a number as US currency
13611          * @param {Number/String} value The numeric value to format
13612          * @return {String} The formatted currency string
13613          */
13614         usMoney : function(v){
13615             return '$' + Roo.util.Format.number(v);
13616         },
13617         
13618         /**
13619          * Format a number
13620          * eventually this should probably emulate php's number_format
13621          * @param {Number/String} value The numeric value to format
13622          * @param {Number} decimals number of decimal places
13623          * @return {String} The formatted currency string
13624          */
13625         number : function(v,decimals)
13626         {
13627             // multiply and round.
13628             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13629             var mul = Math.pow(10, decimals);
13630             var zero = String(mul).substring(1);
13631             v = (Math.round((v-0)*mul))/mul;
13632             
13633             // if it's '0' number.. then
13634             
13635             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13636             v = String(v);
13637             var ps = v.split('.');
13638             var whole = ps[0];
13639             
13640             
13641             var r = /(\d+)(\d{3})/;
13642             // add comma's
13643             while (r.test(whole)) {
13644                 whole = whole.replace(r, '$1' + ',' + '$2');
13645             }
13646             
13647             
13648             var sub = ps[1] ?
13649                     // has decimals..
13650                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13651                     // does not have decimals
13652                     (decimals ? ('.' + zero) : '');
13653             
13654             
13655             return whole + sub ;
13656         },
13657         
13658         /**
13659          * Parse a value into a formatted date using the specified format pattern.
13660          * @param {Mixed} value The value to format
13661          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13662          * @return {String} The formatted date string
13663          */
13664         date : function(v, format){
13665             if(!v){
13666                 return "";
13667             }
13668             if(!(v instanceof Date)){
13669                 v = new Date(Date.parse(v));
13670             }
13671             return v.dateFormat(format || Roo.util.Format.defaults.date);
13672         },
13673
13674         /**
13675          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13676          * @param {String} format Any valid date format string
13677          * @return {Function} The date formatting function
13678          */
13679         dateRenderer : function(format){
13680             return function(v){
13681                 return Roo.util.Format.date(v, format);  
13682             };
13683         },
13684
13685         // private
13686         stripTagsRE : /<\/?[^>]+>/gi,
13687         
13688         /**
13689          * Strips all HTML tags
13690          * @param {Mixed} value The text from which to strip tags
13691          * @return {String} The stripped text
13692          */
13693         stripTags : function(v){
13694             return !v ? v : String(v).replace(this.stripTagsRE, "");
13695         }
13696     };
13697 }();
13698 Roo.util.Format.defaults = {
13699     date : 'd/M/Y'
13700 };/*
13701  * Based on:
13702  * Ext JS Library 1.1.1
13703  * Copyright(c) 2006-2007, Ext JS, LLC.
13704  *
13705  * Originally Released Under LGPL - original licence link has changed is not relivant.
13706  *
13707  * Fork - LGPL
13708  * <script type="text/javascript">
13709  */
13710
13711
13712  
13713
13714 /**
13715  * @class Roo.MasterTemplate
13716  * @extends Roo.Template
13717  * Provides a template that can have child templates. The syntax is:
13718 <pre><code>
13719 var t = new Roo.MasterTemplate(
13720         '&lt;select name="{name}"&gt;',
13721                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13722         '&lt;/select&gt;'
13723 );
13724 t.add('options', {value: 'foo', text: 'bar'});
13725 // or you can add multiple child elements in one shot
13726 t.addAll('options', [
13727     {value: 'foo', text: 'bar'},
13728     {value: 'foo2', text: 'bar2'},
13729     {value: 'foo3', text: 'bar3'}
13730 ]);
13731 // then append, applying the master template values
13732 t.append('my-form', {name: 'my-select'});
13733 </code></pre>
13734 * A name attribute for the child template is not required if you have only one child
13735 * template or you want to refer to them by index.
13736  */
13737 Roo.MasterTemplate = function(){
13738     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13739     this.originalHtml = this.html;
13740     var st = {};
13741     var m, re = this.subTemplateRe;
13742     re.lastIndex = 0;
13743     var subIndex = 0;
13744     while(m = re.exec(this.html)){
13745         var name = m[1], content = m[2];
13746         st[subIndex] = {
13747             name: name,
13748             index: subIndex,
13749             buffer: [],
13750             tpl : new Roo.Template(content)
13751         };
13752         if(name){
13753             st[name] = st[subIndex];
13754         }
13755         st[subIndex].tpl.compile();
13756         st[subIndex].tpl.call = this.call.createDelegate(this);
13757         subIndex++;
13758     }
13759     this.subCount = subIndex;
13760     this.subs = st;
13761 };
13762 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13763     /**
13764     * The regular expression used to match sub templates
13765     * @type RegExp
13766     * @property
13767     */
13768     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13769
13770     /**
13771      * Applies the passed values to a child template.
13772      * @param {String/Number} name (optional) The name or index of the child template
13773      * @param {Array/Object} values The values to be applied to the template
13774      * @return {MasterTemplate} this
13775      */
13776      add : function(name, values){
13777         if(arguments.length == 1){
13778             values = arguments[0];
13779             name = 0;
13780         }
13781         var s = this.subs[name];
13782         s.buffer[s.buffer.length] = s.tpl.apply(values);
13783         return this;
13784     },
13785
13786     /**
13787      * Applies all the passed values to a child template.
13788      * @param {String/Number} name (optional) The name or index of the child template
13789      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13790      * @param {Boolean} reset (optional) True to reset the template first
13791      * @return {MasterTemplate} this
13792      */
13793     fill : function(name, values, reset){
13794         var a = arguments;
13795         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13796             values = a[0];
13797             name = 0;
13798             reset = a[1];
13799         }
13800         if(reset){
13801             this.reset();
13802         }
13803         for(var i = 0, len = values.length; i < len; i++){
13804             this.add(name, values[i]);
13805         }
13806         return this;
13807     },
13808
13809     /**
13810      * Resets the template for reuse
13811      * @return {MasterTemplate} this
13812      */
13813      reset : function(){
13814         var s = this.subs;
13815         for(var i = 0; i < this.subCount; i++){
13816             s[i].buffer = [];
13817         }
13818         return this;
13819     },
13820
13821     applyTemplate : function(values){
13822         var s = this.subs;
13823         var replaceIndex = -1;
13824         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13825             return s[++replaceIndex].buffer.join("");
13826         });
13827         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13828     },
13829
13830     apply : function(){
13831         return this.applyTemplate.apply(this, arguments);
13832     },
13833
13834     compile : function(){return this;}
13835 });
13836
13837 /**
13838  * Alias for fill().
13839  * @method
13840  */
13841 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13842  /**
13843  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13844  * var tpl = Roo.MasterTemplate.from('element-id');
13845  * @param {String/HTMLElement} el
13846  * @param {Object} config
13847  * @static
13848  */
13849 Roo.MasterTemplate.from = function(el, config){
13850     el = Roo.getDom(el);
13851     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13852 };/*
13853  * Based on:
13854  * Ext JS Library 1.1.1
13855  * Copyright(c) 2006-2007, Ext JS, LLC.
13856  *
13857  * Originally Released Under LGPL - original licence link has changed is not relivant.
13858  *
13859  * Fork - LGPL
13860  * <script type="text/javascript">
13861  */
13862
13863  
13864 /**
13865  * @class Roo.util.CSS
13866  * Utility class for manipulating CSS rules
13867  * @singleton
13868  */
13869 Roo.util.CSS = function(){
13870         var rules = null;
13871         var doc = document;
13872
13873     var camelRe = /(-[a-z])/gi;
13874     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13875
13876    return {
13877    /**
13878     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13879     * tag and appended to the HEAD of the document.
13880     * @param {String|Object} cssText The text containing the css rules
13881     * @param {String} id An id to add to the stylesheet for later removal
13882     * @return {StyleSheet}
13883     */
13884     createStyleSheet : function(cssText, id){
13885         var ss;
13886         var head = doc.getElementsByTagName("head")[0];
13887         var nrules = doc.createElement("style");
13888         nrules.setAttribute("type", "text/css");
13889         if(id){
13890             nrules.setAttribute("id", id);
13891         }
13892         if (typeof(cssText) != 'string') {
13893             // support object maps..
13894             // not sure if this a good idea.. 
13895             // perhaps it should be merged with the general css handling
13896             // and handle js style props.
13897             var cssTextNew = [];
13898             for(var n in cssText) {
13899                 var citems = [];
13900                 for(var k in cssText[n]) {
13901                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13902                 }
13903                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13904                 
13905             }
13906             cssText = cssTextNew.join("\n");
13907             
13908         }
13909        
13910        
13911        if(Roo.isIE){
13912            head.appendChild(nrules);
13913            ss = nrules.styleSheet;
13914            ss.cssText = cssText;
13915        }else{
13916            try{
13917                 nrules.appendChild(doc.createTextNode(cssText));
13918            }catch(e){
13919                nrules.cssText = cssText; 
13920            }
13921            head.appendChild(nrules);
13922            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13923        }
13924        this.cacheStyleSheet(ss);
13925        return ss;
13926    },
13927
13928    /**
13929     * Removes a style or link tag by id
13930     * @param {String} id The id of the tag
13931     */
13932    removeStyleSheet : function(id){
13933        var existing = doc.getElementById(id);
13934        if(existing){
13935            existing.parentNode.removeChild(existing);
13936        }
13937    },
13938
13939    /**
13940     * Dynamically swaps an existing stylesheet reference for a new one
13941     * @param {String} id The id of an existing link tag to remove
13942     * @param {String} url The href of the new stylesheet to include
13943     */
13944    swapStyleSheet : function(id, url){
13945        this.removeStyleSheet(id);
13946        var ss = doc.createElement("link");
13947        ss.setAttribute("rel", "stylesheet");
13948        ss.setAttribute("type", "text/css");
13949        ss.setAttribute("id", id);
13950        ss.setAttribute("href", url);
13951        doc.getElementsByTagName("head")[0].appendChild(ss);
13952    },
13953    
13954    /**
13955     * Refresh the rule cache if you have dynamically added stylesheets
13956     * @return {Object} An object (hash) of rules indexed by selector
13957     */
13958    refreshCache : function(){
13959        return this.getRules(true);
13960    },
13961
13962    // private
13963    cacheStyleSheet : function(stylesheet){
13964        if(!rules){
13965            rules = {};
13966        }
13967        try{// try catch for cross domain access issue
13968            var ssRules = stylesheet.cssRules || stylesheet.rules;
13969            for(var j = ssRules.length-1; j >= 0; --j){
13970                rules[ssRules[j].selectorText] = ssRules[j];
13971            }
13972        }catch(e){}
13973    },
13974    
13975    /**
13976     * Gets all css rules for the document
13977     * @param {Boolean} refreshCache true to refresh the internal cache
13978     * @return {Object} An object (hash) of rules indexed by selector
13979     */
13980    getRules : function(refreshCache){
13981                 if(rules == null || refreshCache){
13982                         rules = {};
13983                         var ds = doc.styleSheets;
13984                         for(var i =0, len = ds.length; i < len; i++){
13985                             try{
13986                         this.cacheStyleSheet(ds[i]);
13987                     }catch(e){} 
13988                 }
13989                 }
13990                 return rules;
13991         },
13992         
13993         /**
13994     * Gets an an individual CSS rule by selector(s)
13995     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
13996     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
13997     * @return {CSSRule} The CSS rule or null if one is not found
13998     */
13999    getRule : function(selector, refreshCache){
14000                 var rs = this.getRules(refreshCache);
14001                 if(!(selector instanceof Array)){
14002                     return rs[selector];
14003                 }
14004                 for(var i = 0; i < selector.length; i++){
14005                         if(rs[selector[i]]){
14006                                 return rs[selector[i]];
14007                         }
14008                 }
14009                 return null;
14010         },
14011         
14012         
14013         /**
14014     * Updates a rule property
14015     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14016     * @param {String} property The css property
14017     * @param {String} value The new value for the property
14018     * @return {Boolean} true If a rule was found and updated
14019     */
14020    updateRule : function(selector, property, value){
14021                 if(!(selector instanceof Array)){
14022                         var rule = this.getRule(selector);
14023                         if(rule){
14024                                 rule.style[property.replace(camelRe, camelFn)] = value;
14025                                 return true;
14026                         }
14027                 }else{
14028                         for(var i = 0; i < selector.length; i++){
14029                                 if(this.updateRule(selector[i], property, value)){
14030                                         return true;
14031                                 }
14032                         }
14033                 }
14034                 return false;
14035         }
14036    };   
14037 }();/*
14038  * Based on:
14039  * Ext JS Library 1.1.1
14040  * Copyright(c) 2006-2007, Ext JS, LLC.
14041  *
14042  * Originally Released Under LGPL - original licence link has changed is not relivant.
14043  *
14044  * Fork - LGPL
14045  * <script type="text/javascript">
14046  */
14047
14048  
14049
14050 /**
14051  * @class Roo.util.ClickRepeater
14052  * @extends Roo.util.Observable
14053  * 
14054  * A wrapper class which can be applied to any element. Fires a "click" event while the
14055  * mouse is pressed. The interval between firings may be specified in the config but
14056  * defaults to 10 milliseconds.
14057  * 
14058  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14059  * 
14060  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14061  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14062  * Similar to an autorepeat key delay.
14063  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14064  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14065  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14066  *           "interval" and "delay" are ignored. "immediate" is honored.
14067  * @cfg {Boolean} preventDefault True to prevent the default click event
14068  * @cfg {Boolean} stopDefault True to stop the default click event
14069  * 
14070  * @history
14071  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14072  *     2007-02-02 jvs Renamed to ClickRepeater
14073  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14074  *
14075  *  @constructor
14076  * @param {String/HTMLElement/Element} el The element to listen on
14077  * @param {Object} config
14078  **/
14079 Roo.util.ClickRepeater = function(el, config)
14080 {
14081     this.el = Roo.get(el);
14082     this.el.unselectable();
14083
14084     Roo.apply(this, config);
14085
14086     this.addEvents({
14087     /**
14088      * @event mousedown
14089      * Fires when the mouse button is depressed.
14090      * @param {Roo.util.ClickRepeater} this
14091      */
14092         "mousedown" : true,
14093     /**
14094      * @event click
14095      * Fires on a specified interval during the time the element is pressed.
14096      * @param {Roo.util.ClickRepeater} this
14097      */
14098         "click" : true,
14099     /**
14100      * @event mouseup
14101      * Fires when the mouse key is released.
14102      * @param {Roo.util.ClickRepeater} this
14103      */
14104         "mouseup" : true
14105     });
14106
14107     this.el.on("mousedown", this.handleMouseDown, this);
14108     if(this.preventDefault || this.stopDefault){
14109         this.el.on("click", function(e){
14110             if(this.preventDefault){
14111                 e.preventDefault();
14112             }
14113             if(this.stopDefault){
14114                 e.stopEvent();
14115             }
14116         }, this);
14117     }
14118
14119     // allow inline handler
14120     if(this.handler){
14121         this.on("click", this.handler,  this.scope || this);
14122     }
14123
14124     Roo.util.ClickRepeater.superclass.constructor.call(this);
14125 };
14126
14127 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14128     interval : 20,
14129     delay: 250,
14130     preventDefault : true,
14131     stopDefault : false,
14132     timer : 0,
14133
14134     // private
14135     handleMouseDown : function(){
14136         clearTimeout(this.timer);
14137         this.el.blur();
14138         if(this.pressClass){
14139             this.el.addClass(this.pressClass);
14140         }
14141         this.mousedownTime = new Date();
14142
14143         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14144         this.el.on("mouseout", this.handleMouseOut, this);
14145
14146         this.fireEvent("mousedown", this);
14147         this.fireEvent("click", this);
14148         
14149         this.timer = this.click.defer(this.delay || this.interval, this);
14150     },
14151
14152     // private
14153     click : function(){
14154         this.fireEvent("click", this);
14155         this.timer = this.click.defer(this.getInterval(), this);
14156     },
14157
14158     // private
14159     getInterval: function(){
14160         if(!this.accelerate){
14161             return this.interval;
14162         }
14163         var pressTime = this.mousedownTime.getElapsed();
14164         if(pressTime < 500){
14165             return 400;
14166         }else if(pressTime < 1700){
14167             return 320;
14168         }else if(pressTime < 2600){
14169             return 250;
14170         }else if(pressTime < 3500){
14171             return 180;
14172         }else if(pressTime < 4400){
14173             return 140;
14174         }else if(pressTime < 5300){
14175             return 80;
14176         }else if(pressTime < 6200){
14177             return 50;
14178         }else{
14179             return 10;
14180         }
14181     },
14182
14183     // private
14184     handleMouseOut : function(){
14185         clearTimeout(this.timer);
14186         if(this.pressClass){
14187             this.el.removeClass(this.pressClass);
14188         }
14189         this.el.on("mouseover", this.handleMouseReturn, this);
14190     },
14191
14192     // private
14193     handleMouseReturn : function(){
14194         this.el.un("mouseover", this.handleMouseReturn);
14195         if(this.pressClass){
14196             this.el.addClass(this.pressClass);
14197         }
14198         this.click();
14199     },
14200
14201     // private
14202     handleMouseUp : function(){
14203         clearTimeout(this.timer);
14204         this.el.un("mouseover", this.handleMouseReturn);
14205         this.el.un("mouseout", this.handleMouseOut);
14206         Roo.get(document).un("mouseup", this.handleMouseUp);
14207         this.el.removeClass(this.pressClass);
14208         this.fireEvent("mouseup", this);
14209     }
14210 });/*
14211  * Based on:
14212  * Ext JS Library 1.1.1
14213  * Copyright(c) 2006-2007, Ext JS, LLC.
14214  *
14215  * Originally Released Under LGPL - original licence link has changed is not relivant.
14216  *
14217  * Fork - LGPL
14218  * <script type="text/javascript">
14219  */
14220
14221  
14222 /**
14223  * @class Roo.KeyNav
14224  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14225  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14226  * way to implement custom navigation schemes for any UI component.</p>
14227  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14228  * pageUp, pageDown, del, home, end.  Usage:</p>
14229  <pre><code>
14230 var nav = new Roo.KeyNav("my-element", {
14231     "left" : function(e){
14232         this.moveLeft(e.ctrlKey);
14233     },
14234     "right" : function(e){
14235         this.moveRight(e.ctrlKey);
14236     },
14237     "enter" : function(e){
14238         this.save();
14239     },
14240     scope : this
14241 });
14242 </code></pre>
14243  * @constructor
14244  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14245  * @param {Object} config The config
14246  */
14247 Roo.KeyNav = function(el, config){
14248     this.el = Roo.get(el);
14249     Roo.apply(this, config);
14250     if(!this.disabled){
14251         this.disabled = true;
14252         this.enable();
14253     }
14254 };
14255
14256 Roo.KeyNav.prototype = {
14257     /**
14258      * @cfg {Boolean} disabled
14259      * True to disable this KeyNav instance (defaults to false)
14260      */
14261     disabled : false,
14262     /**
14263      * @cfg {String} defaultEventAction
14264      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14265      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14266      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14267      */
14268     defaultEventAction: "stopEvent",
14269     /**
14270      * @cfg {Boolean} forceKeyDown
14271      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14272      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14273      * handle keydown instead of keypress.
14274      */
14275     forceKeyDown : false,
14276
14277     // private
14278     prepareEvent : function(e){
14279         var k = e.getKey();
14280         var h = this.keyToHandler[k];
14281         //if(h && this[h]){
14282         //    e.stopPropagation();
14283         //}
14284         if(Roo.isSafari && h && k >= 37 && k <= 40){
14285             e.stopEvent();
14286         }
14287     },
14288
14289     // private
14290     relay : function(e){
14291         var k = e.getKey();
14292         var h = this.keyToHandler[k];
14293         if(h && this[h]){
14294             if(this.doRelay(e, this[h], h) !== true){
14295                 e[this.defaultEventAction]();
14296             }
14297         }
14298     },
14299
14300     // private
14301     doRelay : function(e, h, hname){
14302         return h.call(this.scope || this, e);
14303     },
14304
14305     // possible handlers
14306     enter : false,
14307     left : false,
14308     right : false,
14309     up : false,
14310     down : false,
14311     tab : false,
14312     esc : false,
14313     pageUp : false,
14314     pageDown : false,
14315     del : false,
14316     home : false,
14317     end : false,
14318
14319     // quick lookup hash
14320     keyToHandler : {
14321         37 : "left",
14322         39 : "right",
14323         38 : "up",
14324         40 : "down",
14325         33 : "pageUp",
14326         34 : "pageDown",
14327         46 : "del",
14328         36 : "home",
14329         35 : "end",
14330         13 : "enter",
14331         27 : "esc",
14332         9  : "tab"
14333     },
14334
14335         /**
14336          * Enable this KeyNav
14337          */
14338         enable: function(){
14339                 if(this.disabled){
14340             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14341             // the EventObject will normalize Safari automatically
14342             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14343                 this.el.on("keydown", this.relay,  this);
14344             }else{
14345                 this.el.on("keydown", this.prepareEvent,  this);
14346                 this.el.on("keypress", this.relay,  this);
14347             }
14348                     this.disabled = false;
14349                 }
14350         },
14351
14352         /**
14353          * Disable this KeyNav
14354          */
14355         disable: function(){
14356                 if(!this.disabled){
14357                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14358                 this.el.un("keydown", this.relay);
14359             }else{
14360                 this.el.un("keydown", this.prepareEvent);
14361                 this.el.un("keypress", this.relay);
14362             }
14363                     this.disabled = true;
14364                 }
14365         }
14366 };/*
14367  * Based on:
14368  * Ext JS Library 1.1.1
14369  * Copyright(c) 2006-2007, Ext JS, LLC.
14370  *
14371  * Originally Released Under LGPL - original licence link has changed is not relivant.
14372  *
14373  * Fork - LGPL
14374  * <script type="text/javascript">
14375  */
14376
14377  
14378 /**
14379  * @class Roo.KeyMap
14380  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14381  * The constructor accepts the same config object as defined by {@link #addBinding}.
14382  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14383  * combination it will call the function with this signature (if the match is a multi-key
14384  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14385  * A KeyMap can also handle a string representation of keys.<br />
14386  * Usage:
14387  <pre><code>
14388 // map one key by key code
14389 var map = new Roo.KeyMap("my-element", {
14390     key: 13, // or Roo.EventObject.ENTER
14391     fn: myHandler,
14392     scope: myObject
14393 });
14394
14395 // map multiple keys to one action by string
14396 var map = new Roo.KeyMap("my-element", {
14397     key: "a\r\n\t",
14398     fn: myHandler,
14399     scope: myObject
14400 });
14401
14402 // map multiple keys to multiple actions by strings and array of codes
14403 var map = new Roo.KeyMap("my-element", [
14404     {
14405         key: [10,13],
14406         fn: function(){ alert("Return was pressed"); }
14407     }, {
14408         key: "abc",
14409         fn: function(){ alert('a, b or c was pressed'); }
14410     }, {
14411         key: "\t",
14412         ctrl:true,
14413         shift:true,
14414         fn: function(){ alert('Control + shift + tab was pressed.'); }
14415     }
14416 ]);
14417 </code></pre>
14418  * <b>Note: A KeyMap starts enabled</b>
14419  * @constructor
14420  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14421  * @param {Object} config The config (see {@link #addBinding})
14422  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14423  */
14424 Roo.KeyMap = function(el, config, eventName){
14425     this.el  = Roo.get(el);
14426     this.eventName = eventName || "keydown";
14427     this.bindings = [];
14428     if(config){
14429         this.addBinding(config);
14430     }
14431     this.enable();
14432 };
14433
14434 Roo.KeyMap.prototype = {
14435     /**
14436      * True to stop the event from bubbling and prevent the default browser action if the
14437      * key was handled by the KeyMap (defaults to false)
14438      * @type Boolean
14439      */
14440     stopEvent : false,
14441
14442     /**
14443      * Add a new binding to this KeyMap. The following config object properties are supported:
14444      * <pre>
14445 Property    Type             Description
14446 ----------  ---------------  ----------------------------------------------------------------------
14447 key         String/Array     A single keycode or an array of keycodes to handle
14448 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14449 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14450 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14451 fn          Function         The function to call when KeyMap finds the expected key combination
14452 scope       Object           The scope of the callback function
14453 </pre>
14454      *
14455      * Usage:
14456      * <pre><code>
14457 // Create a KeyMap
14458 var map = new Roo.KeyMap(document, {
14459     key: Roo.EventObject.ENTER,
14460     fn: handleKey,
14461     scope: this
14462 });
14463
14464 //Add a new binding to the existing KeyMap later
14465 map.addBinding({
14466     key: 'abc',
14467     shift: true,
14468     fn: handleKey,
14469     scope: this
14470 });
14471 </code></pre>
14472      * @param {Object/Array} config A single KeyMap config or an array of configs
14473      */
14474         addBinding : function(config){
14475         if(config instanceof Array){
14476             for(var i = 0, len = config.length; i < len; i++){
14477                 this.addBinding(config[i]);
14478             }
14479             return;
14480         }
14481         var keyCode = config.key,
14482             shift = config.shift, 
14483             ctrl = config.ctrl, 
14484             alt = config.alt,
14485             fn = config.fn,
14486             scope = config.scope;
14487         if(typeof keyCode == "string"){
14488             var ks = [];
14489             var keyString = keyCode.toUpperCase();
14490             for(var j = 0, len = keyString.length; j < len; j++){
14491                 ks.push(keyString.charCodeAt(j));
14492             }
14493             keyCode = ks;
14494         }
14495         var keyArray = keyCode instanceof Array;
14496         var handler = function(e){
14497             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14498                 var k = e.getKey();
14499                 if(keyArray){
14500                     for(var i = 0, len = keyCode.length; i < len; i++){
14501                         if(keyCode[i] == k){
14502                           if(this.stopEvent){
14503                               e.stopEvent();
14504                           }
14505                           fn.call(scope || window, k, e);
14506                           return;
14507                         }
14508                     }
14509                 }else{
14510                     if(k == keyCode){
14511                         if(this.stopEvent){
14512                            e.stopEvent();
14513                         }
14514                         fn.call(scope || window, k, e);
14515                     }
14516                 }
14517             }
14518         };
14519         this.bindings.push(handler);  
14520         },
14521
14522     /**
14523      * Shorthand for adding a single key listener
14524      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14525      * following options:
14526      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14527      * @param {Function} fn The function to call
14528      * @param {Object} scope (optional) The scope of the function
14529      */
14530     on : function(key, fn, scope){
14531         var keyCode, shift, ctrl, alt;
14532         if(typeof key == "object" && !(key instanceof Array)){
14533             keyCode = key.key;
14534             shift = key.shift;
14535             ctrl = key.ctrl;
14536             alt = key.alt;
14537         }else{
14538             keyCode = key;
14539         }
14540         this.addBinding({
14541             key: keyCode,
14542             shift: shift,
14543             ctrl: ctrl,
14544             alt: alt,
14545             fn: fn,
14546             scope: scope
14547         })
14548     },
14549
14550     // private
14551     handleKeyDown : function(e){
14552             if(this.enabled){ //just in case
14553             var b = this.bindings;
14554             for(var i = 0, len = b.length; i < len; i++){
14555                 b[i].call(this, e);
14556             }
14557             }
14558         },
14559         
14560         /**
14561          * Returns true if this KeyMap is enabled
14562          * @return {Boolean} 
14563          */
14564         isEnabled : function(){
14565             return this.enabled;  
14566         },
14567         
14568         /**
14569          * Enables this KeyMap
14570          */
14571         enable: function(){
14572                 if(!this.enabled){
14573                     this.el.on(this.eventName, this.handleKeyDown, this);
14574                     this.enabled = true;
14575                 }
14576         },
14577
14578         /**
14579          * Disable this KeyMap
14580          */
14581         disable: function(){
14582                 if(this.enabled){
14583                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14584                     this.enabled = false;
14585                 }
14586         }
14587 };/*
14588  * Based on:
14589  * Ext JS Library 1.1.1
14590  * Copyright(c) 2006-2007, Ext JS, LLC.
14591  *
14592  * Originally Released Under LGPL - original licence link has changed is not relivant.
14593  *
14594  * Fork - LGPL
14595  * <script type="text/javascript">
14596  */
14597
14598  
14599 /**
14600  * @class Roo.util.TextMetrics
14601  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14602  * wide, in pixels, a given block of text will be.
14603  * @singleton
14604  */
14605 Roo.util.TextMetrics = function(){
14606     var shared;
14607     return {
14608         /**
14609          * Measures the size of the specified text
14610          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14611          * that can affect the size of the rendered text
14612          * @param {String} text The text to measure
14613          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14614          * in order to accurately measure the text height
14615          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14616          */
14617         measure : function(el, text, fixedWidth){
14618             if(!shared){
14619                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14620             }
14621             shared.bind(el);
14622             shared.setFixedWidth(fixedWidth || 'auto');
14623             return shared.getSize(text);
14624         },
14625
14626         /**
14627          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14628          * the overhead of multiple calls to initialize the style properties on each measurement.
14629          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14630          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14631          * in order to accurately measure the text height
14632          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14633          */
14634         createInstance : function(el, fixedWidth){
14635             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14636         }
14637     };
14638 }();
14639
14640  
14641
14642 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14643     var ml = new Roo.Element(document.createElement('div'));
14644     document.body.appendChild(ml.dom);
14645     ml.position('absolute');
14646     ml.setLeftTop(-1000, -1000);
14647     ml.hide();
14648
14649     if(fixedWidth){
14650         ml.setWidth(fixedWidth);
14651     }
14652      
14653     var instance = {
14654         /**
14655          * Returns the size of the specified text based on the internal element's style and width properties
14656          * @memberOf Roo.util.TextMetrics.Instance#
14657          * @param {String} text The text to measure
14658          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14659          */
14660         getSize : function(text){
14661             ml.update(text);
14662             var s = ml.getSize();
14663             ml.update('');
14664             return s;
14665         },
14666
14667         /**
14668          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14669          * that can affect the size of the rendered text
14670          * @memberOf Roo.util.TextMetrics.Instance#
14671          * @param {String/HTMLElement} el The element, dom node or id
14672          */
14673         bind : function(el){
14674             ml.setStyle(
14675                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14676             );
14677         },
14678
14679         /**
14680          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14681          * to set a fixed width in order to accurately measure the text height.
14682          * @memberOf Roo.util.TextMetrics.Instance#
14683          * @param {Number} width The width to set on the element
14684          */
14685         setFixedWidth : function(width){
14686             ml.setWidth(width);
14687         },
14688
14689         /**
14690          * Returns the measured width of the specified text
14691          * @memberOf Roo.util.TextMetrics.Instance#
14692          * @param {String} text The text to measure
14693          * @return {Number} width The width in pixels
14694          */
14695         getWidth : function(text){
14696             ml.dom.style.width = 'auto';
14697             return this.getSize(text).width;
14698         },
14699
14700         /**
14701          * Returns the measured height of the specified text.  For multiline text, be sure to call
14702          * {@link #setFixedWidth} if necessary.
14703          * @memberOf Roo.util.TextMetrics.Instance#
14704          * @param {String} text The text to measure
14705          * @return {Number} height The height in pixels
14706          */
14707         getHeight : function(text){
14708             return this.getSize(text).height;
14709         }
14710     };
14711
14712     instance.bind(bindTo);
14713
14714     return instance;
14715 };
14716
14717 // backwards compat
14718 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14719  * Based on:
14720  * Ext JS Library 1.1.1
14721  * Copyright(c) 2006-2007, Ext JS, LLC.
14722  *
14723  * Originally Released Under LGPL - original licence link has changed is not relivant.
14724  *
14725  * Fork - LGPL
14726  * <script type="text/javascript">
14727  */
14728
14729 /**
14730  * @class Roo.state.Provider
14731  * Abstract base class for state provider implementations. This class provides methods
14732  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14733  * Provider interface.
14734  */
14735 Roo.state.Provider = function(){
14736     /**
14737      * @event statechange
14738      * Fires when a state change occurs.
14739      * @param {Provider} this This state provider
14740      * @param {String} key The state key which was changed
14741      * @param {String} value The encoded value for the state
14742      */
14743     this.addEvents({
14744         "statechange": true
14745     });
14746     this.state = {};
14747     Roo.state.Provider.superclass.constructor.call(this);
14748 };
14749 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14750     /**
14751      * Returns the current value for a key
14752      * @param {String} name The key name
14753      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14754      * @return {Mixed} The state data
14755      */
14756     get : function(name, defaultValue){
14757         return typeof this.state[name] == "undefined" ?
14758             defaultValue : this.state[name];
14759     },
14760     
14761     /**
14762      * Clears a value from the state
14763      * @param {String} name The key name
14764      */
14765     clear : function(name){
14766         delete this.state[name];
14767         this.fireEvent("statechange", this, name, null);
14768     },
14769     
14770     /**
14771      * Sets the value for a key
14772      * @param {String} name The key name
14773      * @param {Mixed} value The value to set
14774      */
14775     set : function(name, value){
14776         this.state[name] = value;
14777         this.fireEvent("statechange", this, name, value);
14778     },
14779     
14780     /**
14781      * Decodes a string previously encoded with {@link #encodeValue}.
14782      * @param {String} value The value to decode
14783      * @return {Mixed} The decoded value
14784      */
14785     decodeValue : function(cookie){
14786         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14787         var matches = re.exec(unescape(cookie));
14788         if(!matches || !matches[1]) return; // non state cookie
14789         var type = matches[1];
14790         var v = matches[2];
14791         switch(type){
14792             case "n":
14793                 return parseFloat(v);
14794             case "d":
14795                 return new Date(Date.parse(v));
14796             case "b":
14797                 return (v == "1");
14798             case "a":
14799                 var all = [];
14800                 var values = v.split("^");
14801                 for(var i = 0, len = values.length; i < len; i++){
14802                     all.push(this.decodeValue(values[i]));
14803                 }
14804                 return all;
14805            case "o":
14806                 var all = {};
14807                 var values = v.split("^");
14808                 for(var i = 0, len = values.length; i < len; i++){
14809                     var kv = values[i].split("=");
14810                     all[kv[0]] = this.decodeValue(kv[1]);
14811                 }
14812                 return all;
14813            default:
14814                 return v;
14815         }
14816     },
14817     
14818     /**
14819      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14820      * @param {Mixed} value The value to encode
14821      * @return {String} The encoded value
14822      */
14823     encodeValue : function(v){
14824         var enc;
14825         if(typeof v == "number"){
14826             enc = "n:" + v;
14827         }else if(typeof v == "boolean"){
14828             enc = "b:" + (v ? "1" : "0");
14829         }else if(v instanceof Date){
14830             enc = "d:" + v.toGMTString();
14831         }else if(v instanceof Array){
14832             var flat = "";
14833             for(var i = 0, len = v.length; i < len; i++){
14834                 flat += this.encodeValue(v[i]);
14835                 if(i != len-1) flat += "^";
14836             }
14837             enc = "a:" + flat;
14838         }else if(typeof v == "object"){
14839             var flat = "";
14840             for(var key in v){
14841                 if(typeof v[key] != "function"){
14842                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14843                 }
14844             }
14845             enc = "o:" + flat.substring(0, flat.length-1);
14846         }else{
14847             enc = "s:" + v;
14848         }
14849         return escape(enc);        
14850     }
14851 });
14852
14853 /*
14854  * Based on:
14855  * Ext JS Library 1.1.1
14856  * Copyright(c) 2006-2007, Ext JS, LLC.
14857  *
14858  * Originally Released Under LGPL - original licence link has changed is not relivant.
14859  *
14860  * Fork - LGPL
14861  * <script type="text/javascript">
14862  */
14863 /**
14864  * @class Roo.state.Manager
14865  * This is the global state manager. By default all components that are "state aware" check this class
14866  * for state information if you don't pass them a custom state provider. In order for this class
14867  * to be useful, it must be initialized with a provider when your application initializes.
14868  <pre><code>
14869 // in your initialization function
14870 init : function(){
14871    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14872    ...
14873    // supposed you have a {@link Roo.BorderLayout}
14874    var layout = new Roo.BorderLayout(...);
14875    layout.restoreState();
14876    // or a {Roo.BasicDialog}
14877    var dialog = new Roo.BasicDialog(...);
14878    dialog.restoreState();
14879  </code></pre>
14880  * @singleton
14881  */
14882 Roo.state.Manager = function(){
14883     var provider = new Roo.state.Provider();
14884     
14885     return {
14886         /**
14887          * Configures the default state provider for your application
14888          * @param {Provider} stateProvider The state provider to set
14889          */
14890         setProvider : function(stateProvider){
14891             provider = stateProvider;
14892         },
14893         
14894         /**
14895          * Returns the current value for a key
14896          * @param {String} name The key name
14897          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14898          * @return {Mixed} The state data
14899          */
14900         get : function(key, defaultValue){
14901             return provider.get(key, defaultValue);
14902         },
14903         
14904         /**
14905          * Sets the value for a key
14906          * @param {String} name The key name
14907          * @param {Mixed} value The state data
14908          */
14909          set : function(key, value){
14910             provider.set(key, value);
14911         },
14912         
14913         /**
14914          * Clears a value from the state
14915          * @param {String} name The key name
14916          */
14917         clear : function(key){
14918             provider.clear(key);
14919         },
14920         
14921         /**
14922          * Gets the currently configured state provider
14923          * @return {Provider} The state provider
14924          */
14925         getProvider : function(){
14926             return provider;
14927         }
14928     };
14929 }();
14930 /*
14931  * Based on:
14932  * Ext JS Library 1.1.1
14933  * Copyright(c) 2006-2007, Ext JS, LLC.
14934  *
14935  * Originally Released Under LGPL - original licence link has changed is not relivant.
14936  *
14937  * Fork - LGPL
14938  * <script type="text/javascript">
14939  */
14940 /**
14941  * @class Roo.state.CookieProvider
14942  * @extends Roo.state.Provider
14943  * The default Provider implementation which saves state via cookies.
14944  * <br />Usage:
14945  <pre><code>
14946    var cp = new Roo.state.CookieProvider({
14947        path: "/cgi-bin/",
14948        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14949        domain: "roojs.com"
14950    })
14951    Roo.state.Manager.setProvider(cp);
14952  </code></pre>
14953  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14954  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14955  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14956  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14957  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14958  * domain the page is running on including the 'www' like 'www.roojs.com')
14959  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14960  * @constructor
14961  * Create a new CookieProvider
14962  * @param {Object} config The configuration object
14963  */
14964 Roo.state.CookieProvider = function(config){
14965     Roo.state.CookieProvider.superclass.constructor.call(this);
14966     this.path = "/";
14967     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14968     this.domain = null;
14969     this.secure = false;
14970     Roo.apply(this, config);
14971     this.state = this.readCookies();
14972 };
14973
14974 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14975     // private
14976     set : function(name, value){
14977         if(typeof value == "undefined" || value === null){
14978             this.clear(name);
14979             return;
14980         }
14981         this.setCookie(name, value);
14982         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14983     },
14984
14985     // private
14986     clear : function(name){
14987         this.clearCookie(name);
14988         Roo.state.CookieProvider.superclass.clear.call(this, name);
14989     },
14990
14991     // private
14992     readCookies : function(){
14993         var cookies = {};
14994         var c = document.cookie + ";";
14995         var re = /\s?(.*?)=(.*?);/g;
14996         var matches;
14997         while((matches = re.exec(c)) != null){
14998             var name = matches[1];
14999             var value = matches[2];
15000             if(name && name.substring(0,3) == "ys-"){
15001                 cookies[name.substr(3)] = this.decodeValue(value);
15002             }
15003         }
15004         return cookies;
15005     },
15006
15007     // private
15008     setCookie : function(name, value){
15009         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15010            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15011            ((this.path == null) ? "" : ("; path=" + this.path)) +
15012            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15013            ((this.secure == true) ? "; secure" : "");
15014     },
15015
15016     // private
15017     clearCookie : function(name){
15018         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15019            ((this.path == null) ? "" : ("; path=" + this.path)) +
15020            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15021            ((this.secure == true) ? "; secure" : "");
15022     }
15023 });/*
15024  * Based on:
15025  * Ext JS Library 1.1.1
15026  * Copyright(c) 2006-2007, Ext JS, LLC.
15027  *
15028  * Originally Released Under LGPL - original licence link has changed is not relivant.
15029  *
15030  * Fork - LGPL
15031  * <script type="text/javascript">
15032  */
15033  
15034
15035 /**
15036  * @class Roo.ComponentMgr
15037  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15038  * @singleton
15039  */
15040 Roo.ComponentMgr = function(){
15041     var all = new Roo.util.MixedCollection();
15042
15043     return {
15044         /**
15045          * Registers a component.
15046          * @param {Roo.Component} c The component
15047          */
15048         register : function(c){
15049             all.add(c);
15050         },
15051
15052         /**
15053          * Unregisters a component.
15054          * @param {Roo.Component} c The component
15055          */
15056         unregister : function(c){
15057             all.remove(c);
15058         },
15059
15060         /**
15061          * Returns a component by id
15062          * @param {String} id The component id
15063          */
15064         get : function(id){
15065             return all.get(id);
15066         },
15067
15068         /**
15069          * Registers a function that will be called when a specified component is added to ComponentMgr
15070          * @param {String} id The component id
15071          * @param {Funtction} fn The callback function
15072          * @param {Object} scope The scope of the callback
15073          */
15074         onAvailable : function(id, fn, scope){
15075             all.on("add", function(index, o){
15076                 if(o.id == id){
15077                     fn.call(scope || o, o);
15078                     all.un("add", fn, scope);
15079                 }
15080             });
15081         }
15082     };
15083 }();/*
15084  * Based on:
15085  * Ext JS Library 1.1.1
15086  * Copyright(c) 2006-2007, Ext JS, LLC.
15087  *
15088  * Originally Released Under LGPL - original licence link has changed is not relivant.
15089  *
15090  * Fork - LGPL
15091  * <script type="text/javascript">
15092  */
15093  
15094 /**
15095  * @class Roo.Component
15096  * @extends Roo.util.Observable
15097  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15098  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15099  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15100  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15101  * All visual components (widgets) that require rendering into a layout should subclass Component.
15102  * @constructor
15103  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15104  * 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
15105  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15106  */
15107 Roo.Component = function(config){
15108     config = config || {};
15109     if(config.tagName || config.dom || typeof config == "string"){ // element object
15110         config = {el: config, id: config.id || config};
15111     }
15112     this.initialConfig = config;
15113
15114     Roo.apply(this, config);
15115     this.addEvents({
15116         /**
15117          * @event disable
15118          * Fires after the component is disabled.
15119              * @param {Roo.Component} this
15120              */
15121         disable : true,
15122         /**
15123          * @event enable
15124          * Fires after the component is enabled.
15125              * @param {Roo.Component} this
15126              */
15127         enable : true,
15128         /**
15129          * @event beforeshow
15130          * Fires before the component is shown.  Return false to stop the show.
15131              * @param {Roo.Component} this
15132              */
15133         beforeshow : true,
15134         /**
15135          * @event show
15136          * Fires after the component is shown.
15137              * @param {Roo.Component} this
15138              */
15139         show : true,
15140         /**
15141          * @event beforehide
15142          * Fires before the component is hidden. Return false to stop the hide.
15143              * @param {Roo.Component} this
15144              */
15145         beforehide : true,
15146         /**
15147          * @event hide
15148          * Fires after the component is hidden.
15149              * @param {Roo.Component} this
15150              */
15151         hide : true,
15152         /**
15153          * @event beforerender
15154          * Fires before the component is rendered. Return false to stop the render.
15155              * @param {Roo.Component} this
15156              */
15157         beforerender : true,
15158         /**
15159          * @event render
15160          * Fires after the component is rendered.
15161              * @param {Roo.Component} this
15162              */
15163         render : true,
15164         /**
15165          * @event beforedestroy
15166          * Fires before the component is destroyed. Return false to stop the destroy.
15167              * @param {Roo.Component} this
15168              */
15169         beforedestroy : true,
15170         /**
15171          * @event destroy
15172          * Fires after the component is destroyed.
15173              * @param {Roo.Component} this
15174              */
15175         destroy : true
15176     });
15177     if(!this.id){
15178         this.id = "ext-comp-" + (++Roo.Component.AUTO_ID);
15179     }
15180     Roo.ComponentMgr.register(this);
15181     Roo.Component.superclass.constructor.call(this);
15182     this.initComponent();
15183     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15184         this.render(this.renderTo);
15185         delete this.renderTo;
15186     }
15187 };
15188
15189 /** @private */
15190 Roo.Component.AUTO_ID = 1000;
15191
15192 Roo.extend(Roo.Component, Roo.util.Observable, {
15193     /**
15194      * @scope Roo.Component.prototype
15195      * @type {Boolean}
15196      * true if this component is hidden. Read-only.
15197      */
15198     hidden : false,
15199     /**
15200      * @type {Boolean}
15201      * true if this component is disabled. Read-only.
15202      */
15203     disabled : false,
15204     /**
15205      * @type {Boolean}
15206      * true if this component has been rendered. Read-only.
15207      */
15208     rendered : false,
15209     
15210     /** @cfg {String} disableClass
15211      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15212      */
15213     disabledClass : "x-item-disabled",
15214         /** @cfg {Boolean} allowDomMove
15215          * Whether the component can move the Dom node when rendering (defaults to true).
15216          */
15217     allowDomMove : true,
15218     /** @cfg {String} hideMode (display|visibility)
15219      * How this component should hidden. Supported values are
15220      * "visibility" (css visibility), "offsets" (negative offset position) and
15221      * "display" (css display) - defaults to "display".
15222      */
15223     hideMode: 'display',
15224
15225     /** @private */
15226     ctype : "Roo.Component",
15227
15228     /**
15229      * @cfg {String} actionMode 
15230      * which property holds the element that used for  hide() / show() / disable() / enable()
15231      * default is 'el' 
15232      */
15233     actionMode : "el",
15234
15235     /** @private */
15236     getActionEl : function(){
15237         return this[this.actionMode];
15238     },
15239
15240     initComponent : Roo.emptyFn,
15241     /**
15242      * If this is a lazy rendering component, render it to its container element.
15243      * @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.
15244      */
15245     render : function(container, position){
15246         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15247             if(!container && this.el){
15248                 this.el = Roo.get(this.el);
15249                 container = this.el.dom.parentNode;
15250                 this.allowDomMove = false;
15251             }
15252             this.container = Roo.get(container);
15253             this.rendered = true;
15254             if(position !== undefined){
15255                 if(typeof position == 'number'){
15256                     position = this.container.dom.childNodes[position];
15257                 }else{
15258                     position = Roo.getDom(position);
15259                 }
15260             }
15261             this.onRender(this.container, position || null);
15262             if(this.cls){
15263                 this.el.addClass(this.cls);
15264                 delete this.cls;
15265             }
15266             if(this.style){
15267                 this.el.applyStyles(this.style);
15268                 delete this.style;
15269             }
15270             this.fireEvent("render", this);
15271             this.afterRender(this.container);
15272             if(this.hidden){
15273                 this.hide();
15274             }
15275             if(this.disabled){
15276                 this.disable();
15277             }
15278         }
15279         return this;
15280     },
15281
15282     /** @private */
15283     // default function is not really useful
15284     onRender : function(ct, position){
15285         if(this.el){
15286             this.el = Roo.get(this.el);
15287             if(this.allowDomMove !== false){
15288                 ct.dom.insertBefore(this.el.dom, position);
15289             }
15290         }
15291     },
15292
15293     /** @private */
15294     getAutoCreate : function(){
15295         var cfg = typeof this.autoCreate == "object" ?
15296                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15297         if(this.id && !cfg.id){
15298             cfg.id = this.id;
15299         }
15300         return cfg;
15301     },
15302
15303     /** @private */
15304     afterRender : Roo.emptyFn,
15305
15306     /**
15307      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15308      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15309      */
15310     destroy : function(){
15311         if(this.fireEvent("beforedestroy", this) !== false){
15312             this.purgeListeners();
15313             this.beforeDestroy();
15314             if(this.rendered){
15315                 this.el.removeAllListeners();
15316                 this.el.remove();
15317                 if(this.actionMode == "container"){
15318                     this.container.remove();
15319                 }
15320             }
15321             this.onDestroy();
15322             Roo.ComponentMgr.unregister(this);
15323             this.fireEvent("destroy", this);
15324         }
15325     },
15326
15327         /** @private */
15328     beforeDestroy : function(){
15329
15330     },
15331
15332         /** @private */
15333         onDestroy : function(){
15334
15335     },
15336
15337     /**
15338      * Returns the underlying {@link Roo.Element}.
15339      * @return {Roo.Element} The element
15340      */
15341     getEl : function(){
15342         return this.el;
15343     },
15344
15345     /**
15346      * Returns the id of this component.
15347      * @return {String}
15348      */
15349     getId : function(){
15350         return this.id;
15351     },
15352
15353     /**
15354      * Try to focus this component.
15355      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15356      * @return {Roo.Component} this
15357      */
15358     focus : function(selectText){
15359         if(this.rendered){
15360             this.el.focus();
15361             if(selectText === true){
15362                 this.el.dom.select();
15363             }
15364         }
15365         return this;
15366     },
15367
15368     /** @private */
15369     blur : function(){
15370         if(this.rendered){
15371             this.el.blur();
15372         }
15373         return this;
15374     },
15375
15376     /**
15377      * Disable this component.
15378      * @return {Roo.Component} this
15379      */
15380     disable : function(){
15381         if(this.rendered){
15382             this.onDisable();
15383         }
15384         this.disabled = true;
15385         this.fireEvent("disable", this);
15386         return this;
15387     },
15388
15389         // private
15390     onDisable : function(){
15391         this.getActionEl().addClass(this.disabledClass);
15392         this.el.dom.disabled = true;
15393     },
15394
15395     /**
15396      * Enable this component.
15397      * @return {Roo.Component} this
15398      */
15399     enable : function(){
15400         if(this.rendered){
15401             this.onEnable();
15402         }
15403         this.disabled = false;
15404         this.fireEvent("enable", this);
15405         return this;
15406     },
15407
15408         // private
15409     onEnable : function(){
15410         this.getActionEl().removeClass(this.disabledClass);
15411         this.el.dom.disabled = false;
15412     },
15413
15414     /**
15415      * Convenience function for setting disabled/enabled by boolean.
15416      * @param {Boolean} disabled
15417      */
15418     setDisabled : function(disabled){
15419         this[disabled ? "disable" : "enable"]();
15420     },
15421
15422     /**
15423      * Show this component.
15424      * @return {Roo.Component} this
15425      */
15426     show: function(){
15427         if(this.fireEvent("beforeshow", this) !== false){
15428             this.hidden = false;
15429             if(this.rendered){
15430                 this.onShow();
15431             }
15432             this.fireEvent("show", this);
15433         }
15434         return this;
15435     },
15436
15437     // private
15438     onShow : function(){
15439         var ae = this.getActionEl();
15440         if(this.hideMode == 'visibility'){
15441             ae.dom.style.visibility = "visible";
15442         }else if(this.hideMode == 'offsets'){
15443             ae.removeClass('x-hidden');
15444         }else{
15445             ae.dom.style.display = "";
15446         }
15447     },
15448
15449     /**
15450      * Hide this component.
15451      * @return {Roo.Component} this
15452      */
15453     hide: function(){
15454         if(this.fireEvent("beforehide", this) !== false){
15455             this.hidden = true;
15456             if(this.rendered){
15457                 this.onHide();
15458             }
15459             this.fireEvent("hide", this);
15460         }
15461         return this;
15462     },
15463
15464     // private
15465     onHide : function(){
15466         var ae = this.getActionEl();
15467         if(this.hideMode == 'visibility'){
15468             ae.dom.style.visibility = "hidden";
15469         }else if(this.hideMode == 'offsets'){
15470             ae.addClass('x-hidden');
15471         }else{
15472             ae.dom.style.display = "none";
15473         }
15474     },
15475
15476     /**
15477      * Convenience function to hide or show this component by boolean.
15478      * @param {Boolean} visible True to show, false to hide
15479      * @return {Roo.Component} this
15480      */
15481     setVisible: function(visible){
15482         if(visible) {
15483             this.show();
15484         }else{
15485             this.hide();
15486         }
15487         return this;
15488     },
15489
15490     /**
15491      * Returns true if this component is visible.
15492      */
15493     isVisible : function(){
15494         return this.getActionEl().isVisible();
15495     },
15496
15497     cloneConfig : function(overrides){
15498         overrides = overrides || {};
15499         var id = overrides.id || Roo.id();
15500         var cfg = Roo.applyIf(overrides, this.initialConfig);
15501         cfg.id = id; // prevent dup id
15502         return new this.constructor(cfg);
15503     }
15504 });/*
15505  * Based on:
15506  * Ext JS Library 1.1.1
15507  * Copyright(c) 2006-2007, Ext JS, LLC.
15508  *
15509  * Originally Released Under LGPL - original licence link has changed is not relivant.
15510  *
15511  * Fork - LGPL
15512  * <script type="text/javascript">
15513  */
15514
15515 /**
15516  * @class Roo.BoxComponent
15517  * @extends Roo.Component
15518  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15519  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15520  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15521  * layout containers.
15522  * @constructor
15523  * @param {Roo.Element/String/Object} config The configuration options.
15524  */
15525 Roo.BoxComponent = function(config){
15526     Roo.Component.call(this, config);
15527     this.addEvents({
15528         /**
15529          * @event resize
15530          * Fires after the component is resized.
15531              * @param {Roo.Component} this
15532              * @param {Number} adjWidth The box-adjusted width that was set
15533              * @param {Number} adjHeight The box-adjusted height that was set
15534              * @param {Number} rawWidth The width that was originally specified
15535              * @param {Number} rawHeight The height that was originally specified
15536              */
15537         resize : true,
15538         /**
15539          * @event move
15540          * Fires after the component is moved.
15541              * @param {Roo.Component} this
15542              * @param {Number} x The new x position
15543              * @param {Number} y The new y position
15544              */
15545         move : true
15546     });
15547 };
15548
15549 Roo.extend(Roo.BoxComponent, Roo.Component, {
15550     // private, set in afterRender to signify that the component has been rendered
15551     boxReady : false,
15552     // private, used to defer height settings to subclasses
15553     deferHeight: false,
15554     /** @cfg {Number} width
15555      * width (optional) size of component
15556      */
15557      /** @cfg {Number} height
15558      * height (optional) size of component
15559      */
15560      
15561     /**
15562      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15563      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15564      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15565      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15566      * @return {Roo.BoxComponent} this
15567      */
15568     setSize : function(w, h){
15569         // support for standard size objects
15570         if(typeof w == 'object'){
15571             h = w.height;
15572             w = w.width;
15573         }
15574         // not rendered
15575         if(!this.boxReady){
15576             this.width = w;
15577             this.height = h;
15578             return this;
15579         }
15580
15581         // prevent recalcs when not needed
15582         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15583             return this;
15584         }
15585         this.lastSize = {width: w, height: h};
15586
15587         var adj = this.adjustSize(w, h);
15588         var aw = adj.width, ah = adj.height;
15589         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15590             var rz = this.getResizeEl();
15591             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15592                 rz.setSize(aw, ah);
15593             }else if(!this.deferHeight && ah !== undefined){
15594                 rz.setHeight(ah);
15595             }else if(aw !== undefined){
15596                 rz.setWidth(aw);
15597             }
15598             this.onResize(aw, ah, w, h);
15599             this.fireEvent('resize', this, aw, ah, w, h);
15600         }
15601         return this;
15602     },
15603
15604     /**
15605      * Gets the current size of the component's underlying element.
15606      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15607      */
15608     getSize : function(){
15609         return this.el.getSize();
15610     },
15611
15612     /**
15613      * Gets the current XY position of the component's underlying element.
15614      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15615      * @return {Array} The XY position of the element (e.g., [100, 200])
15616      */
15617     getPosition : function(local){
15618         if(local === true){
15619             return [this.el.getLeft(true), this.el.getTop(true)];
15620         }
15621         return this.xy || this.el.getXY();
15622     },
15623
15624     /**
15625      * Gets the current box measurements of the component's underlying element.
15626      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15627      * @returns {Object} box An object in the format {x, y, width, height}
15628      */
15629     getBox : function(local){
15630         var s = this.el.getSize();
15631         if(local){
15632             s.x = this.el.getLeft(true);
15633             s.y = this.el.getTop(true);
15634         }else{
15635             var xy = this.xy || this.el.getXY();
15636             s.x = xy[0];
15637             s.y = xy[1];
15638         }
15639         return s;
15640     },
15641
15642     /**
15643      * Sets the current box measurements of the component's underlying element.
15644      * @param {Object} box An object in the format {x, y, width, height}
15645      * @returns {Roo.BoxComponent} this
15646      */
15647     updateBox : function(box){
15648         this.setSize(box.width, box.height);
15649         this.setPagePosition(box.x, box.y);
15650         return this;
15651     },
15652
15653     // protected
15654     getResizeEl : function(){
15655         return this.resizeEl || this.el;
15656     },
15657
15658     // protected
15659     getPositionEl : function(){
15660         return this.positionEl || this.el;
15661     },
15662
15663     /**
15664      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15665      * This method fires the move event.
15666      * @param {Number} left The new left
15667      * @param {Number} top The new top
15668      * @returns {Roo.BoxComponent} this
15669      */
15670     setPosition : function(x, y){
15671         this.x = x;
15672         this.y = y;
15673         if(!this.boxReady){
15674             return this;
15675         }
15676         var adj = this.adjustPosition(x, y);
15677         var ax = adj.x, ay = adj.y;
15678
15679         var el = this.getPositionEl();
15680         if(ax !== undefined || ay !== undefined){
15681             if(ax !== undefined && ay !== undefined){
15682                 el.setLeftTop(ax, ay);
15683             }else if(ax !== undefined){
15684                 el.setLeft(ax);
15685             }else if(ay !== undefined){
15686                 el.setTop(ay);
15687             }
15688             this.onPosition(ax, ay);
15689             this.fireEvent('move', this, ax, ay);
15690         }
15691         return this;
15692     },
15693
15694     /**
15695      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15696      * This method fires the move event.
15697      * @param {Number} x The new x position
15698      * @param {Number} y The new y position
15699      * @returns {Roo.BoxComponent} this
15700      */
15701     setPagePosition : function(x, y){
15702         this.pageX = x;
15703         this.pageY = y;
15704         if(!this.boxReady){
15705             return;
15706         }
15707         if(x === undefined || y === undefined){ // cannot translate undefined points
15708             return;
15709         }
15710         var p = this.el.translatePoints(x, y);
15711         this.setPosition(p.left, p.top);
15712         return this;
15713     },
15714
15715     // private
15716     onRender : function(ct, position){
15717         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15718         if(this.resizeEl){
15719             this.resizeEl = Roo.get(this.resizeEl);
15720         }
15721         if(this.positionEl){
15722             this.positionEl = Roo.get(this.positionEl);
15723         }
15724     },
15725
15726     // private
15727     afterRender : function(){
15728         Roo.BoxComponent.superclass.afterRender.call(this);
15729         this.boxReady = true;
15730         this.setSize(this.width, this.height);
15731         if(this.x || this.y){
15732             this.setPosition(this.x, this.y);
15733         }
15734         if(this.pageX || this.pageY){
15735             this.setPagePosition(this.pageX, this.pageY);
15736         }
15737     },
15738
15739     /**
15740      * Force the component's size to recalculate based on the underlying element's current height and width.
15741      * @returns {Roo.BoxComponent} this
15742      */
15743     syncSize : function(){
15744         delete this.lastSize;
15745         this.setSize(this.el.getWidth(), this.el.getHeight());
15746         return this;
15747     },
15748
15749     /**
15750      * Called after the component is resized, this method is empty by default but can be implemented by any
15751      * subclass that needs to perform custom logic after a resize occurs.
15752      * @param {Number} adjWidth The box-adjusted width that was set
15753      * @param {Number} adjHeight The box-adjusted height that was set
15754      * @param {Number} rawWidth The width that was originally specified
15755      * @param {Number} rawHeight The height that was originally specified
15756      */
15757     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15758
15759     },
15760
15761     /**
15762      * Called after the component is moved, this method is empty by default but can be implemented by any
15763      * subclass that needs to perform custom logic after a move occurs.
15764      * @param {Number} x The new x position
15765      * @param {Number} y The new y position
15766      */
15767     onPosition : function(x, y){
15768
15769     },
15770
15771     // private
15772     adjustSize : function(w, h){
15773         if(this.autoWidth){
15774             w = 'auto';
15775         }
15776         if(this.autoHeight){
15777             h = 'auto';
15778         }
15779         return {width : w, height: h};
15780     },
15781
15782     // private
15783     adjustPosition : function(x, y){
15784         return {x : x, y: y};
15785     }
15786 });/*
15787  * Original code for Roojs - LGPL
15788  * <script type="text/javascript">
15789  */
15790  
15791 /**
15792  * @class Roo.XComponent
15793  * A delayed Element creator...
15794  * Or a way to group chunks of interface together.
15795  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15796  *  used in conjunction with XComponent.build() it will create an instance of each element,
15797  *  then call addxtype() to build the User interface.
15798  * 
15799  * Mypart.xyx = new Roo.XComponent({
15800
15801     parent : 'Mypart.xyz', // empty == document.element.!!
15802     order : '001',
15803     name : 'xxxx'
15804     region : 'xxxx'
15805     disabled : function() {} 
15806      
15807     tree : function() { // return an tree of xtype declared components
15808         var MODULE = this;
15809         return 
15810         {
15811             xtype : 'NestedLayoutPanel',
15812             // technicall
15813         }
15814      ]
15815  *})
15816  *
15817  *
15818  * It can be used to build a big heiracy, with parent etc.
15819  * or you can just use this to render a single compoent to a dom element
15820  * MYPART.render(Roo.Element | String(id) | dom_element )
15821  *
15822  *
15823  * Usage patterns.
15824  *
15825  * Classic Roo
15826  *
15827  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15828  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15829  *
15830  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15831  *
15832  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15833  * - if mulitple topModules exist, the last one is defined as the top module.
15834  *
15835  * Embeded Roo
15836  * 
15837  * When the top level or multiple modules are to embedded into a existing HTML page,
15838  * the parent element can container '#id' of the element where the module will be drawn.
15839  *
15840  * Bootstrap Roo
15841  *
15842  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15843  * it relies more on a include mechanism, where sub modules are included into an outer page.
15844  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15845  * 
15846  * Bootstrap Roo Included elements
15847  *
15848  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15849  * hence confusing the component builder as it thinks there are multiple top level elements. 
15850  *
15851  * 
15852  * 
15853  * @extends Roo.util.Observable
15854  * @constructor
15855  * @param cfg {Object} configuration of component
15856  * 
15857  */
15858 Roo.XComponent = function(cfg) {
15859     Roo.apply(this, cfg);
15860     this.addEvents({ 
15861         /**
15862              * @event built
15863              * Fires when this the componnt is built
15864              * @param {Roo.XComponent} c the component
15865              */
15866         'built' : true
15867         
15868     });
15869     this.region = this.region || 'center'; // default..
15870     Roo.XComponent.register(this);
15871     this.modules = false;
15872     this.el = false; // where the layout goes..
15873     
15874     
15875 }
15876 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15877     /**
15878      * @property el
15879      * The created element (with Roo.factory())
15880      * @type {Roo.Layout}
15881      */
15882     el  : false,
15883     
15884     /**
15885      * @property el
15886      * for BC  - use el in new code
15887      * @type {Roo.Layout}
15888      */
15889     panel : false,
15890     
15891     /**
15892      * @property layout
15893      * for BC  - use el in new code
15894      * @type {Roo.Layout}
15895      */
15896     layout : false,
15897     
15898      /**
15899      * @cfg {Function|boolean} disabled
15900      * If this module is disabled by some rule, return true from the funtion
15901      */
15902     disabled : false,
15903     
15904     /**
15905      * @cfg {String} parent 
15906      * Name of parent element which it get xtype added to..
15907      */
15908     parent: false,
15909     
15910     /**
15911      * @cfg {String} order
15912      * Used to set the order in which elements are created (usefull for multiple tabs)
15913      */
15914     
15915     order : false,
15916     /**
15917      * @cfg {String} name
15918      * String to display while loading.
15919      */
15920     name : false,
15921     /**
15922      * @cfg {String} region
15923      * Region to render component to (defaults to center)
15924      */
15925     region : 'center',
15926     
15927     /**
15928      * @cfg {Array} items
15929      * A single item array - the first element is the root of the tree..
15930      * It's done this way to stay compatible with the Xtype system...
15931      */
15932     items : false,
15933     
15934     /**
15935      * @property _tree
15936      * The method that retuns the tree of parts that make up this compoennt 
15937      * @type {function}
15938      */
15939     _tree  : false,
15940     
15941      /**
15942      * render
15943      * render element to dom or tree
15944      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15945      */
15946     
15947     render : function(el)
15948     {
15949         
15950         el = el || false;
15951         var hp = this.parent ? 1 : 0;
15952         Roo.debug &&  Roo.log(this);
15953         
15954         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15955             // if parent is a '#.....' string, then let's use that..
15956             var ename = this.parent.substr(1);
15957             this.parent = false;
15958             Roo.debug && Roo.log(ename);
15959             switch (ename) {
15960                 case 'bootstrap-body' :
15961                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15962                         this.parent = { el :  new  Roo.bootstrap.Body() };
15963                         Roo.debug && Roo.log("setting el to doc body");
15964                          
15965                     } else {
15966                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15967                     }
15968                     break;
15969                 case 'bootstrap':
15970                     this.parent = { el : true};
15971                     // fall through
15972                 default:
15973                     el = Roo.get(ename);
15974                     break;
15975             }
15976                 
15977             
15978             if (!el && !this.parent) {
15979                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15980                 return;
15981             }
15982         }
15983         Roo.debug && Roo.log("EL:");
15984         Roo.debug && Roo.log(el);
15985         Roo.debug && Roo.log("this.parent.el:");
15986         Roo.debug && Roo.log(this.parent.el);
15987         
15988         var tree = this._tree ? this._tree() : this.tree();
15989
15990         // altertive root elements ??? - we need a better way to indicate these.
15991         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
15992                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
15993         
15994         if (!this.parent && is_alt) {
15995             //el = Roo.get(document.body);
15996             this.parent = { el : true };
15997         }
15998             
15999             
16000         
16001         if (!this.parent) {
16002             
16003             Roo.debug && Roo.log("no parent - creating one");
16004             
16005             el = el ? Roo.get(el) : false;      
16006             
16007             // it's a top level one..
16008             this.parent =  {
16009                 el : new Roo.BorderLayout(el || document.body, {
16010                 
16011                      center: {
16012                          titlebar: false,
16013                          autoScroll:false,
16014                          closeOnTab: true,
16015                          tabPosition: 'top',
16016                           //resizeTabs: true,
16017                          alwaysShowTabs: el && hp? false :  true,
16018                          hideTabs: el || !hp ? true :  false,
16019                          minTabWidth: 140
16020                      }
16021                  })
16022             }
16023         }
16024         
16025         if (!this.parent.el) {
16026                 // probably an old style ctor, which has been disabled.
16027                 return;
16028
16029         }
16030                 // The 'tree' method is  '_tree now' 
16031             
16032         tree.region = tree.region || this.region;
16033         
16034         if (this.parent.el === true) {
16035             // bootstrap... - body..
16036             this.parent.el = Roo.factory(tree);
16037         }
16038         
16039         this.el = this.parent.el.addxtype(tree);
16040         this.fireEvent('built', this);
16041         
16042         this.panel = this.el;
16043         this.layout = this.panel.layout;
16044         this.parentLayout = this.parent.layout  || false;  
16045          
16046     }
16047     
16048 });
16049
16050 Roo.apply(Roo.XComponent, {
16051     /**
16052      * @property  hideProgress
16053      * true to disable the building progress bar.. usefull on single page renders.
16054      * @type Boolean
16055      */
16056     hideProgress : false,
16057     /**
16058      * @property  buildCompleted
16059      * True when the builder has completed building the interface.
16060      * @type Boolean
16061      */
16062     buildCompleted : false,
16063      
16064     /**
16065      * @property  topModule
16066      * the upper most module - uses document.element as it's constructor.
16067      * @type Object
16068      */
16069      
16070     topModule  : false,
16071       
16072     /**
16073      * @property  modules
16074      * array of modules to be created by registration system.
16075      * @type {Array} of Roo.XComponent
16076      */
16077     
16078     modules : [],
16079     /**
16080      * @property  elmodules
16081      * array of modules to be created by which use #ID 
16082      * @type {Array} of Roo.XComponent
16083      */
16084      
16085     elmodules : [],
16086
16087      /**
16088      * @property  build_from_html
16089      * Build elements from html - used by bootstrap HTML stuff 
16090      *    - this is cleared after build is completed
16091      * @type {boolean} true  (default false)
16092      */
16093      
16094     build_from_html : false,
16095
16096     /**
16097      * Register components to be built later.
16098      *
16099      * This solves the following issues
16100      * - Building is not done on page load, but after an authentication process has occured.
16101      * - Interface elements are registered on page load
16102      * - Parent Interface elements may not be loaded before child, so this handles that..
16103      * 
16104      *
16105      * example:
16106      * 
16107      * MyApp.register({
16108           order : '000001',
16109           module : 'Pman.Tab.projectMgr',
16110           region : 'center',
16111           parent : 'Pman.layout',
16112           disabled : false,  // or use a function..
16113         })
16114      
16115      * * @param {Object} details about module
16116      */
16117     register : function(obj) {
16118                 
16119         Roo.XComponent.event.fireEvent('register', obj);
16120         switch(typeof(obj.disabled) ) {
16121                 
16122             case 'undefined':
16123                 break;
16124             
16125             case 'function':
16126                 if ( obj.disabled() ) {
16127                         return;
16128                 }
16129                 break;
16130             
16131             default:
16132                 if (obj.disabled) {
16133                         return;
16134                 }
16135                 break;
16136         }
16137                 
16138         this.modules.push(obj);
16139          
16140     },
16141     /**
16142      * convert a string to an object..
16143      * eg. 'AAA.BBB' -> finds AAA.BBB
16144
16145      */
16146     
16147     toObject : function(str)
16148     {
16149         if (!str || typeof(str) == 'object') {
16150             return str;
16151         }
16152         if (str.substring(0,1) == '#') {
16153             return str;
16154         }
16155
16156         var ar = str.split('.');
16157         var rt, o;
16158         rt = ar.shift();
16159             /** eval:var:o */
16160         try {
16161             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16162         } catch (e) {
16163             throw "Module not found : " + str;
16164         }
16165         
16166         if (o === false) {
16167             throw "Module not found : " + str;
16168         }
16169         Roo.each(ar, function(e) {
16170             if (typeof(o[e]) == 'undefined') {
16171                 throw "Module not found : " + str;
16172             }
16173             o = o[e];
16174         });
16175         
16176         return o;
16177         
16178     },
16179     
16180     
16181     /**
16182      * move modules into their correct place in the tree..
16183      * 
16184      */
16185     preBuild : function ()
16186     {
16187         var _t = this;
16188         Roo.each(this.modules , function (obj)
16189         {
16190             Roo.XComponent.event.fireEvent('beforebuild', obj);
16191             
16192             var opar = obj.parent;
16193             try { 
16194                 obj.parent = this.toObject(opar);
16195             } catch(e) {
16196                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16197                 return;
16198             }
16199             
16200             if (!obj.parent) {
16201                 Roo.debug && Roo.log("GOT top level module");
16202                 Roo.debug && Roo.log(obj);
16203                 obj.modules = new Roo.util.MixedCollection(false, 
16204                     function(o) { return o.order + '' }
16205                 );
16206                 this.topModule = obj;
16207                 return;
16208             }
16209                         // parent is a string (usually a dom element name..)
16210             if (typeof(obj.parent) == 'string') {
16211                 this.elmodules.push(obj);
16212                 return;
16213             }
16214             if (obj.parent.constructor != Roo.XComponent) {
16215                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16216             }
16217             if (!obj.parent.modules) {
16218                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16219                     function(o) { return o.order + '' }
16220                 );
16221             }
16222             if (obj.parent.disabled) {
16223                 obj.disabled = true;
16224             }
16225             obj.parent.modules.add(obj);
16226         }, this);
16227     },
16228     
16229      /**
16230      * make a list of modules to build.
16231      * @return {Array} list of modules. 
16232      */ 
16233     
16234     buildOrder : function()
16235     {
16236         var _this = this;
16237         var cmp = function(a,b) {   
16238             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16239         };
16240         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16241             throw "No top level modules to build";
16242         }
16243         
16244         // make a flat list in order of modules to build.
16245         var mods = this.topModule ? [ this.topModule ] : [];
16246                 
16247         
16248         // elmodules (is a list of DOM based modules )
16249         Roo.each(this.elmodules, function(e) {
16250             mods.push(e);
16251             if (!this.topModule &&
16252                 typeof(e.parent) == 'string' &&
16253                 e.parent.substring(0,1) == '#' &&
16254                 Roo.get(e.parent.substr(1))
16255                ) {
16256                 
16257                 _this.topModule = e;
16258             }
16259             
16260         });
16261
16262         
16263         // add modules to their parents..
16264         var addMod = function(m) {
16265             Roo.debug && Roo.log("build Order: add: " + m.name);
16266                 
16267             mods.push(m);
16268             if (m.modules && !m.disabled) {
16269                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16270                 m.modules.keySort('ASC',  cmp );
16271                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16272     
16273                 m.modules.each(addMod);
16274             } else {
16275                 Roo.debug && Roo.log("build Order: no child modules");
16276             }
16277             // not sure if this is used any more..
16278             if (m.finalize) {
16279                 m.finalize.name = m.name + " (clean up) ";
16280                 mods.push(m.finalize);
16281             }
16282             
16283         }
16284         if (this.topModule && this.topModule.modules) { 
16285             this.topModule.modules.keySort('ASC',  cmp );
16286             this.topModule.modules.each(addMod);
16287         } 
16288         return mods;
16289     },
16290     
16291      /**
16292      * Build the registered modules.
16293      * @param {Object} parent element.
16294      * @param {Function} optional method to call after module has been added.
16295      * 
16296      */ 
16297    
16298     build : function(opts) 
16299     {
16300         
16301         if (typeof(opts) != 'undefined') {
16302             Roo.apply(this,opts);
16303         }
16304         
16305         this.preBuild();
16306         var mods = this.buildOrder();
16307       
16308         //this.allmods = mods;
16309         //Roo.debug && Roo.log(mods);
16310         //return;
16311         if (!mods.length) { // should not happen
16312             throw "NO modules!!!";
16313         }
16314         
16315         
16316         var msg = "Building Interface...";
16317         // flash it up as modal - so we store the mask!?
16318         if (!this.hideProgress && Roo.MessageBox) {
16319             Roo.MessageBox.show({ title: 'loading' });
16320             Roo.MessageBox.show({
16321                title: "Please wait...",
16322                msg: msg,
16323                width:450,
16324                progress:true,
16325                closable:false,
16326                modal: false
16327               
16328             });
16329         }
16330         var total = mods.length;
16331         
16332         var _this = this;
16333         var progressRun = function() {
16334             if (!mods.length) {
16335                 Roo.debug && Roo.log('hide?');
16336                 if (!this.hideProgress && Roo.MessageBox) {
16337                     Roo.MessageBox.hide();
16338                 }
16339                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16340                 
16341                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16342                 
16343                 // THE END...
16344                 return false;   
16345             }
16346             
16347             var m = mods.shift();
16348             
16349             
16350             Roo.debug && Roo.log(m);
16351             // not sure if this is supported any more.. - modules that are are just function
16352             if (typeof(m) == 'function') { 
16353                 m.call(this);
16354                 return progressRun.defer(10, _this);
16355             } 
16356             
16357             
16358             msg = "Building Interface " + (total  - mods.length) + 
16359                     " of " + total + 
16360                     (m.name ? (' - ' + m.name) : '');
16361                         Roo.debug && Roo.log(msg);
16362             if (!this.hideProgress &&  Roo.MessageBox) { 
16363                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16364             }
16365             
16366          
16367             // is the module disabled?
16368             var disabled = (typeof(m.disabled) == 'function') ?
16369                 m.disabled.call(m.module.disabled) : m.disabled;    
16370             
16371             
16372             if (disabled) {
16373                 return progressRun(); // we do not update the display!
16374             }
16375             
16376             // now build 
16377             
16378                         
16379                         
16380             m.render();
16381             // it's 10 on top level, and 1 on others??? why...
16382             return progressRun.defer(10, _this);
16383              
16384         }
16385         progressRun.defer(1, _this);
16386      
16387         
16388         
16389     },
16390         
16391         
16392         /**
16393          * Event Object.
16394          *
16395          *
16396          */
16397         event: false, 
16398     /**
16399          * wrapper for event.on - aliased later..  
16400          * Typically use to register a event handler for register:
16401          *
16402          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16403          *
16404          */
16405     on : false
16406    
16407     
16408     
16409 });
16410
16411 Roo.XComponent.event = new Roo.util.Observable({
16412                 events : { 
16413                         /**
16414                          * @event register
16415                          * Fires when an Component is registered,
16416                          * set the disable property on the Component to stop registration.
16417                          * @param {Roo.XComponent} c the component being registerd.
16418                          * 
16419                          */
16420                         'register' : true,
16421             /**
16422                          * @event beforebuild
16423                          * Fires before each Component is built
16424                          * can be used to apply permissions.
16425                          * @param {Roo.XComponent} c the component being registerd.
16426                          * 
16427                          */
16428                         'beforebuild' : true,
16429                         /**
16430                          * @event buildcomplete
16431                          * Fires on the top level element when all elements have been built
16432                          * @param {Roo.XComponent} the top level component.
16433                          */
16434                         'buildcomplete' : true
16435                         
16436                 }
16437 });
16438
16439 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16440