roojs-core.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iphone|ipad/.test(ua),
67         isTouch =  (function() {
68             try {  
69                 document.createEvent("TouchEvent");  
70                 return true;  
71             } catch (e) {  
72                 return false;  
73             } 
74             
75         })();
76     // remove css image flicker
77         if(isIE && !isIE7){
78         try{
79             document.execCommand("BackgroundImageCache", false, true);
80         }catch(e){}
81     }
82     
83     Roo.apply(Roo, {
84         /**
85          * True if the browser is in strict mode
86          * @type Boolean
87          */
88         isStrict : isStrict,
89         /**
90          * True if the page is running over SSL
91          * @type Boolean
92          */
93         isSecure : isSecure,
94         /**
95          * True when the document is fully initialized and ready for action
96          * @type Boolean
97          */
98         isReady : false,
99         /**
100          * Turn on debugging output (currently only the factory uses this)
101          * @type Boolean
102          */
103         
104         debug: false,
105
106         /**
107          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
108          * @type Boolean
109          */
110         enableGarbageCollector : true,
111
112         /**
113          * True to automatically purge event listeners after uncaching an element (defaults to false).
114          * Note: this only happens if enableGarbageCollector is true.
115          * @type Boolean
116          */
117         enableListenerCollection:false,
118
119         /**
120          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
121          * the IE insecure content warning (defaults to javascript:false).
122          * @type String
123          */
124         SSL_SECURE_URL : "javascript:false",
125
126         /**
127          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
128          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
129          * @type String
130          */
131         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
132
133         emptyFn : function(){},
134         
135         /**
136          * Copies all the properties of config to obj if they don't already exist.
137          * @param {Object} obj The receiver of the properties
138          * @param {Object} config The source of the properties
139          * @return {Object} returns obj
140          */
141         applyIf : function(o, c){
142             if(o && c){
143                 for(var p in c){
144                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
145                 }
146             }
147             return o;
148         },
149
150         /**
151          * Applies event listeners to elements by selectors when the document is ready.
152          * The event name is specified with an @ suffix.
153 <pre><code>
154 Roo.addBehaviors({
155    // add a listener for click on all anchors in element with id foo
156    '#foo a@click' : function(e, t){
157        // do something
158    },
159
160    // add the same listener to multiple selectors (separated by comma BEFORE the @)
161    '#foo a, #bar span.some-class@mouseover' : function(){
162        // do something
163    }
164 });
165 </code></pre>
166          * @param {Object} obj The list of behaviors to apply
167          */
168         addBehaviors : function(o){
169             if(!Roo.isReady){
170                 Roo.onReady(function(){
171                     Roo.addBehaviors(o);
172                 });
173                 return;
174             }
175             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
176             for(var b in o){
177                 var parts = b.split('@');
178                 if(parts[1]){ // for Object prototype breakers
179                     var s = parts[0];
180                     if(!cache[s]){
181                         cache[s] = Roo.select(s);
182                     }
183                     cache[s].on(parts[1], o[b]);
184                 }
185             }
186             cache = null;
187         },
188
189         /**
190          * Generates unique ids. If the element already has an id, it is unchanged
191          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
192          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
193          * @return {String} The generated Id.
194          */
195         id : function(el, prefix){
196             prefix = prefix || "roo-gen";
197             el = Roo.getDom(el);
198             var id = prefix + (++idSeed);
199             return el ? (el.id ? el.id : (el.id = id)) : id;
200         },
201          
202        
203         /**
204          * Extends one class with another class and optionally overrides members with the passed literal. This class
205          * also adds the function "override()" to the class that can be used to override
206          * members on an instance.
207          * @param {Object} subclass The class inheriting the functionality
208          * @param {Object} superclass The class being extended
209          * @param {Object} overrides (optional) A literal with members
210          * @method extend
211          */
212         extend : function(){
213             // inline overrides
214             var io = function(o){
215                 for(var m in o){
216                     this[m] = o[m];
217                 }
218             };
219             return function(sb, sp, overrides){
220                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
221                     overrides = sp;
222                     sp = sb;
223                     sb = function(){sp.apply(this, arguments);};
224                 }
225                 var F = function(){}, sbp, spp = sp.prototype;
226                 F.prototype = spp;
227                 sbp = sb.prototype = new F();
228                 sbp.constructor=sb;
229                 sb.superclass=spp;
230                 
231                 if(spp.constructor == Object.prototype.constructor){
232                     spp.constructor=sp;
233                    
234                 }
235                 
236                 sb.override = function(o){
237                     Roo.override(sb, o);
238                 };
239                 sbp.override = io;
240                 Roo.override(sb, overrides);
241                 return sb;
242             };
243         }(),
244
245         /**
246          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
247          * Usage:<pre><code>
248 Roo.override(MyClass, {
249     newMethod1: function(){
250         // etc.
251     },
252     newMethod2: function(foo){
253         // etc.
254     }
255 });
256  </code></pre>
257          * @param {Object} origclass The class to override
258          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
259          * containing one or more methods.
260          * @method override
261          */
262         override : function(origclass, overrides){
263             if(overrides){
264                 var p = origclass.prototype;
265                 for(var method in overrides){
266                     p[method] = overrides[method];
267                 }
268             }
269         },
270         /**
271          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
272          * <pre><code>
273 Roo.namespace('Company', 'Company.data');
274 Company.Widget = function() { ... }
275 Company.data.CustomStore = function(config) { ... }
276 </code></pre>
277          * @param {String} namespace1
278          * @param {String} namespace2
279          * @param {String} etc
280          * @method namespace
281          */
282         namespace : function(){
283             var a=arguments, o=null, i, j, d, rt;
284             for (i=0; i<a.length; ++i) {
285                 d=a[i].split(".");
286                 rt = d[0];
287                 /** eval:var:o */
288                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
289                 for (j=1; j<d.length; ++j) {
290                     o[d[j]]=o[d[j]] || {};
291                     o=o[d[j]];
292                 }
293             }
294         },
295         /**
296          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
297          * <pre><code>
298 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
299 Roo.factory(conf, Roo.data);
300 </code></pre>
301          * @param {String} classname
302          * @param {String} namespace (optional)
303          * @method factory
304          */
305          
306         factory : function(c, ns)
307         {
308             // no xtype, no ns or c.xns - or forced off by c.xns
309             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
310                 return c;
311             }
312             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
313             if (c.constructor == ns[c.xtype]) {// already created...
314                 return c;
315             }
316             if (ns[c.xtype]) {
317                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
318                 var ret = new ns[c.xtype](c);
319                 ret.xns = false;
320                 return ret;
321             }
322             c.xns = false; // prevent recursion..
323             return c;
324         },
325          /**
326          * Logs to console if it can.
327          *
328          * @param {String|Object} string
329          * @method log
330          */
331         log : function(s)
332         {
333             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
334                 return; // alerT?
335             }
336             console.log(s);
337             
338         },
339         /**
340          * 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.
341          * @param {Object} o
342          * @return {String}
343          */
344         urlEncode : function(o){
345             if(!o){
346                 return "";
347             }
348             var buf = [];
349             for(var key in o){
350                 var ov = o[key], k = Roo.encodeURIComponent(key);
351                 var type = typeof ov;
352                 if(type == 'undefined'){
353                     buf.push(k, "=&");
354                 }else if(type != "function" && type != "object"){
355                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
356                 }else if(ov instanceof Array){
357                     if (ov.length) {
358                             for(var i = 0, len = ov.length; i < len; i++) {
359                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
360                             }
361                         } else {
362                             buf.push(k, "=&");
363                         }
364                 }
365             }
366             buf.pop();
367             return buf.join("");
368         },
369          /**
370          * Safe version of encodeURIComponent
371          * @param {String} data 
372          * @return {String} 
373          */
374         
375         encodeURIComponent : function (data)
376         {
377             try {
378                 return encodeURIComponent(data);
379             } catch(e) {} // should be an uri encode error.
380             
381             if (data == '' || data == null){
382                return '';
383             }
384             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
385             function nibble_to_hex(nibble){
386                 var chars = '0123456789ABCDEF';
387                 return chars.charAt(nibble);
388             }
389             data = data.toString();
390             var buffer = '';
391             for(var i=0; i<data.length; i++){
392                 var c = data.charCodeAt(i);
393                 var bs = new Array();
394                 if (c > 0x10000){
395                         // 4 bytes
396                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
397                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
398                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
399                     bs[3] = 0x80 | (c & 0x3F);
400                 }else if (c > 0x800){
401                          // 3 bytes
402                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
403                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
404                     bs[2] = 0x80 | (c & 0x3F);
405                 }else if (c > 0x80){
406                        // 2 bytes
407                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
408                     bs[1] = 0x80 | (c & 0x3F);
409                 }else{
410                         // 1 byte
411                     bs[0] = c;
412                 }
413                 for(var j=0; j<bs.length; j++){
414                     var b = bs[j];
415                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
416                             + nibble_to_hex(b &0x0F);
417                     buffer += '%'+hex;
418                }
419             }
420             return buffer;    
421              
422         },
423
424         /**
425          * 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]}.
426          * @param {String} string
427          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
428          * @return {Object} A literal with members
429          */
430         urlDecode : function(string, overwrite){
431             if(!string || !string.length){
432                 return {};
433             }
434             var obj = {};
435             var pairs = string.split('&');
436             var pair, name, value;
437             for(var i = 0, len = pairs.length; i < len; i++){
438                 pair = pairs[i].split('=');
439                 name = decodeURIComponent(pair[0]);
440                 value = decodeURIComponent(pair[1]);
441                 if(overwrite !== true){
442                     if(typeof obj[name] == "undefined"){
443                         obj[name] = value;
444                     }else if(typeof obj[name] == "string"){
445                         obj[name] = [obj[name]];
446                         obj[name].push(value);
447                     }else{
448                         obj[name].push(value);
449                     }
450                 }else{
451                     obj[name] = value;
452                 }
453             }
454             return obj;
455         },
456
457         /**
458          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
459          * passed array is not really an array, your function is called once with it.
460          * The supplied function is called with (Object item, Number index, Array allItems).
461          * @param {Array/NodeList/Mixed} array
462          * @param {Function} fn
463          * @param {Object} scope
464          */
465         each : function(array, fn, scope){
466             if(typeof array.length == "undefined" || typeof array == "string"){
467                 array = [array];
468             }
469             for(var i = 0, len = array.length; i < len; i++){
470                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
471             }
472         },
473
474         // deprecated
475         combine : function(){
476             var as = arguments, l = as.length, r = [];
477             for(var i = 0; i < l; i++){
478                 var a = as[i];
479                 if(a instanceof Array){
480                     r = r.concat(a);
481                 }else if(a.length !== undefined && !a.substr){
482                     r = r.concat(Array.prototype.slice.call(a, 0));
483                 }else{
484                     r.push(a);
485                 }
486             }
487             return r;
488         },
489
490         /**
491          * Escapes the passed string for use in a regular expression
492          * @param {String} str
493          * @return {String}
494          */
495         escapeRe : function(s) {
496             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
497         },
498
499         // internal
500         callback : function(cb, scope, args, delay){
501             if(typeof cb == "function"){
502                 if(delay){
503                     cb.defer(delay, scope, args || []);
504                 }else{
505                     cb.apply(scope, args || []);
506                 }
507             }
508         },
509
510         /**
511          * Return the dom node for the passed string (id), dom node, or Roo.Element
512          * @param {String/HTMLElement/Roo.Element} el
513          * @return HTMLElement
514          */
515         getDom : function(el){
516             if(!el){
517                 return null;
518             }
519             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
520         },
521
522         /**
523         * Shorthand for {@link Roo.ComponentMgr#get}
524         * @param {String} id
525         * @return Roo.Component
526         */
527         getCmp : function(id){
528             return Roo.ComponentMgr.get(id);
529         },
530          
531         num : function(v, defaultValue){
532             if(typeof v != 'number'){
533                 return defaultValue;
534             }
535             return v;
536         },
537
538         destroy : function(){
539             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
540                 var as = a[i];
541                 if(as){
542                     if(as.dom){
543                         as.removeAllListeners();
544                         as.remove();
545                         continue;
546                     }
547                     if(typeof as.purgeListeners == 'function'){
548                         as.purgeListeners();
549                     }
550                     if(typeof as.destroy == 'function'){
551                         as.destroy();
552                     }
553                 }
554             }
555         },
556
557         // inpired by a similar function in mootools library
558         /**
559          * Returns the type of object that is passed in. If the object passed in is null or undefined it
560          * return false otherwise it returns one of the following values:<ul>
561          * <li><b>string</b>: If the object passed is a string</li>
562          * <li><b>number</b>: If the object passed is a number</li>
563          * <li><b>boolean</b>: If the object passed is a boolean value</li>
564          * <li><b>function</b>: If the object passed is a function reference</li>
565          * <li><b>object</b>: If the object passed is an object</li>
566          * <li><b>array</b>: If the object passed is an array</li>
567          * <li><b>regexp</b>: If the object passed is a regular expression</li>
568          * <li><b>element</b>: If the object passed is a DOM Element</li>
569          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
570          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
571          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
572          * @param {Mixed} object
573          * @return {String}
574          */
575         type : function(o){
576             if(o === undefined || o === null){
577                 return false;
578             }
579             if(o.htmlElement){
580                 return 'element';
581             }
582             var t = typeof o;
583             if(t == 'object' && o.nodeName) {
584                 switch(o.nodeType) {
585                     case 1: return 'element';
586                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
587                 }
588             }
589             if(t == 'object' || t == 'function') {
590                 switch(o.constructor) {
591                     case Array: return 'array';
592                     case RegExp: return 'regexp';
593                 }
594                 if(typeof o.length == 'number' && typeof o.item == 'function') {
595                     return 'nodelist';
596                 }
597             }
598             return t;
599         },
600
601         /**
602          * Returns true if the passed value is null, undefined or an empty string (optional).
603          * @param {Mixed} value The value to test
604          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
605          * @return {Boolean}
606          */
607         isEmpty : function(v, allowBlank){
608             return v === null || v === undefined || (!allowBlank ? v === '' : false);
609         },
610         
611         /** @type Boolean */
612         isOpera : isOpera,
613         /** @type Boolean */
614         isSafari : isSafari,
615         /** @type Boolean */
616         isFirefox : isFirefox,
617         /** @type Boolean */
618         isIE : isIE,
619         /** @type Boolean */
620         isIE7 : isIE7,
621         /** @type Boolean */
622         isIE11 : isIE11,
623         /** @type Boolean */
624         isGecko : isGecko,
625         /** @type Boolean */
626         isBorderBox : isBorderBox,
627         /** @type Boolean */
628         isWindows : isWindows,
629         /** @type Boolean */
630         isLinux : isLinux,
631         /** @type Boolean */
632         isMac : isMac,
633         /** @type Boolean */
634         isIOS : isIOS,
635         /** @type Boolean */
636         isTouch : isTouch,
637
638         /**
639          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
640          * you may want to set this to true.
641          * @type Boolean
642          */
643         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
644         
645         
646                 
647         /**
648          * Selects a single element as a Roo Element
649          * This is about as close as you can get to jQuery's $('do crazy stuff')
650          * @param {String} selector The selector/xpath query
651          * @param {Node} root (optional) The start of the query (defaults to document).
652          * @return {Roo.Element}
653          */
654         selectNode : function(selector, root) 
655         {
656             var node = Roo.DomQuery.selectNode(selector,root);
657             return node ? Roo.get(node) : new Roo.Element(false);
658         }
659         
660     });
661
662
663 })();
664
665 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
666                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
667                 "Roo.app", "Roo.ux",
668                 "Roo.bootstrap",
669                 "Roo.bootstrap.dash");
670 /*
671  * Based on:
672  * Ext JS Library 1.1.1
673  * Copyright(c) 2006-2007, Ext JS, LLC.
674  *
675  * Originally Released Under LGPL - original licence link has changed is not relivant.
676  *
677  * Fork - LGPL
678  * <script type="text/javascript">
679  */
680
681 (function() {    
682     // wrappedn so fnCleanup is not in global scope...
683     if(Roo.isIE) {
684         function fnCleanUp() {
685             var p = Function.prototype;
686             delete p.createSequence;
687             delete p.defer;
688             delete p.createDelegate;
689             delete p.createCallback;
690             delete p.createInterceptor;
691
692             window.detachEvent("onunload", fnCleanUp);
693         }
694         window.attachEvent("onunload", fnCleanUp);
695     }
696 })();
697
698
699 /**
700  * @class Function
701  * These functions are available on every Function object (any JavaScript function).
702  */
703 Roo.apply(Function.prototype, {
704      /**
705      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
706      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
707      * Will create a function that is bound to those 2 args.
708      * @return {Function} The new function
709     */
710     createCallback : function(/*args...*/){
711         // make args available, in function below
712         var args = arguments;
713         var method = this;
714         return function() {
715             return method.apply(window, args);
716         };
717     },
718
719     /**
720      * Creates a delegate (callback) that sets the scope to obj.
721      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
722      * Will create a function that is automatically scoped to this.
723      * @param {Object} obj (optional) The object for which the scope is set
724      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
725      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
726      *                                             if a number the args are inserted at the specified position
727      * @return {Function} The new function
728      */
729     createDelegate : function(obj, args, appendArgs){
730         var method = this;
731         return function() {
732             var callArgs = args || arguments;
733             if(appendArgs === true){
734                 callArgs = Array.prototype.slice.call(arguments, 0);
735                 callArgs = callArgs.concat(args);
736             }else if(typeof appendArgs == "number"){
737                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
738                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
739                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
740             }
741             return method.apply(obj || window, callArgs);
742         };
743     },
744
745     /**
746      * Calls this function after the number of millseconds specified.
747      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
748      * @param {Object} obj (optional) The object for which the scope is set
749      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
750      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
751      *                                             if a number the args are inserted at the specified position
752      * @return {Number} The timeout id that can be used with clearTimeout
753      */
754     defer : function(millis, obj, args, appendArgs){
755         var fn = this.createDelegate(obj, args, appendArgs);
756         if(millis){
757             return setTimeout(fn, millis);
758         }
759         fn();
760         return 0;
761     },
762     /**
763      * Create a combined function call sequence of the original function + the passed function.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function
766      * @param {Function} fcn The function to sequence
767      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
768      * @return {Function} The new function
769      */
770     createSequence : function(fcn, scope){
771         if(typeof fcn != "function"){
772             return this;
773         }
774         var method = this;
775         return function() {
776             var retval = method.apply(this || window, arguments);
777             fcn.apply(scope || this || window, arguments);
778             return retval;
779         };
780     },
781
782     /**
783      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
784      * The resulting function returns the results of the original function.
785      * The passed fcn is called with the parameters of the original function.
786      * @addon
787      * @param {Function} fcn The function to call before the original
788      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
789      * @return {Function} The new function
790      */
791     createInterceptor : function(fcn, scope){
792         if(typeof fcn != "function"){
793             return this;
794         }
795         var method = this;
796         return function() {
797             fcn.target = this;
798             fcn.method = method;
799             if(fcn.apply(scope || this || window, arguments) === false){
800                 return;
801             }
802             return method.apply(this || window, arguments);
803         };
804     }
805 });
806 /*
807  * Based on:
808  * Ext JS Library 1.1.1
809  * Copyright(c) 2006-2007, Ext JS, LLC.
810  *
811  * Originally Released Under LGPL - original licence link has changed is not relivant.
812  *
813  * Fork - LGPL
814  * <script type="text/javascript">
815  */
816
817 Roo.applyIf(String, {
818     
819     /** @scope String */
820     
821     /**
822      * Escapes the passed string for ' and \
823      * @param {String} string The string to escape
824      * @return {String} The escaped string
825      * @static
826      */
827     escape : function(string) {
828         return string.replace(/('|\\)/g, "\\$1");
829     },
830
831     /**
832      * Pads the left side of a string with a specified character.  This is especially useful
833      * for normalizing number and date strings.  Example usage:
834      * <pre><code>
835 var s = String.leftPad('123', 5, '0');
836 // s now contains the string: '00123'
837 </code></pre>
838      * @param {String} string The original string
839      * @param {Number} size The total length of the output string
840      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
841      * @return {String} The padded string
842      * @static
843      */
844     leftPad : function (val, size, ch) {
845         var result = new String(val);
846         if(ch === null || ch === undefined || ch === '') {
847             ch = " ";
848         }
849         while (result.length < size) {
850             result = ch + result;
851         }
852         return result;
853     },
854
855     /**
856      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
857      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
858      * <pre><code>
859 var cls = 'my-class', text = 'Some text';
860 var s = String.format('<div class="{0}">{1}</div>', cls, text);
861 // s now contains the string: '<div class="my-class">Some text</div>'
862 </code></pre>
863      * @param {String} string The tokenized string to be formatted
864      * @param {String} value1 The value to replace token {0}
865      * @param {String} value2 Etc...
866      * @return {String} The formatted string
867      * @static
868      */
869     format : function(format){
870         var args = Array.prototype.slice.call(arguments, 1);
871         return format.replace(/\{(\d+)\}/g, function(m, i){
872             return Roo.util.Format.htmlEncode(args[i]);
873         });
874     }
875 });
876
877 /**
878  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
879  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
880  * they are already different, the first value passed in is returned.  Note that this method returns the new value
881  * but does not change the current string.
882  * <pre><code>
883 // alternate sort directions
884 sort = sort.toggle('ASC', 'DESC');
885
886 // instead of conditional logic:
887 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
888 </code></pre>
889  * @param {String} value The value to compare to the current string
890  * @param {String} other The new value to use if the string already equals the first value passed in
891  * @return {String} The new value
892  */
893  
894 String.prototype.toggle = function(value, other){
895     return this == value ? other : value;
896 };/*
897  * Based on:
898  * Ext JS Library 1.1.1
899  * Copyright(c) 2006-2007, Ext JS, LLC.
900  *
901  * Originally Released Under LGPL - original licence link has changed is not relivant.
902  *
903  * Fork - LGPL
904  * <script type="text/javascript">
905  */
906
907  /**
908  * @class Number
909  */
910 Roo.applyIf(Number.prototype, {
911     /**
912      * Checks whether or not the current number is within a desired range.  If the number is already within the
913      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
914      * exceeded.  Note that this method returns the constrained value but does not change the current number.
915      * @param {Number} min The minimum number in the range
916      * @param {Number} max The maximum number in the range
917      * @return {Number} The constrained value if outside the range, otherwise the current value
918      */
919     constrain : function(min, max){
920         return Math.min(Math.max(this, min), max);
921     }
922 });/*
923  * Based on:
924  * Ext JS Library 1.1.1
925  * Copyright(c) 2006-2007, Ext JS, LLC.
926  *
927  * Originally Released Under LGPL - original licence link has changed is not relivant.
928  *
929  * Fork - LGPL
930  * <script type="text/javascript">
931  */
932  /**
933  * @class Array
934  */
935 Roo.applyIf(Array.prototype, {
936     /**
937      * 
938      * Checks whether or not the specified object exists in the array.
939      * @param {Object} o The object to check for
940      * @return {Number} The index of o in the array (or -1 if it is not found)
941      */
942     indexOf : function(o){
943        for (var i = 0, len = this.length; i < len; i++){
944               if(this[i] == o) return i;
945        }
946            return -1;
947     },
948
949     /**
950      * Removes the specified object from the array.  If the object is not found nothing happens.
951      * @param {Object} o The object to remove
952      */
953     remove : function(o){
954        var index = this.indexOf(o);
955        if(index != -1){
956            this.splice(index, 1);
957        }
958     },
959     /**
960      * Map (JS 1.6 compatibility)
961      * @param {Function} function  to call
962      */
963     map : function(fun )
964     {
965         var len = this.length >>> 0;
966         if (typeof fun != "function")
967             throw new TypeError();
968
969         var res = new Array(len);
970         var thisp = arguments[1];
971         for (var i = 0; i < len; i++)
972         {
973             if (i in this)
974                 res[i] = fun.call(thisp, this[i], i, this);
975         }
976
977         return res;
978     }
979     
980 });
981
982
983  /*
984  * Based on:
985  * Ext JS Library 1.1.1
986  * Copyright(c) 2006-2007, Ext JS, LLC.
987  *
988  * Originally Released Under LGPL - original licence link has changed is not relivant.
989  *
990  * Fork - LGPL
991  * <script type="text/javascript">
992  */
993
994 /**
995  * @class Date
996  *
997  * The date parsing and format syntax is a subset of
998  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
999  * supported will provide results equivalent to their PHP versions.
1000  *
1001  * Following is the list of all currently supported formats:
1002  *<pre>
1003 Sample date:
1004 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1005
1006 Format  Output      Description
1007 ------  ----------  --------------------------------------------------------------
1008   d      10         Day of the month, 2 digits with leading zeros
1009   D      Wed        A textual representation of a day, three letters
1010   j      10         Day of the month without leading zeros
1011   l      Wednesday  A full textual representation of the day of the week
1012   S      th         English ordinal day of month suffix, 2 chars (use with j)
1013   w      3          Numeric representation of the day of the week
1014   z      9          The julian date, or day of the year (0-365)
1015   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1016   F      January    A full textual representation of the month
1017   m      01         Numeric representation of a month, with leading zeros
1018   M      Jan        Month name abbreviation, three letters
1019   n      1          Numeric representation of a month, without leading zeros
1020   t      31         Number of days in the given month
1021   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1022   Y      2007       A full numeric representation of a year, 4 digits
1023   y      07         A two digit representation of a year
1024   a      pm         Lowercase Ante meridiem and Post meridiem
1025   A      PM         Uppercase Ante meridiem and Post meridiem
1026   g      3          12-hour format of an hour without leading zeros
1027   G      15         24-hour format of an hour without leading zeros
1028   h      03         12-hour format of an hour with leading zeros
1029   H      15         24-hour format of an hour with leading zeros
1030   i      05         Minutes with leading zeros
1031   s      01         Seconds, with leading zeros
1032   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1033   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1034   T      CST        Timezone setting of the machine running the code
1035   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1036 </pre>
1037  *
1038  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1039  * <pre><code>
1040 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1041 document.write(dt.format('Y-m-d'));                         //2007-01-10
1042 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1043 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
1044  </code></pre>
1045  *
1046  * Here are some standard date/time patterns that you might find helpful.  They
1047  * are not part of the source of Date.js, but to use them you can simply copy this
1048  * block of code into any script that is included after Date.js and they will also become
1049  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1050  * <pre><code>
1051 Date.patterns = {
1052     ISO8601Long:"Y-m-d H:i:s",
1053     ISO8601Short:"Y-m-d",
1054     ShortDate: "n/j/Y",
1055     LongDate: "l, F d, Y",
1056     FullDateTime: "l, F d, Y g:i:s A",
1057     MonthDay: "F d",
1058     ShortTime: "g:i A",
1059     LongTime: "g:i:s A",
1060     SortableDateTime: "Y-m-d\\TH:i:s",
1061     UniversalSortableDateTime: "Y-m-d H:i:sO",
1062     YearMonth: "F, Y"
1063 };
1064 </code></pre>
1065  *
1066  * Example usage:
1067  * <pre><code>
1068 var dt = new Date();
1069 document.write(dt.format(Date.patterns.ShortDate));
1070  </code></pre>
1071  */
1072
1073 /*
1074  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1075  * They generate precompiled functions from date formats instead of parsing and
1076  * processing the pattern every time you format a date.  These functions are available
1077  * on every Date object (any javascript function).
1078  *
1079  * The original article and download are here:
1080  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1081  *
1082  */
1083  
1084  
1085  // was in core
1086 /**
1087  Returns the number of milliseconds between this date and date
1088  @param {Date} date (optional) Defaults to now
1089  @return {Number} The diff in milliseconds
1090  @member Date getElapsed
1091  */
1092 Date.prototype.getElapsed = function(date) {
1093         return Math.abs((date || new Date()).getTime()-this.getTime());
1094 };
1095 // was in date file..
1096
1097
1098 // private
1099 Date.parseFunctions = {count:0};
1100 // private
1101 Date.parseRegexes = [];
1102 // private
1103 Date.formatFunctions = {count:0};
1104
1105 // private
1106 Date.prototype.dateFormat = function(format) {
1107     if (Date.formatFunctions[format] == null) {
1108         Date.createNewFormat(format);
1109     }
1110     var func = Date.formatFunctions[format];
1111     return this[func]();
1112 };
1113
1114
1115 /**
1116  * Formats a date given the supplied format string
1117  * @param {String} format The format string
1118  * @return {String} The formatted date
1119  * @method
1120  */
1121 Date.prototype.format = Date.prototype.dateFormat;
1122
1123 // private
1124 Date.createNewFormat = function(format) {
1125     var funcName = "format" + Date.formatFunctions.count++;
1126     Date.formatFunctions[format] = funcName;
1127     var code = "Date.prototype." + funcName + " = function(){return ";
1128     var special = false;
1129     var ch = '';
1130     for (var i = 0; i < format.length; ++i) {
1131         ch = format.charAt(i);
1132         if (!special && ch == "\\") {
1133             special = true;
1134         }
1135         else if (special) {
1136             special = false;
1137             code += "'" + String.escape(ch) + "' + ";
1138         }
1139         else {
1140             code += Date.getFormatCode(ch);
1141         }
1142     }
1143     /** eval:var:zzzzzzzzzzzzz */
1144     eval(code.substring(0, code.length - 3) + ";}");
1145 };
1146
1147 // private
1148 Date.getFormatCode = function(character) {
1149     switch (character) {
1150     case "d":
1151         return "String.leftPad(this.getDate(), 2, '0') + ";
1152     case "D":
1153         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1154     case "j":
1155         return "this.getDate() + ";
1156     case "l":
1157         return "Date.dayNames[this.getDay()] + ";
1158     case "S":
1159         return "this.getSuffix() + ";
1160     case "w":
1161         return "this.getDay() + ";
1162     case "z":
1163         return "this.getDayOfYear() + ";
1164     case "W":
1165         return "this.getWeekOfYear() + ";
1166     case "F":
1167         return "Date.monthNames[this.getMonth()] + ";
1168     case "m":
1169         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1170     case "M":
1171         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1172     case "n":
1173         return "(this.getMonth() + 1) + ";
1174     case "t":
1175         return "this.getDaysInMonth() + ";
1176     case "L":
1177         return "(this.isLeapYear() ? 1 : 0) + ";
1178     case "Y":
1179         return "this.getFullYear() + ";
1180     case "y":
1181         return "('' + this.getFullYear()).substring(2, 4) + ";
1182     case "a":
1183         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1184     case "A":
1185         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1186     case "g":
1187         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1188     case "G":
1189         return "this.getHours() + ";
1190     case "h":
1191         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1192     case "H":
1193         return "String.leftPad(this.getHours(), 2, '0') + ";
1194     case "i":
1195         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1196     case "s":
1197         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1198     case "O":
1199         return "this.getGMTOffset() + ";
1200     case "P":
1201         return "this.getGMTColonOffset() + ";
1202     case "T":
1203         return "this.getTimezone() + ";
1204     case "Z":
1205         return "(this.getTimezoneOffset() * -60) + ";
1206     default:
1207         return "'" + String.escape(character) + "' + ";
1208     }
1209 };
1210
1211 /**
1212  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1213  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1214  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1215  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1216  * string or the parse operation will fail.
1217  * Example Usage:
1218 <pre><code>
1219 //dt = Fri May 25 2007 (current date)
1220 var dt = new Date();
1221
1222 //dt = Thu May 25 2006 (today's month/day in 2006)
1223 dt = Date.parseDate("2006", "Y");
1224
1225 //dt = Sun Jan 15 2006 (all date parts specified)
1226 dt = Date.parseDate("2006-1-15", "Y-m-d");
1227
1228 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1229 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1230 </code></pre>
1231  * @param {String} input The unparsed date as a string
1232  * @param {String} format The format the date is in
1233  * @return {Date} The parsed date
1234  * @static
1235  */
1236 Date.parseDate = function(input, format) {
1237     if (Date.parseFunctions[format] == null) {
1238         Date.createParser(format);
1239     }
1240     var func = Date.parseFunctions[format];
1241     return Date[func](input);
1242 };
1243 /**
1244  * @private
1245  */
1246
1247 Date.createParser = function(format) {
1248     var funcName = "parse" + Date.parseFunctions.count++;
1249     var regexNum = Date.parseRegexes.length;
1250     var currentGroup = 1;
1251     Date.parseFunctions[format] = funcName;
1252
1253     var code = "Date." + funcName + " = function(input){\n"
1254         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1255         + "var d = new Date();\n"
1256         + "y = d.getFullYear();\n"
1257         + "m = d.getMonth();\n"
1258         + "d = d.getDate();\n"
1259         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1260         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1261         + "if (results && results.length > 0) {";
1262     var regex = "";
1263
1264     var special = false;
1265     var ch = '';
1266     for (var i = 0; i < format.length; ++i) {
1267         ch = format.charAt(i);
1268         if (!special && ch == "\\") {
1269             special = true;
1270         }
1271         else if (special) {
1272             special = false;
1273             regex += String.escape(ch);
1274         }
1275         else {
1276             var obj = Date.formatCodeToRegex(ch, currentGroup);
1277             currentGroup += obj.g;
1278             regex += obj.s;
1279             if (obj.g && obj.c) {
1280                 code += obj.c;
1281             }
1282         }
1283     }
1284
1285     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1286         + "{v = new Date(y, m, d, h, i, s);}\n"
1287         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1288         + "{v = new Date(y, m, d, h, i);}\n"
1289         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1290         + "{v = new Date(y, m, d, h);}\n"
1291         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1292         + "{v = new Date(y, m, d);}\n"
1293         + "else if (y >= 0 && m >= 0)\n"
1294         + "{v = new Date(y, m);}\n"
1295         + "else if (y >= 0)\n"
1296         + "{v = new Date(y);}\n"
1297         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1298         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1299         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1300         + ";}";
1301
1302     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1303     /** eval:var:zzzzzzzzzzzzz */
1304     eval(code);
1305 };
1306
1307 // private
1308 Date.formatCodeToRegex = function(character, currentGroup) {
1309     switch (character) {
1310     case "D":
1311         return {g:0,
1312         c:null,
1313         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1314     case "j":
1315         return {g:1,
1316             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1317             s:"(\\d{1,2})"}; // day of month without leading zeroes
1318     case "d":
1319         return {g:1,
1320             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1321             s:"(\\d{2})"}; // day of month with leading zeroes
1322     case "l":
1323         return {g:0,
1324             c:null,
1325             s:"(?:" + Date.dayNames.join("|") + ")"};
1326     case "S":
1327         return {g:0,
1328             c:null,
1329             s:"(?:st|nd|rd|th)"};
1330     case "w":
1331         return {g:0,
1332             c:null,
1333             s:"\\d"};
1334     case "z":
1335         return {g:0,
1336             c:null,
1337             s:"(?:\\d{1,3})"};
1338     case "W":
1339         return {g:0,
1340             c:null,
1341             s:"(?:\\d{2})"};
1342     case "F":
1343         return {g:1,
1344             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1345             s:"(" + Date.monthNames.join("|") + ")"};
1346     case "M":
1347         return {g:1,
1348             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1349             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1350     case "n":
1351         return {g:1,
1352             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1353             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1354     case "m":
1355         return {g:1,
1356             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1357             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1358     case "t":
1359         return {g:0,
1360             c:null,
1361             s:"\\d{1,2}"};
1362     case "L":
1363         return {g:0,
1364             c:null,
1365             s:"(?:1|0)"};
1366     case "Y":
1367         return {g:1,
1368             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1369             s:"(\\d{4})"};
1370     case "y":
1371         return {g:1,
1372             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1373                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1374             s:"(\\d{1,2})"};
1375     case "a":
1376         return {g:1,
1377             c:"if (results[" + currentGroup + "] == 'am') {\n"
1378                 + "if (h == 12) { h = 0; }\n"
1379                 + "} else { if (h < 12) { h += 12; }}",
1380             s:"(am|pm)"};
1381     case "A":
1382         return {g:1,
1383             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1384                 + "if (h == 12) { h = 0; }\n"
1385                 + "} else { if (h < 12) { h += 12; }}",
1386             s:"(AM|PM)"};
1387     case "g":
1388     case "G":
1389         return {g:1,
1390             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1391             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1392     case "h":
1393     case "H":
1394         return {g:1,
1395             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1396             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1397     case "i":
1398         return {g:1,
1399             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1400             s:"(\\d{2})"};
1401     case "s":
1402         return {g:1,
1403             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1404             s:"(\\d{2})"};
1405     case "O":
1406         return {g:1,
1407             c:[
1408                 "o = results[", currentGroup, "];\n",
1409                 "var sn = o.substring(0,1);\n", // get + / - sign
1410                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1411                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1412                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1413                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1414             ].join(""),
1415             s:"([+\-]\\d{2,4})"};
1416     
1417     
1418     case "P":
1419         return {g:1,
1420                 c:[
1421                    "o = results[", currentGroup, "];\n",
1422                    "var sn = o.substring(0,1);\n",
1423                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1424                    "var mn = o.substring(4,6) % 60;\n",
1425                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1426                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1427             ].join(""),
1428             s:"([+\-]\\d{4})"};
1429     case "T":
1430         return {g:0,
1431             c:null,
1432             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1433     case "Z":
1434         return {g:1,
1435             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1436                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1437             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1438     default:
1439         return {g:0,
1440             c:null,
1441             s:String.escape(character)};
1442     }
1443 };
1444
1445 /**
1446  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1447  * @return {String} The abbreviated timezone name (e.g. 'CST')
1448  */
1449 Date.prototype.getTimezone = function() {
1450     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1451 };
1452
1453 /**
1454  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1455  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1456  */
1457 Date.prototype.getGMTOffset = function() {
1458     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1459         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1460         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1461 };
1462
1463 /**
1464  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1465  * @return {String} 2-characters representing hours and 2-characters representing minutes
1466  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1467  */
1468 Date.prototype.getGMTColonOffset = function() {
1469         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1470                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1471                 + ":"
1472                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1473 }
1474
1475 /**
1476  * Get the numeric day number of the year, adjusted for leap year.
1477  * @return {Number} 0 through 364 (365 in leap years)
1478  */
1479 Date.prototype.getDayOfYear = function() {
1480     var num = 0;
1481     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1482     for (var i = 0; i < this.getMonth(); ++i) {
1483         num += Date.daysInMonth[i];
1484     }
1485     return num + this.getDate() - 1;
1486 };
1487
1488 /**
1489  * Get the string representation of the numeric week number of the year
1490  * (equivalent to the format specifier 'W').
1491  * @return {String} '00' through '52'
1492  */
1493 Date.prototype.getWeekOfYear = function() {
1494     // Skip to Thursday of this week
1495     var now = this.getDayOfYear() + (4 - this.getDay());
1496     // Find the first Thursday of the year
1497     var jan1 = new Date(this.getFullYear(), 0, 1);
1498     var then = (7 - jan1.getDay() + 4);
1499     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1500 };
1501
1502 /**
1503  * Whether or not the current date is in a leap year.
1504  * @return {Boolean} True if the current date is in a leap year, else false
1505  */
1506 Date.prototype.isLeapYear = function() {
1507     var year = this.getFullYear();
1508     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1509 };
1510
1511 /**
1512  * Get the first day of the current month, adjusted for leap year.  The returned value
1513  * is the numeric day index within the week (0-6) which can be used in conjunction with
1514  * the {@link #monthNames} array to retrieve the textual day name.
1515  * Example:
1516  *<pre><code>
1517 var dt = new Date('1/10/2007');
1518 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1519 </code></pre>
1520  * @return {Number} The day number (0-6)
1521  */
1522 Date.prototype.getFirstDayOfMonth = function() {
1523     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1524     return (day < 0) ? (day + 7) : day;
1525 };
1526
1527 /**
1528  * Get the last day of the current month, adjusted for leap year.  The returned value
1529  * is the numeric day index within the week (0-6) which can be used in conjunction with
1530  * the {@link #monthNames} array to retrieve the textual day name.
1531  * Example:
1532  *<pre><code>
1533 var dt = new Date('1/10/2007');
1534 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1535 </code></pre>
1536  * @return {Number} The day number (0-6)
1537  */
1538 Date.prototype.getLastDayOfMonth = function() {
1539     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1540     return (day < 0) ? (day + 7) : day;
1541 };
1542
1543
1544 /**
1545  * Get the first date of this date's month
1546  * @return {Date}
1547  */
1548 Date.prototype.getFirstDateOfMonth = function() {
1549     return new Date(this.getFullYear(), this.getMonth(), 1);
1550 };
1551
1552 /**
1553  * Get the last date of this date's month
1554  * @return {Date}
1555  */
1556 Date.prototype.getLastDateOfMonth = function() {
1557     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1558 };
1559 /**
1560  * Get the number of days in the current month, adjusted for leap year.
1561  * @return {Number} The number of days in the month
1562  */
1563 Date.prototype.getDaysInMonth = function() {
1564     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1565     return Date.daysInMonth[this.getMonth()];
1566 };
1567
1568 /**
1569  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1570  * @return {String} 'st, 'nd', 'rd' or 'th'
1571  */
1572 Date.prototype.getSuffix = function() {
1573     switch (this.getDate()) {
1574         case 1:
1575         case 21:
1576         case 31:
1577             return "st";
1578         case 2:
1579         case 22:
1580             return "nd";
1581         case 3:
1582         case 23:
1583             return "rd";
1584         default:
1585             return "th";
1586     }
1587 };
1588
1589 // private
1590 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1591
1592 /**
1593  * An array of textual month names.
1594  * Override these values for international dates, for example...
1595  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1596  * @type Array
1597  * @static
1598  */
1599 Date.monthNames =
1600    ["January",
1601     "February",
1602     "March",
1603     "April",
1604     "May",
1605     "June",
1606     "July",
1607     "August",
1608     "September",
1609     "October",
1610     "November",
1611     "December"];
1612
1613 /**
1614  * An array of textual day names.
1615  * Override these values for international dates, for example...
1616  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1617  * @type Array
1618  * @static
1619  */
1620 Date.dayNames =
1621    ["Sunday",
1622     "Monday",
1623     "Tuesday",
1624     "Wednesday",
1625     "Thursday",
1626     "Friday",
1627     "Saturday"];
1628
1629 // private
1630 Date.y2kYear = 50;
1631 // private
1632 Date.monthNumbers = {
1633     Jan:0,
1634     Feb:1,
1635     Mar:2,
1636     Apr:3,
1637     May:4,
1638     Jun:5,
1639     Jul:6,
1640     Aug:7,
1641     Sep:8,
1642     Oct:9,
1643     Nov:10,
1644     Dec:11};
1645
1646 /**
1647  * Creates and returns a new Date instance with the exact same date value as the called instance.
1648  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1649  * variable will also be changed.  When the intention is to create a new variable that will not
1650  * modify the original instance, you should create a clone.
1651  *
1652  * Example of correctly cloning a date:
1653  * <pre><code>
1654 //wrong way:
1655 var orig = new Date('10/1/2006');
1656 var copy = orig;
1657 copy.setDate(5);
1658 document.write(orig);  //returns 'Thu Oct 05 2006'!
1659
1660 //correct way:
1661 var orig = new Date('10/1/2006');
1662 var copy = orig.clone();
1663 copy.setDate(5);
1664 document.write(orig);  //returns 'Thu Oct 01 2006'
1665 </code></pre>
1666  * @return {Date} The new Date instance
1667  */
1668 Date.prototype.clone = function() {
1669         return new Date(this.getTime());
1670 };
1671
1672 /**
1673  * Clears any time information from this date
1674  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1675  @return {Date} this or the clone
1676  */
1677 Date.prototype.clearTime = function(clone){
1678     if(clone){
1679         return this.clone().clearTime();
1680     }
1681     this.setHours(0);
1682     this.setMinutes(0);
1683     this.setSeconds(0);
1684     this.setMilliseconds(0);
1685     return this;
1686 };
1687
1688 // private
1689 // safari setMonth is broken
1690 if(Roo.isSafari){
1691     Date.brokenSetMonth = Date.prototype.setMonth;
1692         Date.prototype.setMonth = function(num){
1693                 if(num <= -1){
1694                         var n = Math.ceil(-num);
1695                         var back_year = Math.ceil(n/12);
1696                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1697                         this.setFullYear(this.getFullYear() - back_year);
1698                         return Date.brokenSetMonth.call(this, month);
1699                 } else {
1700                         return Date.brokenSetMonth.apply(this, arguments);
1701                 }
1702         };
1703 }
1704
1705 /** Date interval constant 
1706 * @static 
1707 * @type String */
1708 Date.MILLI = "ms";
1709 /** Date interval constant 
1710 * @static 
1711 * @type String */
1712 Date.SECOND = "s";
1713 /** Date interval constant 
1714 * @static 
1715 * @type String */
1716 Date.MINUTE = "mi";
1717 /** Date interval constant 
1718 * @static 
1719 * @type String */
1720 Date.HOUR = "h";
1721 /** Date interval constant 
1722 * @static 
1723 * @type String */
1724 Date.DAY = "d";
1725 /** Date interval constant 
1726 * @static 
1727 * @type String */
1728 Date.MONTH = "mo";
1729 /** Date interval constant 
1730 * @static 
1731 * @type String */
1732 Date.YEAR = "y";
1733
1734 /**
1735  * Provides a convenient method of performing basic date arithmetic.  This method
1736  * does not modify the Date instance being called - it creates and returns
1737  * a new Date instance containing the resulting date value.
1738  *
1739  * Examples:
1740  * <pre><code>
1741 //Basic usage:
1742 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1743 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1744
1745 //Negative values will subtract correctly:
1746 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1747 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1748
1749 //You can even chain several calls together in one line!
1750 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1751 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1752  </code></pre>
1753  *
1754  * @param {String} interval   A valid date interval enum value
1755  * @param {Number} value      The amount to add to the current date
1756  * @return {Date} The new Date instance
1757  */
1758 Date.prototype.add = function(interval, value){
1759   var d = this.clone();
1760   if (!interval || value === 0) return d;
1761   switch(interval.toLowerCase()){
1762     case Date.MILLI:
1763       d.setMilliseconds(this.getMilliseconds() + value);
1764       break;
1765     case Date.SECOND:
1766       d.setSeconds(this.getSeconds() + value);
1767       break;
1768     case Date.MINUTE:
1769       d.setMinutes(this.getMinutes() + value);
1770       break;
1771     case Date.HOUR:
1772       d.setHours(this.getHours() + value);
1773       break;
1774     case Date.DAY:
1775       d.setDate(this.getDate() + value);
1776       break;
1777     case Date.MONTH:
1778       var day = this.getDate();
1779       if(day > 28){
1780           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1781       }
1782       d.setDate(day);
1783       d.setMonth(this.getMonth() + value);
1784       break;
1785     case Date.YEAR:
1786       d.setFullYear(this.getFullYear() + value);
1787       break;
1788   }
1789   return d;
1790 };
1791 /*
1792  * Based on:
1793  * Ext JS Library 1.1.1
1794  * Copyright(c) 2006-2007, Ext JS, LLC.
1795  *
1796  * Originally Released Under LGPL - original licence link has changed is not relivant.
1797  *
1798  * Fork - LGPL
1799  * <script type="text/javascript">
1800  */
1801
1802 /**
1803  * @class Roo.lib.Dom
1804  * @static
1805  * 
1806  * Dom utils (from YIU afaik)
1807  * 
1808  **/
1809 Roo.lib.Dom = {
1810     /**
1811      * Get the view width
1812      * @param {Boolean} full True will get the full document, otherwise it's the view width
1813      * @return {Number} The width
1814      */
1815      
1816     getViewWidth : function(full) {
1817         return full ? this.getDocumentWidth() : this.getViewportWidth();
1818     },
1819     /**
1820      * Get the view height
1821      * @param {Boolean} full True will get the full document, otherwise it's the view height
1822      * @return {Number} The height
1823      */
1824     getViewHeight : function(full) {
1825         return full ? this.getDocumentHeight() : this.getViewportHeight();
1826     },
1827
1828     getDocumentHeight: function() {
1829         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1830         return Math.max(scrollHeight, this.getViewportHeight());
1831     },
1832
1833     getDocumentWidth: function() {
1834         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1835         return Math.max(scrollWidth, this.getViewportWidth());
1836     },
1837
1838     getViewportHeight: function() {
1839         var height = self.innerHeight;
1840         var mode = document.compatMode;
1841
1842         if ((mode || Roo.isIE) && !Roo.isOpera) {
1843             height = (mode == "CSS1Compat") ?
1844                      document.documentElement.clientHeight :
1845                      document.body.clientHeight;
1846         }
1847
1848         return height;
1849     },
1850
1851     getViewportWidth: function() {
1852         var width = self.innerWidth;
1853         var mode = document.compatMode;
1854
1855         if (mode || Roo.isIE) {
1856             width = (mode == "CSS1Compat") ?
1857                     document.documentElement.clientWidth :
1858                     document.body.clientWidth;
1859         }
1860         return width;
1861     },
1862
1863     isAncestor : function(p, c) {
1864         p = Roo.getDom(p);
1865         c = Roo.getDom(c);
1866         if (!p || !c) {
1867             return false;
1868         }
1869
1870         if (p.contains && !Roo.isSafari) {
1871             return p.contains(c);
1872         } else if (p.compareDocumentPosition) {
1873             return !!(p.compareDocumentPosition(c) & 16);
1874         } else {
1875             var parent = c.parentNode;
1876             while (parent) {
1877                 if (parent == p) {
1878                     return true;
1879                 }
1880                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1881                     return false;
1882                 }
1883                 parent = parent.parentNode;
1884             }
1885             return false;
1886         }
1887     },
1888
1889     getRegion : function(el) {
1890         return Roo.lib.Region.getRegion(el);
1891     },
1892
1893     getY : function(el) {
1894         return this.getXY(el)[1];
1895     },
1896
1897     getX : function(el) {
1898         return this.getXY(el)[0];
1899     },
1900
1901     getXY : function(el) {
1902         var p, pe, b, scroll, bd = document.body;
1903         el = Roo.getDom(el);
1904         var fly = Roo.lib.AnimBase.fly;
1905         if (el.getBoundingClientRect) {
1906             b = el.getBoundingClientRect();
1907             scroll = fly(document).getScroll();
1908             return [b.left + scroll.left, b.top + scroll.top];
1909         }
1910         var x = 0, y = 0;
1911
1912         p = el;
1913
1914         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1915
1916         while (p) {
1917
1918             x += p.offsetLeft;
1919             y += p.offsetTop;
1920
1921             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1922                 hasAbsolute = true;
1923             }
1924
1925             if (Roo.isGecko) {
1926                 pe = fly(p);
1927
1928                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1929                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1930
1931
1932                 x += bl;
1933                 y += bt;
1934
1935
1936                 if (p != el && pe.getStyle('overflow') != 'visible') {
1937                     x += bl;
1938                     y += bt;
1939                 }
1940             }
1941             p = p.offsetParent;
1942         }
1943
1944         if (Roo.isSafari && hasAbsolute) {
1945             x -= bd.offsetLeft;
1946             y -= bd.offsetTop;
1947         }
1948
1949         if (Roo.isGecko && !hasAbsolute) {
1950             var dbd = fly(bd);
1951             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1952             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1953         }
1954
1955         p = el.parentNode;
1956         while (p && p != bd) {
1957             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1958                 x -= p.scrollLeft;
1959                 y -= p.scrollTop;
1960             }
1961             p = p.parentNode;
1962         }
1963         return [x, y];
1964     },
1965  
1966   
1967
1968
1969     setXY : function(el, xy) {
1970         el = Roo.fly(el, '_setXY');
1971         el.position();
1972         var pts = el.translatePoints(xy);
1973         if (xy[0] !== false) {
1974             el.dom.style.left = pts.left + "px";
1975         }
1976         if (xy[1] !== false) {
1977             el.dom.style.top = pts.top + "px";
1978         }
1979     },
1980
1981     setX : function(el, x) {
1982         this.setXY(el, [x, false]);
1983     },
1984
1985     setY : function(el, y) {
1986         this.setXY(el, [false, y]);
1987     }
1988 };
1989 /*
1990  * Portions of this file are based on pieces of Yahoo User Interface Library
1991  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1992  * YUI licensed under the BSD License:
1993  * http://developer.yahoo.net/yui/license.txt
1994  * <script type="text/javascript">
1995  *
1996  */
1997
1998 Roo.lib.Event = function() {
1999     var loadComplete = false;
2000     var listeners = [];
2001     var unloadListeners = [];
2002     var retryCount = 0;
2003     var onAvailStack = [];
2004     var counter = 0;
2005     var lastError = null;
2006
2007     return {
2008         POLL_RETRYS: 200,
2009         POLL_INTERVAL: 20,
2010         EL: 0,
2011         TYPE: 1,
2012         FN: 2,
2013         WFN: 3,
2014         OBJ: 3,
2015         ADJ_SCOPE: 4,
2016         _interval: null,
2017
2018         startInterval: function() {
2019             if (!this._interval) {
2020                 var self = this;
2021                 var callback = function() {
2022                     self._tryPreloadAttach();
2023                 };
2024                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2025
2026             }
2027         },
2028
2029         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2030             onAvailStack.push({ id:         p_id,
2031                 fn:         p_fn,
2032                 obj:        p_obj,
2033                 override:   p_override,
2034                 checkReady: false    });
2035
2036             retryCount = this.POLL_RETRYS;
2037             this.startInterval();
2038         },
2039
2040
2041         addListener: function(el, eventName, fn) {
2042             el = Roo.getDom(el);
2043             if (!el || !fn) {
2044                 return false;
2045             }
2046
2047             if ("unload" == eventName) {
2048                 unloadListeners[unloadListeners.length] =
2049                 [el, eventName, fn];
2050                 return true;
2051             }
2052
2053             var wrappedFn = function(e) {
2054                 return fn(Roo.lib.Event.getEvent(e));
2055             };
2056
2057             var li = [el, eventName, fn, wrappedFn];
2058
2059             var index = listeners.length;
2060             listeners[index] = li;
2061
2062             this.doAdd(el, eventName, wrappedFn, false);
2063             return true;
2064
2065         },
2066
2067
2068         removeListener: function(el, eventName, fn) {
2069             var i, len;
2070
2071             el = Roo.getDom(el);
2072
2073             if(!fn) {
2074                 return this.purgeElement(el, false, eventName);
2075             }
2076
2077
2078             if ("unload" == eventName) {
2079
2080                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2081                     var li = unloadListeners[i];
2082                     if (li &&
2083                         li[0] == el &&
2084                         li[1] == eventName &&
2085                         li[2] == fn) {
2086                         unloadListeners.splice(i, 1);
2087                         return true;
2088                     }
2089                 }
2090
2091                 return false;
2092             }
2093
2094             var cacheItem = null;
2095
2096
2097             var index = arguments[3];
2098
2099             if ("undefined" == typeof index) {
2100                 index = this._getCacheIndex(el, eventName, fn);
2101             }
2102
2103             if (index >= 0) {
2104                 cacheItem = listeners[index];
2105             }
2106
2107             if (!el || !cacheItem) {
2108                 return false;
2109             }
2110
2111             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2112
2113             delete listeners[index][this.WFN];
2114             delete listeners[index][this.FN];
2115             listeners.splice(index, 1);
2116
2117             return true;
2118
2119         },
2120
2121
2122         getTarget: function(ev, resolveTextNode) {
2123             ev = ev.browserEvent || ev;
2124             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2125             var t = ev.target || ev.srcElement;
2126             return this.resolveTextNode(t);
2127         },
2128
2129
2130         resolveTextNode: function(node) {
2131             if (Roo.isSafari && node && 3 == node.nodeType) {
2132                 return node.parentNode;
2133             } else {
2134                 return node;
2135             }
2136         },
2137
2138
2139         getPageX: function(ev) {
2140             ev = ev.browserEvent || ev;
2141             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2142             var x = ev.pageX;
2143             if (!x && 0 !== x) {
2144                 x = ev.clientX || 0;
2145
2146                 if (Roo.isIE) {
2147                     x += this.getScroll()[1];
2148                 }
2149             }
2150
2151             return x;
2152         },
2153
2154
2155         getPageY: function(ev) {
2156             ev = ev.browserEvent || ev;
2157             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2158             var y = ev.pageY;
2159             if (!y && 0 !== y) {
2160                 y = ev.clientY || 0;
2161
2162                 if (Roo.isIE) {
2163                     y += this.getScroll()[0];
2164                 }
2165             }
2166
2167
2168             return y;
2169         },
2170
2171
2172         getXY: function(ev) {
2173             ev = ev.browserEvent || ev;
2174             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2175             return [this.getPageX(ev), this.getPageY(ev)];
2176         },
2177
2178
2179         getRelatedTarget: function(ev) {
2180             ev = ev.browserEvent || ev;
2181             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2182             var t = ev.relatedTarget;
2183             if (!t) {
2184                 if (ev.type == "mouseout") {
2185                     t = ev.toElement;
2186                 } else if (ev.type == "mouseover") {
2187                     t = ev.fromElement;
2188                 }
2189             }
2190
2191             return this.resolveTextNode(t);
2192         },
2193
2194
2195         getTime: function(ev) {
2196             ev = ev.browserEvent || ev;
2197             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2198             if (!ev.time) {
2199                 var t = new Date().getTime();
2200                 try {
2201                     ev.time = t;
2202                 } catch(ex) {
2203                     this.lastError = ex;
2204                     return t;
2205                 }
2206             }
2207
2208             return ev.time;
2209         },
2210
2211
2212         stopEvent: function(ev) {
2213             this.stopPropagation(ev);
2214             this.preventDefault(ev);
2215         },
2216
2217
2218         stopPropagation: function(ev) {
2219             ev = ev.browserEvent || ev;
2220             if (ev.stopPropagation) {
2221                 ev.stopPropagation();
2222             } else {
2223                 ev.cancelBubble = true;
2224             }
2225         },
2226
2227
2228         preventDefault: function(ev) {
2229             ev = ev.browserEvent || ev;
2230             if(ev.preventDefault) {
2231                 ev.preventDefault();
2232             } else {
2233                 ev.returnValue = false;
2234             }
2235         },
2236
2237
2238         getEvent: function(e) {
2239             var ev = e || window.event;
2240             if (!ev) {
2241                 var c = this.getEvent.caller;
2242                 while (c) {
2243                     ev = c.arguments[0];
2244                     if (ev && Event == ev.constructor) {
2245                         break;
2246                     }
2247                     c = c.caller;
2248                 }
2249             }
2250             return ev;
2251         },
2252
2253
2254         getCharCode: function(ev) {
2255             ev = ev.browserEvent || ev;
2256             return ev.charCode || ev.keyCode || 0;
2257         },
2258
2259
2260         _getCacheIndex: function(el, eventName, fn) {
2261             for (var i = 0,len = listeners.length; i < len; ++i) {
2262                 var li = listeners[i];
2263                 if (li &&
2264                     li[this.FN] == fn &&
2265                     li[this.EL] == el &&
2266                     li[this.TYPE] == eventName) {
2267                     return i;
2268                 }
2269             }
2270
2271             return -1;
2272         },
2273
2274
2275         elCache: {},
2276
2277
2278         getEl: function(id) {
2279             return document.getElementById(id);
2280         },
2281
2282
2283         clearCache: function() {
2284         },
2285
2286
2287         _load: function(e) {
2288             loadComplete = true;
2289             var EU = Roo.lib.Event;
2290
2291
2292             if (Roo.isIE) {
2293                 EU.doRemove(window, "load", EU._load);
2294             }
2295         },
2296
2297
2298         _tryPreloadAttach: function() {
2299
2300             if (this.locked) {
2301                 return false;
2302             }
2303
2304             this.locked = true;
2305
2306
2307             var tryAgain = !loadComplete;
2308             if (!tryAgain) {
2309                 tryAgain = (retryCount > 0);
2310             }
2311
2312
2313             var notAvail = [];
2314             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2315                 var item = onAvailStack[i];
2316                 if (item) {
2317                     var el = this.getEl(item.id);
2318
2319                     if (el) {
2320                         if (!item.checkReady ||
2321                             loadComplete ||
2322                             el.nextSibling ||
2323                             (document && document.body)) {
2324
2325                             var scope = el;
2326                             if (item.override) {
2327                                 if (item.override === true) {
2328                                     scope = item.obj;
2329                                 } else {
2330                                     scope = item.override;
2331                                 }
2332                             }
2333                             item.fn.call(scope, item.obj);
2334                             onAvailStack[i] = null;
2335                         }
2336                     } else {
2337                         notAvail.push(item);
2338                     }
2339                 }
2340             }
2341
2342             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2343
2344             if (tryAgain) {
2345
2346                 this.startInterval();
2347             } else {
2348                 clearInterval(this._interval);
2349                 this._interval = null;
2350             }
2351
2352             this.locked = false;
2353
2354             return true;
2355
2356         },
2357
2358
2359         purgeElement: function(el, recurse, eventName) {
2360             var elListeners = this.getListeners(el, eventName);
2361             if (elListeners) {
2362                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2363                     var l = elListeners[i];
2364                     this.removeListener(el, l.type, l.fn);
2365                 }
2366             }
2367
2368             if (recurse && el && el.childNodes) {
2369                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2370                     this.purgeElement(el.childNodes[i], recurse, eventName);
2371                 }
2372             }
2373         },
2374
2375
2376         getListeners: function(el, eventName) {
2377             var results = [], searchLists;
2378             if (!eventName) {
2379                 searchLists = [listeners, unloadListeners];
2380             } else if (eventName == "unload") {
2381                 searchLists = [unloadListeners];
2382             } else {
2383                 searchLists = [listeners];
2384             }
2385
2386             for (var j = 0; j < searchLists.length; ++j) {
2387                 var searchList = searchLists[j];
2388                 if (searchList && searchList.length > 0) {
2389                     for (var i = 0,len = searchList.length; i < len; ++i) {
2390                         var l = searchList[i];
2391                         if (l && l[this.EL] === el &&
2392                             (!eventName || eventName === l[this.TYPE])) {
2393                             results.push({
2394                                 type:   l[this.TYPE],
2395                                 fn:     l[this.FN],
2396                                 obj:    l[this.OBJ],
2397                                 adjust: l[this.ADJ_SCOPE],
2398                                 index:  i
2399                             });
2400                         }
2401                     }
2402                 }
2403             }
2404
2405             return (results.length) ? results : null;
2406         },
2407
2408
2409         _unload: function(e) {
2410
2411             var EU = Roo.lib.Event, i, j, l, len, index;
2412
2413             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2414                 l = unloadListeners[i];
2415                 if (l) {
2416                     var scope = window;
2417                     if (l[EU.ADJ_SCOPE]) {
2418                         if (l[EU.ADJ_SCOPE] === true) {
2419                             scope = l[EU.OBJ];
2420                         } else {
2421                             scope = l[EU.ADJ_SCOPE];
2422                         }
2423                     }
2424                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2425                     unloadListeners[i] = null;
2426                     l = null;
2427                     scope = null;
2428                 }
2429             }
2430
2431             unloadListeners = null;
2432
2433             if (listeners && listeners.length > 0) {
2434                 j = listeners.length;
2435                 while (j) {
2436                     index = j - 1;
2437                     l = listeners[index];
2438                     if (l) {
2439                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2440                                 l[EU.FN], index);
2441                     }
2442                     j = j - 1;
2443                 }
2444                 l = null;
2445
2446                 EU.clearCache();
2447             }
2448
2449             EU.doRemove(window, "unload", EU._unload);
2450
2451         },
2452
2453
2454         getScroll: function() {
2455             var dd = document.documentElement, db = document.body;
2456             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2457                 return [dd.scrollTop, dd.scrollLeft];
2458             } else if (db) {
2459                 return [db.scrollTop, db.scrollLeft];
2460             } else {
2461                 return [0, 0];
2462             }
2463         },
2464
2465
2466         doAdd: function () {
2467             if (window.addEventListener) {
2468                 return function(el, eventName, fn, capture) {
2469                     el.addEventListener(eventName, fn, (capture));
2470                 };
2471             } else if (window.attachEvent) {
2472                 return function(el, eventName, fn, capture) {
2473                     el.attachEvent("on" + eventName, fn);
2474                 };
2475             } else {
2476                 return function() {
2477                 };
2478             }
2479         }(),
2480
2481
2482         doRemove: function() {
2483             if (window.removeEventListener) {
2484                 return function (el, eventName, fn, capture) {
2485                     el.removeEventListener(eventName, fn, (capture));
2486                 };
2487             } else if (window.detachEvent) {
2488                 return function (el, eventName, fn) {
2489                     el.detachEvent("on" + eventName, fn);
2490                 };
2491             } else {
2492                 return function() {
2493                 };
2494             }
2495         }()
2496     };
2497     
2498 }();
2499 (function() {     
2500    
2501     var E = Roo.lib.Event;
2502     E.on = E.addListener;
2503     E.un = E.removeListener;
2504
2505     if (document && document.body) {
2506         E._load();
2507     } else {
2508         E.doAdd(window, "load", E._load);
2509     }
2510     E.doAdd(window, "unload", E._unload);
2511     E._tryPreloadAttach();
2512 })();
2513
2514 /*
2515  * Portions of this file are based on pieces of Yahoo User Interface Library
2516  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2517  * YUI licensed under the BSD License:
2518  * http://developer.yahoo.net/yui/license.txt
2519  * <script type="text/javascript">
2520  *
2521  */
2522
2523 (function() {
2524     /**
2525      * @class Roo.lib.Ajax
2526      *
2527      */
2528     Roo.lib.Ajax = {
2529         /**
2530          * @static 
2531          */
2532         request : function(method, uri, cb, data, options) {
2533             if(options){
2534                 var hs = options.headers;
2535                 if(hs){
2536                     for(var h in hs){
2537                         if(hs.hasOwnProperty(h)){
2538                             this.initHeader(h, hs[h], false);
2539                         }
2540                     }
2541                 }
2542                 if(options.xmlData){
2543                     this.initHeader('Content-Type', 'text/xml', false);
2544                     method = 'POST';
2545                     data = options.xmlData;
2546                 }
2547             }
2548
2549             return this.asyncRequest(method, uri, cb, data);
2550         },
2551
2552         serializeForm : function(form) {
2553             if(typeof form == 'string') {
2554                 form = (document.getElementById(form) || document.forms[form]);
2555             }
2556
2557             var el, name, val, disabled, data = '', hasSubmit = false;
2558             for (var i = 0; i < form.elements.length; i++) {
2559                 el = form.elements[i];
2560                 disabled = form.elements[i].disabled;
2561                 name = form.elements[i].name;
2562                 val = form.elements[i].value;
2563
2564                 if (!disabled && name){
2565                     switch (el.type)
2566                             {
2567                         case 'select-one':
2568                         case 'select-multiple':
2569                             for (var j = 0; j < el.options.length; j++) {
2570                                 if (el.options[j].selected) {
2571                                     if (Roo.isIE) {
2572                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2573                                     }
2574                                     else {
2575                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2576                                     }
2577                                 }
2578                             }
2579                             break;
2580                         case 'radio':
2581                         case 'checkbox':
2582                             if (el.checked) {
2583                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584                             }
2585                             break;
2586                         case 'file':
2587
2588                         case undefined:
2589
2590                         case 'reset':
2591
2592                         case 'button':
2593
2594                             break;
2595                         case 'submit':
2596                             if(hasSubmit == false) {
2597                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2598                                 hasSubmit = true;
2599                             }
2600                             break;
2601                         default:
2602                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2603                             break;
2604                     }
2605                 }
2606             }
2607             data = data.substr(0, data.length - 1);
2608             return data;
2609         },
2610
2611         headers:{},
2612
2613         hasHeaders:false,
2614
2615         useDefaultHeader:true,
2616
2617         defaultPostHeader:'application/x-www-form-urlencoded',
2618
2619         useDefaultXhrHeader:true,
2620
2621         defaultXhrHeader:'XMLHttpRequest',
2622
2623         hasDefaultHeaders:true,
2624
2625         defaultHeaders:{},
2626
2627         poll:{},
2628
2629         timeout:{},
2630
2631         pollInterval:50,
2632
2633         transactionId:0,
2634
2635         setProgId:function(id)
2636         {
2637             this.activeX.unshift(id);
2638         },
2639
2640         setDefaultPostHeader:function(b)
2641         {
2642             this.useDefaultHeader = b;
2643         },
2644
2645         setDefaultXhrHeader:function(b)
2646         {
2647             this.useDefaultXhrHeader = b;
2648         },
2649
2650         setPollingInterval:function(i)
2651         {
2652             if (typeof i == 'number' && isFinite(i)) {
2653                 this.pollInterval = i;
2654             }
2655         },
2656
2657         createXhrObject:function(transactionId)
2658         {
2659             var obj,http;
2660             try
2661             {
2662
2663                 http = new XMLHttpRequest();
2664
2665                 obj = { conn:http, tId:transactionId };
2666             }
2667             catch(e)
2668             {
2669                 for (var i = 0; i < this.activeX.length; ++i) {
2670                     try
2671                     {
2672
2673                         http = new ActiveXObject(this.activeX[i]);
2674
2675                         obj = { conn:http, tId:transactionId };
2676                         break;
2677                     }
2678                     catch(e) {
2679                     }
2680                 }
2681             }
2682             finally
2683             {
2684                 return obj;
2685             }
2686         },
2687
2688         getConnectionObject:function()
2689         {
2690             var o;
2691             var tId = this.transactionId;
2692
2693             try
2694             {
2695                 o = this.createXhrObject(tId);
2696                 if (o) {
2697                     this.transactionId++;
2698                 }
2699             }
2700             catch(e) {
2701             }
2702             finally
2703             {
2704                 return o;
2705             }
2706         },
2707
2708         asyncRequest:function(method, uri, callback, postData)
2709         {
2710             var o = this.getConnectionObject();
2711
2712             if (!o) {
2713                 return null;
2714             }
2715             else {
2716                 o.conn.open(method, uri, true);
2717
2718                 if (this.useDefaultXhrHeader) {
2719                     if (!this.defaultHeaders['X-Requested-With']) {
2720                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2721                     }
2722                 }
2723
2724                 if(postData && this.useDefaultHeader){
2725                     this.initHeader('Content-Type', this.defaultPostHeader);
2726                 }
2727
2728                  if (this.hasDefaultHeaders || this.hasHeaders) {
2729                     this.setHeader(o);
2730                 }
2731
2732                 this.handleReadyState(o, callback);
2733                 o.conn.send(postData || null);
2734
2735                 return o;
2736             }
2737         },
2738
2739         handleReadyState:function(o, callback)
2740         {
2741             var oConn = this;
2742
2743             if (callback && callback.timeout) {
2744                 
2745                 this.timeout[o.tId] = window.setTimeout(function() {
2746                     oConn.abort(o, callback, true);
2747                 }, callback.timeout);
2748             }
2749
2750             this.poll[o.tId] = window.setInterval(
2751                     function() {
2752                         if (o.conn && o.conn.readyState == 4) {
2753                             window.clearInterval(oConn.poll[o.tId]);
2754                             delete oConn.poll[o.tId];
2755
2756                             if(callback && callback.timeout) {
2757                                 window.clearTimeout(oConn.timeout[o.tId]);
2758                                 delete oConn.timeout[o.tId];
2759                             }
2760
2761                             oConn.handleTransactionResponse(o, callback);
2762                         }
2763                     }
2764                     , this.pollInterval);
2765         },
2766
2767         handleTransactionResponse:function(o, callback, isAbort)
2768         {
2769
2770             if (!callback) {
2771                 this.releaseObject(o);
2772                 return;
2773             }
2774
2775             var httpStatus, responseObject;
2776
2777             try
2778             {
2779                 if (o.conn.status !== undefined && o.conn.status != 0) {
2780                     httpStatus = o.conn.status;
2781                 }
2782                 else {
2783                     httpStatus = 13030;
2784                 }
2785             }
2786             catch(e) {
2787
2788
2789                 httpStatus = 13030;
2790             }
2791
2792             if (httpStatus >= 200 && httpStatus < 300) {
2793                 responseObject = this.createResponseObject(o, callback.argument);
2794                 if (callback.success) {
2795                     if (!callback.scope) {
2796                         callback.success(responseObject);
2797                     }
2798                     else {
2799
2800
2801                         callback.success.apply(callback.scope, [responseObject]);
2802                     }
2803                 }
2804             }
2805             else {
2806                 switch (httpStatus) {
2807
2808                     case 12002:
2809                     case 12029:
2810                     case 12030:
2811                     case 12031:
2812                     case 12152:
2813                     case 13030:
2814                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
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                         break;
2824                     default:
2825                         responseObject = this.createResponseObject(o, callback.argument);
2826                         if (callback.failure) {
2827                             if (!callback.scope) {
2828                                 callback.failure(responseObject);
2829                             }
2830                             else {
2831                                 callback.failure.apply(callback.scope, [responseObject]);
2832                             }
2833                         }
2834                 }
2835             }
2836
2837             this.releaseObject(o);
2838             responseObject = null;
2839         },
2840
2841         createResponseObject:function(o, callbackArg)
2842         {
2843             var obj = {};
2844             var headerObj = {};
2845
2846             try
2847             {
2848                 var headerStr = o.conn.getAllResponseHeaders();
2849                 var header = headerStr.split('\n');
2850                 for (var i = 0; i < header.length; i++) {
2851                     var delimitPos = header[i].indexOf(':');
2852                     if (delimitPos != -1) {
2853                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2854                     }
2855                 }
2856             }
2857             catch(e) {
2858             }
2859
2860             obj.tId = o.tId;
2861             obj.status = o.conn.status;
2862             obj.statusText = o.conn.statusText;
2863             obj.getResponseHeader = headerObj;
2864             obj.getAllResponseHeaders = headerStr;
2865             obj.responseText = o.conn.responseText;
2866             obj.responseXML = o.conn.responseXML;
2867
2868             if (typeof callbackArg !== undefined) {
2869                 obj.argument = callbackArg;
2870             }
2871
2872             return obj;
2873         },
2874
2875         createExceptionObject:function(tId, callbackArg, isAbort)
2876         {
2877             var COMM_CODE = 0;
2878             var COMM_ERROR = 'communication failure';
2879             var ABORT_CODE = -1;
2880             var ABORT_ERROR = 'transaction aborted';
2881
2882             var obj = {};
2883
2884             obj.tId = tId;
2885             if (isAbort) {
2886                 obj.status = ABORT_CODE;
2887                 obj.statusText = ABORT_ERROR;
2888             }
2889             else {
2890                 obj.status = COMM_CODE;
2891                 obj.statusText = COMM_ERROR;
2892             }
2893
2894             if (callbackArg) {
2895                 obj.argument = callbackArg;
2896             }
2897
2898             return obj;
2899         },
2900
2901         initHeader:function(label, value, isDefault)
2902         {
2903             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2904
2905             if (headerObj[label] === undefined) {
2906                 headerObj[label] = value;
2907             }
2908             else {
2909
2910
2911                 headerObj[label] = value + "," + headerObj[label];
2912             }
2913
2914             if (isDefault) {
2915                 this.hasDefaultHeaders = true;
2916             }
2917             else {
2918                 this.hasHeaders = true;
2919             }
2920         },
2921
2922
2923         setHeader:function(o)
2924         {
2925             if (this.hasDefaultHeaders) {
2926                 for (var prop in this.defaultHeaders) {
2927                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2928                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2929                     }
2930                 }
2931             }
2932
2933             if (this.hasHeaders) {
2934                 for (var prop in this.headers) {
2935                     if (this.headers.hasOwnProperty(prop)) {
2936                         o.conn.setRequestHeader(prop, this.headers[prop]);
2937                     }
2938                 }
2939                 this.headers = {};
2940                 this.hasHeaders = false;
2941             }
2942         },
2943
2944         resetDefaultHeaders:function() {
2945             delete this.defaultHeaders;
2946             this.defaultHeaders = {};
2947             this.hasDefaultHeaders = false;
2948         },
2949
2950         abort:function(o, callback, isTimeout)
2951         {
2952             if(this.isCallInProgress(o)) {
2953                 o.conn.abort();
2954                 window.clearInterval(this.poll[o.tId]);
2955                 delete this.poll[o.tId];
2956                 if (isTimeout) {
2957                     delete this.timeout[o.tId];
2958                 }
2959
2960                 this.handleTransactionResponse(o, callback, true);
2961
2962                 return true;
2963             }
2964             else {
2965                 return false;
2966             }
2967         },
2968
2969
2970         isCallInProgress:function(o)
2971         {
2972             if (o && o.conn) {
2973                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2974             }
2975             else {
2976
2977                 return false;
2978             }
2979         },
2980
2981
2982         releaseObject:function(o)
2983         {
2984
2985             o.conn = null;
2986
2987             o = null;
2988         },
2989
2990         activeX:[
2991         'MSXML2.XMLHTTP.3.0',
2992         'MSXML2.XMLHTTP',
2993         'Microsoft.XMLHTTP'
2994         ]
2995
2996
2997     };
2998 })();/*
2999  * Portions of this file are based on pieces of Yahoo User Interface Library
3000  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3001  * YUI licensed under the BSD License:
3002  * http://developer.yahoo.net/yui/license.txt
3003  * <script type="text/javascript">
3004  *
3005  */
3006
3007 Roo.lib.Region = function(t, r, b, l) {
3008     this.top = t;
3009     this[1] = t;
3010     this.right = r;
3011     this.bottom = b;
3012     this.left = l;
3013     this[0] = l;
3014 };
3015
3016
3017 Roo.lib.Region.prototype = {
3018     contains : function(region) {
3019         return ( region.left >= this.left &&
3020                  region.right <= this.right &&
3021                  region.top >= this.top &&
3022                  region.bottom <= this.bottom    );
3023
3024     },
3025
3026     getArea : function() {
3027         return ( (this.bottom - this.top) * (this.right - this.left) );
3028     },
3029
3030     intersect : function(region) {
3031         var t = Math.max(this.top, region.top);
3032         var r = Math.min(this.right, region.right);
3033         var b = Math.min(this.bottom, region.bottom);
3034         var l = Math.max(this.left, region.left);
3035
3036         if (b >= t && r >= l) {
3037             return new Roo.lib.Region(t, r, b, l);
3038         } else {
3039             return null;
3040         }
3041     },
3042     union : function(region) {
3043         var t = Math.min(this.top, region.top);
3044         var r = Math.max(this.right, region.right);
3045         var b = Math.max(this.bottom, region.bottom);
3046         var l = Math.min(this.left, region.left);
3047
3048         return new Roo.lib.Region(t, r, b, l);
3049     },
3050
3051     adjust : function(t, l, b, r) {
3052         this.top += t;
3053         this.left += l;
3054         this.right += r;
3055         this.bottom += b;
3056         return this;
3057     }
3058 };
3059
3060 Roo.lib.Region.getRegion = function(el) {
3061     var p = Roo.lib.Dom.getXY(el);
3062
3063     var t = p[1];
3064     var r = p[0] + el.offsetWidth;
3065     var b = p[1] + el.offsetHeight;
3066     var l = p[0];
3067
3068     return new Roo.lib.Region(t, r, b, l);
3069 };
3070 /*
3071  * Portions of this file are based on pieces of Yahoo User Interface Library
3072  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3073  * YUI licensed under the BSD License:
3074  * http://developer.yahoo.net/yui/license.txt
3075  * <script type="text/javascript">
3076  *
3077  */
3078 //@@dep Roo.lib.Region
3079
3080
3081 Roo.lib.Point = function(x, y) {
3082     if (x instanceof Array) {
3083         y = x[1];
3084         x = x[0];
3085     }
3086     this.x = this.right = this.left = this[0] = x;
3087     this.y = this.top = this.bottom = this[1] = y;
3088 };
3089
3090 Roo.lib.Point.prototype = new Roo.lib.Region();
3091 /*
3092  * Portions of this file are based on pieces of Yahoo User Interface Library
3093  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3094  * YUI licensed under the BSD License:
3095  * http://developer.yahoo.net/yui/license.txt
3096  * <script type="text/javascript">
3097  *
3098  */
3099  
3100 (function() {   
3101
3102     Roo.lib.Anim = {
3103         scroll : function(el, args, duration, easing, cb, scope) {
3104             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3105         },
3106
3107         motion : function(el, args, duration, easing, cb, scope) {
3108             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3109         },
3110
3111         color : function(el, args, duration, easing, cb, scope) {
3112             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3113         },
3114
3115         run : function(el, args, duration, easing, cb, scope, type) {
3116             type = type || Roo.lib.AnimBase;
3117             if (typeof easing == "string") {
3118                 easing = Roo.lib.Easing[easing];
3119             }
3120             var anim = new type(el, args, duration, easing);
3121             anim.animateX(function() {
3122                 Roo.callback(cb, scope);
3123             });
3124             return anim;
3125         }
3126     };
3127 })();/*
3128  * Portions of this file are based on pieces of Yahoo User Interface Library
3129  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3130  * YUI licensed under the BSD License:
3131  * http://developer.yahoo.net/yui/license.txt
3132  * <script type="text/javascript">
3133  *
3134  */
3135
3136 (function() {    
3137     var libFlyweight;
3138     
3139     function fly(el) {
3140         if (!libFlyweight) {
3141             libFlyweight = new Roo.Element.Flyweight();
3142         }
3143         libFlyweight.dom = el;
3144         return libFlyweight;
3145     }
3146
3147     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3148     
3149    
3150     
3151     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3152         if (el) {
3153             this.init(el, attributes, duration, method);
3154         }
3155     };
3156
3157     Roo.lib.AnimBase.fly = fly;
3158     
3159     
3160     
3161     Roo.lib.AnimBase.prototype = {
3162
3163         toString: function() {
3164             var el = this.getEl();
3165             var id = el.id || el.tagName;
3166             return ("Anim " + id);
3167         },
3168
3169         patterns: {
3170             noNegatives:        /width|height|opacity|padding/i,
3171             offsetAttribute:  /^((width|height)|(top|left))$/,
3172             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3173             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3174         },
3175
3176
3177         doMethod: function(attr, start, end) {
3178             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3179         },
3180
3181
3182         setAttribute: function(attr, val, unit) {
3183             if (this.patterns.noNegatives.test(attr)) {
3184                 val = (val > 0) ? val : 0;
3185             }
3186
3187             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3188         },
3189
3190
3191         getAttribute: function(attr) {
3192             var el = this.getEl();
3193             var val = fly(el).getStyle(attr);
3194
3195             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3196                 return parseFloat(val);
3197             }
3198
3199             var a = this.patterns.offsetAttribute.exec(attr) || [];
3200             var pos = !!( a[3] );
3201             var box = !!( a[2] );
3202
3203
3204             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3205                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3206             } else {
3207                 val = 0;
3208             }
3209
3210             return val;
3211         },
3212
3213
3214         getDefaultUnit: function(attr) {
3215             if (this.patterns.defaultUnit.test(attr)) {
3216                 return 'px';
3217             }
3218
3219             return '';
3220         },
3221
3222         animateX : function(callback, scope) {
3223             var f = function() {
3224                 this.onComplete.removeListener(f);
3225                 if (typeof callback == "function") {
3226                     callback.call(scope || this, this);
3227                 }
3228             };
3229             this.onComplete.addListener(f, this);
3230             this.animate();
3231         },
3232
3233
3234         setRuntimeAttribute: function(attr) {
3235             var start;
3236             var end;
3237             var attributes = this.attributes;
3238
3239             this.runtimeAttributes[attr] = {};
3240
3241             var isset = function(prop) {
3242                 return (typeof prop !== 'undefined');
3243             };
3244
3245             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3246                 return false;
3247             }
3248
3249             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3250
3251
3252             if (isset(attributes[attr]['to'])) {
3253                 end = attributes[attr]['to'];
3254             } else if (isset(attributes[attr]['by'])) {
3255                 if (start.constructor == Array) {
3256                     end = [];
3257                     for (var i = 0, len = start.length; i < len; ++i) {
3258                         end[i] = start[i] + attributes[attr]['by'][i];
3259                     }
3260                 } else {
3261                     end = start + attributes[attr]['by'];
3262                 }
3263             }
3264
3265             this.runtimeAttributes[attr].start = start;
3266             this.runtimeAttributes[attr].end = end;
3267
3268
3269             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3270         },
3271
3272
3273         init: function(el, attributes, duration, method) {
3274
3275             var isAnimated = false;
3276
3277
3278             var startTime = null;
3279
3280
3281             var actualFrames = 0;
3282
3283
3284             el = Roo.getDom(el);
3285
3286
3287             this.attributes = attributes || {};
3288
3289
3290             this.duration = duration || 1;
3291
3292
3293             this.method = method || Roo.lib.Easing.easeNone;
3294
3295
3296             this.useSeconds = true;
3297
3298
3299             this.currentFrame = 0;
3300
3301
3302             this.totalFrames = Roo.lib.AnimMgr.fps;
3303
3304
3305             this.getEl = function() {
3306                 return el;
3307             };
3308
3309
3310             this.isAnimated = function() {
3311                 return isAnimated;
3312             };
3313
3314
3315             this.getStartTime = function() {
3316                 return startTime;
3317             };
3318
3319             this.runtimeAttributes = {};
3320
3321
3322             this.animate = function() {
3323                 if (this.isAnimated()) {
3324                     return false;
3325                 }
3326
3327                 this.currentFrame = 0;
3328
3329                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3330
3331                 Roo.lib.AnimMgr.registerElement(this);
3332             };
3333
3334
3335             this.stop = function(finish) {
3336                 if (finish) {
3337                     this.currentFrame = this.totalFrames;
3338                     this._onTween.fire();
3339                 }
3340                 Roo.lib.AnimMgr.stop(this);
3341             };
3342
3343             var onStart = function() {
3344                 this.onStart.fire();
3345
3346                 this.runtimeAttributes = {};
3347                 for (var attr in this.attributes) {
3348                     this.setRuntimeAttribute(attr);
3349                 }
3350
3351                 isAnimated = true;
3352                 actualFrames = 0;
3353                 startTime = new Date();
3354             };
3355
3356
3357             var onTween = function() {
3358                 var data = {
3359                     duration: new Date() - this.getStartTime(),
3360                     currentFrame: this.currentFrame
3361                 };
3362
3363                 data.toString = function() {
3364                     return (
3365                             'duration: ' + data.duration +
3366                             ', currentFrame: ' + data.currentFrame
3367                             );
3368                 };
3369
3370                 this.onTween.fire(data);
3371
3372                 var runtimeAttributes = this.runtimeAttributes;
3373
3374                 for (var attr in runtimeAttributes) {
3375                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3376                 }
3377
3378                 actualFrames += 1;
3379             };
3380
3381             var onComplete = function() {
3382                 var actual_duration = (new Date() - startTime) / 1000 ;
3383
3384                 var data = {
3385                     duration: actual_duration,
3386                     frames: actualFrames,
3387                     fps: actualFrames / actual_duration
3388                 };
3389
3390                 data.toString = function() {
3391                     return (
3392                             'duration: ' + data.duration +
3393                             ', frames: ' + data.frames +
3394                             ', fps: ' + data.fps
3395                             );
3396                 };
3397
3398                 isAnimated = false;
3399                 actualFrames = 0;
3400                 this.onComplete.fire(data);
3401             };
3402
3403
3404             this._onStart = new Roo.util.Event(this);
3405             this.onStart = new Roo.util.Event(this);
3406             this.onTween = new Roo.util.Event(this);
3407             this._onTween = new Roo.util.Event(this);
3408             this.onComplete = new Roo.util.Event(this);
3409             this._onComplete = new Roo.util.Event(this);
3410             this._onStart.addListener(onStart);
3411             this._onTween.addListener(onTween);
3412             this._onComplete.addListener(onComplete);
3413         }
3414     };
3415 })();
3416 /*
3417  * Portions of this file are based on pieces of Yahoo User Interface Library
3418  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3419  * YUI licensed under the BSD License:
3420  * http://developer.yahoo.net/yui/license.txt
3421  * <script type="text/javascript">
3422  *
3423  */
3424
3425 Roo.lib.AnimMgr = new function() {
3426
3427     var thread = null;
3428
3429
3430     var queue = [];
3431
3432
3433     var tweenCount = 0;
3434
3435
3436     this.fps = 1000;
3437
3438
3439     this.delay = 1;
3440
3441
3442     this.registerElement = function(tween) {
3443         queue[queue.length] = tween;
3444         tweenCount += 1;
3445         tween._onStart.fire();
3446         this.start();
3447     };
3448
3449
3450     this.unRegister = function(tween, index) {
3451         tween._onComplete.fire();
3452         index = index || getIndex(tween);
3453         if (index != -1) {
3454             queue.splice(index, 1);
3455         }
3456
3457         tweenCount -= 1;
3458         if (tweenCount <= 0) {
3459             this.stop();
3460         }
3461     };
3462
3463
3464     this.start = function() {
3465         if (thread === null) {
3466             thread = setInterval(this.run, this.delay);
3467         }
3468     };
3469
3470
3471     this.stop = function(tween) {
3472         if (!tween) {
3473             clearInterval(thread);
3474
3475             for (var i = 0, len = queue.length; i < len; ++i) {
3476                 if (queue[0].isAnimated()) {
3477                     this.unRegister(queue[0], 0);
3478                 }
3479             }
3480
3481             queue = [];
3482             thread = null;
3483             tweenCount = 0;
3484         }
3485         else {
3486             this.unRegister(tween);
3487         }
3488     };
3489
3490
3491     this.run = function() {
3492         for (var i = 0, len = queue.length; i < len; ++i) {
3493             var tween = queue[i];
3494             if (!tween || !tween.isAnimated()) {
3495                 continue;
3496             }
3497
3498             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3499             {
3500                 tween.currentFrame += 1;
3501
3502                 if (tween.useSeconds) {
3503                     correctFrame(tween);
3504                 }
3505                 tween._onTween.fire();
3506             }
3507             else {
3508                 Roo.lib.AnimMgr.stop(tween, i);
3509             }
3510         }
3511     };
3512
3513     var getIndex = function(anim) {
3514         for (var i = 0, len = queue.length; i < len; ++i) {
3515             if (queue[i] == anim) {
3516                 return i;
3517             }
3518         }
3519         return -1;
3520     };
3521
3522
3523     var correctFrame = function(tween) {
3524         var frames = tween.totalFrames;
3525         var frame = tween.currentFrame;
3526         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3527         var elapsed = (new Date() - tween.getStartTime());
3528         var tweak = 0;
3529
3530         if (elapsed < tween.duration * 1000) {
3531             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3532         } else {
3533             tweak = frames - (frame + 1);
3534         }
3535         if (tweak > 0 && isFinite(tweak)) {
3536             if (tween.currentFrame + tweak >= frames) {
3537                 tweak = frames - (frame + 1);
3538             }
3539
3540             tween.currentFrame += tweak;
3541         }
3542     };
3543 };
3544
3545     /*
3546  * Portions of this file are based on pieces of Yahoo User Interface Library
3547  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3548  * YUI licensed under the BSD License:
3549  * http://developer.yahoo.net/yui/license.txt
3550  * <script type="text/javascript">
3551  *
3552  */
3553 Roo.lib.Bezier = new function() {
3554
3555         this.getPosition = function(points, t) {
3556             var n = points.length;
3557             var tmp = [];
3558
3559             for (var i = 0; i < n; ++i) {
3560                 tmp[i] = [points[i][0], points[i][1]];
3561             }
3562
3563             for (var j = 1; j < n; ++j) {
3564                 for (i = 0; i < n - j; ++i) {
3565                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3566                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3567                 }
3568             }
3569
3570             return [ tmp[0][0], tmp[0][1] ];
3571
3572         };
3573     };/*
3574  * Portions of this file are based on pieces of Yahoo User Interface Library
3575  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3576  * YUI licensed under the BSD License:
3577  * http://developer.yahoo.net/yui/license.txt
3578  * <script type="text/javascript">
3579  *
3580  */
3581 (function() {
3582
3583     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3584         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3585     };
3586
3587     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3588
3589     var fly = Roo.lib.AnimBase.fly;
3590     var Y = Roo.lib;
3591     var superclass = Y.ColorAnim.superclass;
3592     var proto = Y.ColorAnim.prototype;
3593
3594     proto.toString = function() {
3595         var el = this.getEl();
3596         var id = el.id || el.tagName;
3597         return ("ColorAnim " + id);
3598     };
3599
3600     proto.patterns.color = /color$/i;
3601     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3602     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3603     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3604     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3605
3606
3607     proto.parseColor = function(s) {
3608         if (s.length == 3) {
3609             return s;
3610         }
3611
3612         var c = this.patterns.hex.exec(s);
3613         if (c && c.length == 4) {
3614             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3615         }
3616
3617         c = this.patterns.rgb.exec(s);
3618         if (c && c.length == 4) {
3619             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3620         }
3621
3622         c = this.patterns.hex3.exec(s);
3623         if (c && c.length == 4) {
3624             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3625         }
3626
3627         return null;
3628     };
3629     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3630     proto.getAttribute = function(attr) {
3631         var el = this.getEl();
3632         if (this.patterns.color.test(attr)) {
3633             var val = fly(el).getStyle(attr);
3634
3635             if (this.patterns.transparent.test(val)) {
3636                 var parent = el.parentNode;
3637                 val = fly(parent).getStyle(attr);
3638
3639                 while (parent && this.patterns.transparent.test(val)) {
3640                     parent = parent.parentNode;
3641                     val = fly(parent).getStyle(attr);
3642                     if (parent.tagName.toUpperCase() == 'HTML') {
3643                         val = '#fff';
3644                     }
3645                 }
3646             }
3647         } else {
3648             val = superclass.getAttribute.call(this, attr);
3649         }
3650
3651         return val;
3652     };
3653     proto.getAttribute = function(attr) {
3654         var el = this.getEl();
3655         if (this.patterns.color.test(attr)) {
3656             var val = fly(el).getStyle(attr);
3657
3658             if (this.patterns.transparent.test(val)) {
3659                 var parent = el.parentNode;
3660                 val = fly(parent).getStyle(attr);
3661
3662                 while (parent && this.patterns.transparent.test(val)) {
3663                     parent = parent.parentNode;
3664                     val = fly(parent).getStyle(attr);
3665                     if (parent.tagName.toUpperCase() == 'HTML') {
3666                         val = '#fff';
3667                     }
3668                 }
3669             }
3670         } else {
3671             val = superclass.getAttribute.call(this, attr);
3672         }
3673
3674         return val;
3675     };
3676
3677     proto.doMethod = function(attr, start, end) {
3678         var val;
3679
3680         if (this.patterns.color.test(attr)) {
3681             val = [];
3682             for (var i = 0, len = start.length; i < len; ++i) {
3683                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3684             }
3685
3686             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3687         }
3688         else {
3689             val = superclass.doMethod.call(this, attr, start, end);
3690         }
3691
3692         return val;
3693     };
3694
3695     proto.setRuntimeAttribute = function(attr) {
3696         superclass.setRuntimeAttribute.call(this, attr);
3697
3698         if (this.patterns.color.test(attr)) {
3699             var attributes = this.attributes;
3700             var start = this.parseColor(this.runtimeAttributes[attr].start);
3701             var end = this.parseColor(this.runtimeAttributes[attr].end);
3702
3703             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3704                 end = this.parseColor(attributes[attr].by);
3705
3706                 for (var i = 0, len = start.length; i < len; ++i) {
3707                     end[i] = start[i] + end[i];
3708                 }
3709             }
3710
3711             this.runtimeAttributes[attr].start = start;
3712             this.runtimeAttributes[attr].end = end;
3713         }
3714     };
3715 })();
3716
3717 /*
3718  * Portions of this file are based on pieces of Yahoo User Interface Library
3719  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3720  * YUI licensed under the BSD License:
3721  * http://developer.yahoo.net/yui/license.txt
3722  * <script type="text/javascript">
3723  *
3724  */
3725 Roo.lib.Easing = {
3726
3727
3728     easeNone: function (t, b, c, d) {
3729         return c * t / d + b;
3730     },
3731
3732
3733     easeIn: function (t, b, c, d) {
3734         return c * (t /= d) * t + b;
3735     },
3736
3737
3738     easeOut: function (t, b, c, d) {
3739         return -c * (t /= d) * (t - 2) + b;
3740     },
3741
3742
3743     easeBoth: function (t, b, c, d) {
3744         if ((t /= d / 2) < 1) {
3745             return c / 2 * t * t + b;
3746         }
3747
3748         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3749     },
3750
3751
3752     easeInStrong: function (t, b, c, d) {
3753         return c * (t /= d) * t * t * t + b;
3754     },
3755
3756
3757     easeOutStrong: function (t, b, c, d) {
3758         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3759     },
3760
3761
3762     easeBothStrong: function (t, b, c, d) {
3763         if ((t /= d / 2) < 1) {
3764             return c / 2 * t * t * t * t + b;
3765         }
3766
3767         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3768     },
3769
3770
3771
3772     elasticIn: function (t, b, c, d, a, p) {
3773         if (t == 0) {
3774             return b;
3775         }
3776         if ((t /= d) == 1) {
3777             return b + c;
3778         }
3779         if (!p) {
3780             p = d * .3;
3781         }
3782
3783         if (!a || a < Math.abs(c)) {
3784             a = c;
3785             var s = p / 4;
3786         }
3787         else {
3788             var s = p / (2 * Math.PI) * Math.asin(c / a);
3789         }
3790
3791         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3792     },
3793
3794
3795     elasticOut: function (t, b, c, d, a, p) {
3796         if (t == 0) {
3797             return b;
3798         }
3799         if ((t /= d) == 1) {
3800             return b + c;
3801         }
3802         if (!p) {
3803             p = d * .3;
3804         }
3805
3806         if (!a || a < Math.abs(c)) {
3807             a = c;
3808             var s = p / 4;
3809         }
3810         else {
3811             var s = p / (2 * Math.PI) * Math.asin(c / a);
3812         }
3813
3814         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3815     },
3816
3817
3818     elasticBoth: function (t, b, c, d, a, p) {
3819         if (t == 0) {
3820             return b;
3821         }
3822
3823         if ((t /= d / 2) == 2) {
3824             return b + c;
3825         }
3826
3827         if (!p) {
3828             p = d * (.3 * 1.5);
3829         }
3830
3831         if (!a || a < Math.abs(c)) {
3832             a = c;
3833             var s = p / 4;
3834         }
3835         else {
3836             var s = p / (2 * Math.PI) * Math.asin(c / a);
3837         }
3838
3839         if (t < 1) {
3840             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3841                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3842         }
3843         return a * Math.pow(2, -10 * (t -= 1)) *
3844                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3845     },
3846
3847
3848
3849     backIn: function (t, b, c, d, s) {
3850         if (typeof s == 'undefined') {
3851             s = 1.70158;
3852         }
3853         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3854     },
3855
3856
3857     backOut: function (t, b, c, d, s) {
3858         if (typeof s == 'undefined') {
3859             s = 1.70158;
3860         }
3861         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3862     },
3863
3864
3865     backBoth: function (t, b, c, d, s) {
3866         if (typeof s == 'undefined') {
3867             s = 1.70158;
3868         }
3869
3870         if ((t /= d / 2 ) < 1) {
3871             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3872         }
3873         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3874     },
3875
3876
3877     bounceIn: function (t, b, c, d) {
3878         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3879     },
3880
3881
3882     bounceOut: function (t, b, c, d) {
3883         if ((t /= d) < (1 / 2.75)) {
3884             return c * (7.5625 * t * t) + b;
3885         } else if (t < (2 / 2.75)) {
3886             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3887         } else if (t < (2.5 / 2.75)) {
3888             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3889         }
3890         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3891     },
3892
3893
3894     bounceBoth: function (t, b, c, d) {
3895         if (t < d / 2) {
3896             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3897         }
3898         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3899     }
3900 };/*
3901  * Portions of this file are based on pieces of Yahoo User Interface Library
3902  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3903  * YUI licensed under the BSD License:
3904  * http://developer.yahoo.net/yui/license.txt
3905  * <script type="text/javascript">
3906  *
3907  */
3908     (function() {
3909         Roo.lib.Motion = function(el, attributes, duration, method) {
3910             if (el) {
3911                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3912             }
3913         };
3914
3915         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3916
3917
3918         var Y = Roo.lib;
3919         var superclass = Y.Motion.superclass;
3920         var proto = Y.Motion.prototype;
3921
3922         proto.toString = function() {
3923             var el = this.getEl();
3924             var id = el.id || el.tagName;
3925             return ("Motion " + id);
3926         };
3927
3928         proto.patterns.points = /^points$/i;
3929
3930         proto.setAttribute = function(attr, val, unit) {
3931             if (this.patterns.points.test(attr)) {
3932                 unit = unit || 'px';
3933                 superclass.setAttribute.call(this, 'left', val[0], unit);
3934                 superclass.setAttribute.call(this, 'top', val[1], unit);
3935             } else {
3936                 superclass.setAttribute.call(this, attr, val, unit);
3937             }
3938         };
3939
3940         proto.getAttribute = function(attr) {
3941             if (this.patterns.points.test(attr)) {
3942                 var val = [
3943                         superclass.getAttribute.call(this, 'left'),
3944                         superclass.getAttribute.call(this, 'top')
3945                         ];
3946             } else {
3947                 val = superclass.getAttribute.call(this, attr);
3948             }
3949
3950             return val;
3951         };
3952
3953         proto.doMethod = function(attr, start, end) {
3954             var val = null;
3955
3956             if (this.patterns.points.test(attr)) {
3957                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3958                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3959             } else {
3960                 val = superclass.doMethod.call(this, attr, start, end);
3961             }
3962             return val;
3963         };
3964
3965         proto.setRuntimeAttribute = function(attr) {
3966             if (this.patterns.points.test(attr)) {
3967                 var el = this.getEl();
3968                 var attributes = this.attributes;
3969                 var start;
3970                 var control = attributes['points']['control'] || [];
3971                 var end;
3972                 var i, len;
3973
3974                 if (control.length > 0 && !(control[0] instanceof Array)) {
3975                     control = [control];
3976                 } else {
3977                     var tmp = [];
3978                     for (i = 0,len = control.length; i < len; ++i) {
3979                         tmp[i] = control[i];
3980                     }
3981                     control = tmp;
3982                 }
3983
3984                 Roo.fly(el).position();
3985
3986                 if (isset(attributes['points']['from'])) {
3987                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3988                 }
3989                 else {
3990                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3991                 }
3992
3993                 start = this.getAttribute('points');
3994
3995
3996                 if (isset(attributes['points']['to'])) {
3997                     end = translateValues.call(this, attributes['points']['to'], start);
3998
3999                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4000                     for (i = 0,len = control.length; i < len; ++i) {
4001                         control[i] = translateValues.call(this, control[i], start);
4002                     }
4003
4004
4005                 } else if (isset(attributes['points']['by'])) {
4006                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4007
4008                     for (i = 0,len = control.length; i < len; ++i) {
4009                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4010                     }
4011                 }
4012
4013                 this.runtimeAttributes[attr] = [start];
4014
4015                 if (control.length > 0) {
4016                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4017                 }
4018
4019                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4020             }
4021             else {
4022                 superclass.setRuntimeAttribute.call(this, attr);
4023             }
4024         };
4025
4026         var translateValues = function(val, start) {
4027             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4028             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4029
4030             return val;
4031         };
4032
4033         var isset = function(prop) {
4034             return (typeof prop !== 'undefined');
4035         };
4036     })();
4037 /*
4038  * Portions of this file are based on pieces of Yahoo User Interface Library
4039  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4040  * YUI licensed under the BSD License:
4041  * http://developer.yahoo.net/yui/license.txt
4042  * <script type="text/javascript">
4043  *
4044  */
4045     (function() {
4046         Roo.lib.Scroll = function(el, attributes, duration, method) {
4047             if (el) {
4048                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4049             }
4050         };
4051
4052         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4053
4054
4055         var Y = Roo.lib;
4056         var superclass = Y.Scroll.superclass;
4057         var proto = Y.Scroll.prototype;
4058
4059         proto.toString = function() {
4060             var el = this.getEl();
4061             var id = el.id || el.tagName;
4062             return ("Scroll " + id);
4063         };
4064
4065         proto.doMethod = function(attr, start, end) {
4066             var val = null;
4067
4068             if (attr == 'scroll') {
4069                 val = [
4070                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4071                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4072                         ];
4073
4074             } else {
4075                 val = superclass.doMethod.call(this, attr, start, end);
4076             }
4077             return val;
4078         };
4079
4080         proto.getAttribute = function(attr) {
4081             var val = null;
4082             var el = this.getEl();
4083
4084             if (attr == 'scroll') {
4085                 val = [ el.scrollLeft, el.scrollTop ];
4086             } else {
4087                 val = superclass.getAttribute.call(this, attr);
4088             }
4089
4090             return val;
4091         };
4092
4093         proto.setAttribute = function(attr, val, unit) {
4094             var el = this.getEl();
4095
4096             if (attr == 'scroll') {
4097                 el.scrollLeft = val[0];
4098                 el.scrollTop = val[1];
4099             } else {
4100                 superclass.setAttribute.call(this, attr, val, unit);
4101             }
4102         };
4103     })();
4104 /*
4105  * Based on:
4106  * Ext JS Library 1.1.1
4107  * Copyright(c) 2006-2007, Ext JS, LLC.
4108  *
4109  * Originally Released Under LGPL - original licence link has changed is not relivant.
4110  *
4111  * Fork - LGPL
4112  * <script type="text/javascript">
4113  */
4114
4115
4116 // nasty IE9 hack - what a pile of crap that is..
4117
4118  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4119     Range.prototype.createContextualFragment = function (html) {
4120         var doc = window.document;
4121         var container = doc.createElement("div");
4122         container.innerHTML = html;
4123         var frag = doc.createDocumentFragment(), n;
4124         while ((n = container.firstChild)) {
4125             frag.appendChild(n);
4126         }
4127         return frag;
4128     };
4129 }
4130
4131 /**
4132  * @class Roo.DomHelper
4133  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4134  * 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>.
4135  * @singleton
4136  */
4137 Roo.DomHelper = function(){
4138     var tempTableEl = null;
4139     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4140     var tableRe = /^table|tbody|tr|td$/i;
4141     var xmlns = {};
4142     // build as innerHTML where available
4143     /** @ignore */
4144     var createHtml = function(o){
4145         if(typeof o == 'string'){
4146             return o;
4147         }
4148         var b = "";
4149         if(!o.tag){
4150             o.tag = "div";
4151         }
4152         b += "<" + o.tag;
4153         for(var attr in o){
4154             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4155             if(attr == "style"){
4156                 var s = o["style"];
4157                 if(typeof s == "function"){
4158                     s = s.call();
4159                 }
4160                 if(typeof s == "string"){
4161                     b += ' style="' + s + '"';
4162                 }else if(typeof s == "object"){
4163                     b += ' style="';
4164                     for(var key in s){
4165                         if(typeof s[key] != "function"){
4166                             b += key + ":" + s[key] + ";";
4167                         }
4168                     }
4169                     b += '"';
4170                 }
4171             }else{
4172                 if(attr == "cls"){
4173                     b += ' class="' + o["cls"] + '"';
4174                 }else if(attr == "htmlFor"){
4175                     b += ' for="' + o["htmlFor"] + '"';
4176                 }else{
4177                     b += " " + attr + '="' + o[attr] + '"';
4178                 }
4179             }
4180         }
4181         if(emptyTags.test(o.tag)){
4182             b += "/>";
4183         }else{
4184             b += ">";
4185             var cn = o.children || o.cn;
4186             if(cn){
4187                 //http://bugs.kde.org/show_bug.cgi?id=71506
4188                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4189                     for(var i = 0, len = cn.length; i < len; i++) {
4190                         b += createHtml(cn[i], b);
4191                     }
4192                 }else{
4193                     b += createHtml(cn, b);
4194                 }
4195             }
4196             if(o.html){
4197                 b += o.html;
4198             }
4199             b += "</" + o.tag + ">";
4200         }
4201         return b;
4202     };
4203
4204     // build as dom
4205     /** @ignore */
4206     var createDom = function(o, parentNode){
4207          
4208         // defininition craeted..
4209         var ns = false;
4210         if (o.ns && o.ns != 'html') {
4211                
4212             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4213                 xmlns[o.ns] = o.xmlns;
4214                 ns = o.xmlns;
4215             }
4216             if (typeof(xmlns[o.ns]) == 'undefined') {
4217                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4218             }
4219             ns = xmlns[o.ns];
4220         }
4221         
4222         
4223         if (typeof(o) == 'string') {
4224             return parentNode.appendChild(document.createTextNode(o));
4225         }
4226         o.tag = o.tag || div;
4227         if (o.ns && Roo.isIE) {
4228             ns = false;
4229             o.tag = o.ns + ':' + o.tag;
4230             
4231         }
4232         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4233         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4234         for(var attr in o){
4235             
4236             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4237                     attr == "style" || typeof o[attr] == "function") continue;
4238                     
4239             if(attr=="cls" && Roo.isIE){
4240                 el.className = o["cls"];
4241             }else{
4242                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4243                 else { 
4244                     el[attr] = o[attr];
4245                 }
4246             }
4247         }
4248         Roo.DomHelper.applyStyles(el, o.style);
4249         var cn = o.children || o.cn;
4250         if(cn){
4251             //http://bugs.kde.org/show_bug.cgi?id=71506
4252              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4253                 for(var i = 0, len = cn.length; i < len; i++) {
4254                     createDom(cn[i], el);
4255                 }
4256             }else{
4257                 createDom(cn, el);
4258             }
4259         }
4260         if(o.html){
4261             el.innerHTML = o.html;
4262         }
4263         if(parentNode){
4264            parentNode.appendChild(el);
4265         }
4266         return el;
4267     };
4268
4269     var ieTable = function(depth, s, h, e){
4270         tempTableEl.innerHTML = [s, h, e].join('');
4271         var i = -1, el = tempTableEl;
4272         while(++i < depth){
4273             el = el.firstChild;
4274         }
4275         return el;
4276     };
4277
4278     // kill repeat to save bytes
4279     var ts = '<table>',
4280         te = '</table>',
4281         tbs = ts+'<tbody>',
4282         tbe = '</tbody>'+te,
4283         trs = tbs + '<tr>',
4284         tre = '</tr>'+tbe;
4285
4286     /**
4287      * @ignore
4288      * Nasty code for IE's broken table implementation
4289      */
4290     var insertIntoTable = function(tag, where, el, html){
4291         if(!tempTableEl){
4292             tempTableEl = document.createElement('div');
4293         }
4294         var node;
4295         var before = null;
4296         if(tag == 'td'){
4297             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4298                 return;
4299             }
4300             if(where == 'beforebegin'){
4301                 before = el;
4302                 el = el.parentNode;
4303             } else{
4304                 before = el.nextSibling;
4305                 el = el.parentNode;
4306             }
4307             node = ieTable(4, trs, html, tre);
4308         }
4309         else if(tag == 'tr'){
4310             if(where == 'beforebegin'){
4311                 before = el;
4312                 el = el.parentNode;
4313                 node = ieTable(3, tbs, html, tbe);
4314             } else if(where == 'afterend'){
4315                 before = el.nextSibling;
4316                 el = el.parentNode;
4317                 node = ieTable(3, tbs, html, tbe);
4318             } else{ // INTO a TR
4319                 if(where == 'afterbegin'){
4320                     before = el.firstChild;
4321                 }
4322                 node = ieTable(4, trs, html, tre);
4323             }
4324         } else if(tag == 'tbody'){
4325             if(where == 'beforebegin'){
4326                 before = el;
4327                 el = el.parentNode;
4328                 node = ieTable(2, ts, html, te);
4329             } else if(where == 'afterend'){
4330                 before = el.nextSibling;
4331                 el = el.parentNode;
4332                 node = ieTable(2, ts, html, te);
4333             } else{
4334                 if(where == 'afterbegin'){
4335                     before = el.firstChild;
4336                 }
4337                 node = ieTable(3, tbs, html, tbe);
4338             }
4339         } else{ // TABLE
4340             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4341                 return;
4342             }
4343             if(where == 'afterbegin'){
4344                 before = el.firstChild;
4345             }
4346             node = ieTable(2, ts, html, te);
4347         }
4348         el.insertBefore(node, before);
4349         return node;
4350     };
4351
4352     return {
4353     /** True to force the use of DOM instead of html fragments @type Boolean */
4354     useDom : false,
4355
4356     /**
4357      * Returns the markup for the passed Element(s) config
4358      * @param {Object} o The Dom object spec (and children)
4359      * @return {String}
4360      */
4361     markup : function(o){
4362         return createHtml(o);
4363     },
4364
4365     /**
4366      * Applies a style specification to an element
4367      * @param {String/HTMLElement} el The element to apply styles to
4368      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4369      * a function which returns such a specification.
4370      */
4371     applyStyles : function(el, styles){
4372         if(styles){
4373            el = Roo.fly(el);
4374            if(typeof styles == "string"){
4375                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4376                var matches;
4377                while ((matches = re.exec(styles)) != null){
4378                    el.setStyle(matches[1], matches[2]);
4379                }
4380            }else if (typeof styles == "object"){
4381                for (var style in styles){
4382                   el.setStyle(style, styles[style]);
4383                }
4384            }else if (typeof styles == "function"){
4385                 Roo.DomHelper.applyStyles(el, styles.call());
4386            }
4387         }
4388     },
4389
4390     /**
4391      * Inserts an HTML fragment into the Dom
4392      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4393      * @param {HTMLElement} el The context element
4394      * @param {String} html The HTML fragmenet
4395      * @return {HTMLElement} The new node
4396      */
4397     insertHtml : function(where, el, html){
4398         where = where.toLowerCase();
4399         if(el.insertAdjacentHTML){
4400             if(tableRe.test(el.tagName)){
4401                 var rs;
4402                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4403                     return rs;
4404                 }
4405             }
4406             switch(where){
4407                 case "beforebegin":
4408                     el.insertAdjacentHTML('BeforeBegin', html);
4409                     return el.previousSibling;
4410                 case "afterbegin":
4411                     el.insertAdjacentHTML('AfterBegin', html);
4412                     return el.firstChild;
4413                 case "beforeend":
4414                     el.insertAdjacentHTML('BeforeEnd', html);
4415                     return el.lastChild;
4416                 case "afterend":
4417                     el.insertAdjacentHTML('AfterEnd', html);
4418                     return el.nextSibling;
4419             }
4420             throw 'Illegal insertion point -> "' + where + '"';
4421         }
4422         var range = el.ownerDocument.createRange();
4423         var frag;
4424         switch(where){
4425              case "beforebegin":
4426                 range.setStartBefore(el);
4427                 frag = range.createContextualFragment(html);
4428                 el.parentNode.insertBefore(frag, el);
4429                 return el.previousSibling;
4430              case "afterbegin":
4431                 if(el.firstChild){
4432                     range.setStartBefore(el.firstChild);
4433                     frag = range.createContextualFragment(html);
4434                     el.insertBefore(frag, el.firstChild);
4435                     return el.firstChild;
4436                 }else{
4437                     el.innerHTML = html;
4438                     return el.firstChild;
4439                 }
4440             case "beforeend":
4441                 if(el.lastChild){
4442                     range.setStartAfter(el.lastChild);
4443                     frag = range.createContextualFragment(html);
4444                     el.appendChild(frag);
4445                     return el.lastChild;
4446                 }else{
4447                     el.innerHTML = html;
4448                     return el.lastChild;
4449                 }
4450             case "afterend":
4451                 range.setStartAfter(el);
4452                 frag = range.createContextualFragment(html);
4453                 el.parentNode.insertBefore(frag, el.nextSibling);
4454                 return el.nextSibling;
4455             }
4456             throw 'Illegal insertion point -> "' + where + '"';
4457     },
4458
4459     /**
4460      * Creates new Dom element(s) and inserts them before el
4461      * @param {String/HTMLElement/Element} el The context element
4462      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464      * @return {HTMLElement/Roo.Element} The new node
4465      */
4466     insertBefore : function(el, o, returnElement){
4467         return this.doInsert(el, o, returnElement, "beforeBegin");
4468     },
4469
4470     /**
4471      * Creates new Dom element(s) and inserts them after el
4472      * @param {String/HTMLElement/Element} el The context element
4473      * @param {Object} o The Dom object spec (and children)
4474      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475      * @return {HTMLElement/Roo.Element} The new node
4476      */
4477     insertAfter : function(el, o, returnElement){
4478         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4479     },
4480
4481     /**
4482      * Creates new Dom element(s) and inserts them as the first child of el
4483      * @param {String/HTMLElement/Element} el The context element
4484      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486      * @return {HTMLElement/Roo.Element} The new node
4487      */
4488     insertFirst : function(el, o, returnElement){
4489         return this.doInsert(el, o, returnElement, "afterBegin");
4490     },
4491
4492     // private
4493     doInsert : function(el, o, returnElement, pos, sibling){
4494         el = Roo.getDom(el);
4495         var newNode;
4496         if(this.useDom || o.ns){
4497             newNode = createDom(o, null);
4498             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4499         }else{
4500             var html = createHtml(o);
4501             newNode = this.insertHtml(pos, el, html);
4502         }
4503         return returnElement ? Roo.get(newNode, true) : newNode;
4504     },
4505
4506     /**
4507      * Creates new Dom element(s) and appends them to el
4508      * @param {String/HTMLElement/Element} el The context element
4509      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4510      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4511      * @return {HTMLElement/Roo.Element} The new node
4512      */
4513     append : function(el, o, returnElement){
4514         el = Roo.getDom(el);
4515         var newNode;
4516         if(this.useDom || o.ns){
4517             newNode = createDom(o, null);
4518             el.appendChild(newNode);
4519         }else{
4520             var html = createHtml(o);
4521             newNode = this.insertHtml("beforeEnd", el, html);
4522         }
4523         return returnElement ? Roo.get(newNode, true) : newNode;
4524     },
4525
4526     /**
4527      * Creates new Dom element(s) and overwrites the contents of el with them
4528      * @param {String/HTMLElement/Element} el The context element
4529      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531      * @return {HTMLElement/Roo.Element} The new node
4532      */
4533     overwrite : function(el, o, returnElement){
4534         el = Roo.getDom(el);
4535         if (o.ns) {
4536           
4537             while (el.childNodes.length) {
4538                 el.removeChild(el.firstChild);
4539             }
4540             createDom(o, el);
4541         } else {
4542             el.innerHTML = createHtml(o);   
4543         }
4544         
4545         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4546     },
4547
4548     /**
4549      * Creates a new Roo.DomHelper.Template from the Dom object spec
4550      * @param {Object} o The Dom object spec (and children)
4551      * @return {Roo.DomHelper.Template} The new template
4552      */
4553     createTemplate : function(o){
4554         var html = createHtml(o);
4555         return new Roo.Template(html);
4556     }
4557     };
4558 }();
4559 /*
4560  * Based on:
4561  * Ext JS Library 1.1.1
4562  * Copyright(c) 2006-2007, Ext JS, LLC.
4563  *
4564  * Originally Released Under LGPL - original licence link has changed is not relivant.
4565  *
4566  * Fork - LGPL
4567  * <script type="text/javascript">
4568  */
4569  
4570 /**
4571 * @class Roo.Template
4572 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4573 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4574 * Usage:
4575 <pre><code>
4576 var t = new Roo.Template({
4577     html :  '&lt;div name="{id}"&gt;' + 
4578         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4579         '&lt;/div&gt;',
4580     myformat: function (value, allValues) {
4581         return 'XX' + value;
4582     }
4583 });
4584 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4585 </code></pre>
4586 * For more information see this blog post with examples:
4587 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4588      - Create Elements using DOM, HTML fragments and Templates</a>. 
4589 * @constructor
4590 * @param {Object} cfg - Configuration object.
4591 */
4592 Roo.Template = function(cfg){
4593     // BC!
4594     if(cfg instanceof Array){
4595         cfg = cfg.join("");
4596     }else if(arguments.length > 1){
4597         cfg = Array.prototype.join.call(arguments, "");
4598     }
4599     
4600     
4601     if (typeof(cfg) == 'object') {
4602         Roo.apply(this,cfg)
4603     } else {
4604         // bc
4605         this.html = cfg;
4606     }
4607     if (this.url) {
4608         this.load();
4609     }
4610     
4611 };
4612 Roo.Template.prototype = {
4613     
4614     /**
4615      * @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..
4616      *                    it should be fixed so that template is observable...
4617      */
4618     url : false,
4619     /**
4620      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4621      */
4622     html : '',
4623     /**
4624      * Returns an HTML fragment of this template with the specified values applied.
4625      * @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'})
4626      * @return {String} The HTML fragment
4627      */
4628     applyTemplate : function(values){
4629         try {
4630            
4631             if(this.compiled){
4632                 return this.compiled(values);
4633             }
4634             var useF = this.disableFormats !== true;
4635             var fm = Roo.util.Format, tpl = this;
4636             var fn = function(m, name, format, args){
4637                 if(format && useF){
4638                     if(format.substr(0, 5) == "this."){
4639                         return tpl.call(format.substr(5), values[name], values);
4640                     }else{
4641                         if(args){
4642                             // quoted values are required for strings in compiled templates, 
4643                             // but for non compiled we need to strip them
4644                             // quoted reversed for jsmin
4645                             var re = /^\s*['"](.*)["']\s*$/;
4646                             args = args.split(',');
4647                             for(var i = 0, len = args.length; i < len; i++){
4648                                 args[i] = args[i].replace(re, "$1");
4649                             }
4650                             args = [values[name]].concat(args);
4651                         }else{
4652                             args = [values[name]];
4653                         }
4654                         return fm[format].apply(fm, args);
4655                     }
4656                 }else{
4657                     return values[name] !== undefined ? values[name] : "";
4658                 }
4659             };
4660             return this.html.replace(this.re, fn);
4661         } catch (e) {
4662             Roo.log(e);
4663             throw e;
4664         }
4665          
4666     },
4667     
4668     loading : false,
4669       
4670     load : function ()
4671     {
4672          
4673         if (this.loading) {
4674             return;
4675         }
4676         var _t = this;
4677         
4678         this.loading = true;
4679         this.compiled = false;
4680         
4681         var cx = new Roo.data.Connection();
4682         cx.request({
4683             url : this.url,
4684             method : 'GET',
4685             success : function (response) {
4686                 _t.loading = false;
4687                 _t.html = response.responseText;
4688                 _t.url = false;
4689                 _t.compile();
4690              },
4691             failure : function(response) {
4692                 Roo.log("Template failed to load from " + _t.url);
4693                 _t.loading = false;
4694             }
4695         });
4696     },
4697
4698     /**
4699      * Sets the HTML used as the template and optionally compiles it.
4700      * @param {String} html
4701      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4702      * @return {Roo.Template} this
4703      */
4704     set : function(html, compile){
4705         this.html = html;
4706         this.compiled = null;
4707         if(compile){
4708             this.compile();
4709         }
4710         return this;
4711     },
4712     
4713     /**
4714      * True to disable format functions (defaults to false)
4715      * @type Boolean
4716      */
4717     disableFormats : false,
4718     
4719     /**
4720     * The regular expression used to match template variables 
4721     * @type RegExp
4722     * @property 
4723     */
4724     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4725     
4726     /**
4727      * Compiles the template into an internal function, eliminating the RegEx overhead.
4728      * @return {Roo.Template} this
4729      */
4730     compile : function(){
4731         var fm = Roo.util.Format;
4732         var useF = this.disableFormats !== true;
4733         var sep = Roo.isGecko ? "+" : ",";
4734         var fn = function(m, name, format, args){
4735             if(format && useF){
4736                 args = args ? ',' + args : "";
4737                 if(format.substr(0, 5) != "this."){
4738                     format = "fm." + format + '(';
4739                 }else{
4740                     format = 'this.call("'+ format.substr(5) + '", ';
4741                     args = ", values";
4742                 }
4743             }else{
4744                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4745             }
4746             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4747         };
4748         var body;
4749         // branched to use + in gecko and [].join() in others
4750         if(Roo.isGecko){
4751             body = "this.compiled = function(values){ return '" +
4752                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4753                     "';};";
4754         }else{
4755             body = ["this.compiled = function(values){ return ['"];
4756             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4757             body.push("'].join('');};");
4758             body = body.join('');
4759         }
4760         /**
4761          * eval:var:values
4762          * eval:var:fm
4763          */
4764         eval(body);
4765         return this;
4766     },
4767     
4768     // private function used to call members
4769     call : function(fnName, value, allValues){
4770         return this[fnName](value, allValues);
4771     },
4772     
4773     /**
4774      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4775      * @param {String/HTMLElement/Roo.Element} el The context element
4776      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4777      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778      * @return {HTMLElement/Roo.Element} The new node or Element
4779      */
4780     insertFirst: function(el, values, returnElement){
4781         return this.doInsert('afterBegin', el, values, returnElement);
4782     },
4783
4784     /**
4785      * Applies the supplied values to the template and inserts the new node(s) before el.
4786      * @param {String/HTMLElement/Roo.Element} el The context element
4787      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4788      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789      * @return {HTMLElement/Roo.Element} The new node or Element
4790      */
4791     insertBefore: function(el, values, returnElement){
4792         return this.doInsert('beforeBegin', el, values, returnElement);
4793     },
4794
4795     /**
4796      * Applies the supplied values to the template and inserts the new node(s) after el.
4797      * @param {String/HTMLElement/Roo.Element} el The context element
4798      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4799      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4800      * @return {HTMLElement/Roo.Element} The new node or Element
4801      */
4802     insertAfter : function(el, values, returnElement){
4803         return this.doInsert('afterEnd', el, values, returnElement);
4804     },
4805     
4806     /**
4807      * Applies the supplied values to the template and appends the new node(s) to el.
4808      * @param {String/HTMLElement/Roo.Element} el The context element
4809      * @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'})
4810      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4811      * @return {HTMLElement/Roo.Element} The new node or Element
4812      */
4813     append : function(el, values, returnElement){
4814         return this.doInsert('beforeEnd', el, values, returnElement);
4815     },
4816
4817     doInsert : function(where, el, values, returnEl){
4818         el = Roo.getDom(el);
4819         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4820         return returnEl ? Roo.get(newNode, true) : newNode;
4821     },
4822
4823     /**
4824      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4825      * @param {String/HTMLElement/Roo.Element} el The context element
4826      * @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'})
4827      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4828      * @return {HTMLElement/Roo.Element} The new node or Element
4829      */
4830     overwrite : function(el, values, returnElement){
4831         el = Roo.getDom(el);
4832         el.innerHTML = this.applyTemplate(values);
4833         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4834     }
4835 };
4836 /**
4837  * Alias for {@link #applyTemplate}
4838  * @method
4839  */
4840 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4841
4842 // backwards compat
4843 Roo.DomHelper.Template = Roo.Template;
4844
4845 /**
4846  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4847  * @param {String/HTMLElement} el A DOM element or its id
4848  * @returns {Roo.Template} The created template
4849  * @static
4850  */
4851 Roo.Template.from = function(el){
4852     el = Roo.getDom(el);
4853     return new Roo.Template(el.value || el.innerHTML);
4854 };/*
4855  * Based on:
4856  * Ext JS Library 1.1.1
4857  * Copyright(c) 2006-2007, Ext JS, LLC.
4858  *
4859  * Originally Released Under LGPL - original licence link has changed is not relivant.
4860  *
4861  * Fork - LGPL
4862  * <script type="text/javascript">
4863  */
4864  
4865
4866 /*
4867  * This is code is also distributed under MIT license for use
4868  * with jQuery and prototype JavaScript libraries.
4869  */
4870 /**
4871  * @class Roo.DomQuery
4872 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).
4873 <p>
4874 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>
4875
4876 <p>
4877 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.
4878 </p>
4879 <h4>Element Selectors:</h4>
4880 <ul class="list">
4881     <li> <b>*</b> any element</li>
4882     <li> <b>E</b> an element with the tag E</li>
4883     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4884     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4885     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4886     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4887 </ul>
4888 <h4>Attribute Selectors:</h4>
4889 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4890 <ul class="list">
4891     <li> <b>E[foo]</b> has an attribute "foo"</li>
4892     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4893     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4894     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4895     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4896     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4897     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4898 </ul>
4899 <h4>Pseudo Classes:</h4>
4900 <ul class="list">
4901     <li> <b>E:first-child</b> E is the first child of its parent</li>
4902     <li> <b>E:last-child</b> E is the last child of its parent</li>
4903     <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>
4904     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4905     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4906     <li> <b>E:only-child</b> E is the only child of its parent</li>
4907     <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>
4908     <li> <b>E:first</b> the first E in the resultset</li>
4909     <li> <b>E:last</b> the last E in the resultset</li>
4910     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4911     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4912     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4913     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4914     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4915     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4916     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4917     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4918     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4919 </ul>
4920 <h4>CSS Value Selectors:</h4>
4921 <ul class="list">
4922     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4923     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4924     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4925     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4926     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4927     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4928 </ul>
4929  * @singleton
4930  */
4931 Roo.DomQuery = function(){
4932     var cache = {}, simpleCache = {}, valueCache = {};
4933     var nonSpace = /\S/;
4934     var trimRe = /^\s+|\s+$/g;
4935     var tplRe = /\{(\d+)\}/g;
4936     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4937     var tagTokenRe = /^(#)?([\w-\*]+)/;
4938     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4939
4940     function child(p, index){
4941         var i = 0;
4942         var n = p.firstChild;
4943         while(n){
4944             if(n.nodeType == 1){
4945                if(++i == index){
4946                    return n;
4947                }
4948             }
4949             n = n.nextSibling;
4950         }
4951         return null;
4952     };
4953
4954     function next(n){
4955         while((n = n.nextSibling) && n.nodeType != 1);
4956         return n;
4957     };
4958
4959     function prev(n){
4960         while((n = n.previousSibling) && n.nodeType != 1);
4961         return n;
4962     };
4963
4964     function children(d){
4965         var n = d.firstChild, ni = -1;
4966             while(n){
4967                 var nx = n.nextSibling;
4968                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4969                     d.removeChild(n);
4970                 }else{
4971                     n.nodeIndex = ++ni;
4972                 }
4973                 n = nx;
4974             }
4975             return this;
4976         };
4977
4978     function byClassName(c, a, v){
4979         if(!v){
4980             return c;
4981         }
4982         var r = [], ri = -1, cn;
4983         for(var i = 0, ci; ci = c[i]; i++){
4984             if((' '+ci.className+' ').indexOf(v) != -1){
4985                 r[++ri] = ci;
4986             }
4987         }
4988         return r;
4989     };
4990
4991     function attrValue(n, attr){
4992         if(!n.tagName && typeof n.length != "undefined"){
4993             n = n[0];
4994         }
4995         if(!n){
4996             return null;
4997         }
4998         if(attr == "for"){
4999             return n.htmlFor;
5000         }
5001         if(attr == "class" || attr == "className"){
5002             return n.className;
5003         }
5004         return n.getAttribute(attr) || n[attr];
5005
5006     };
5007
5008     function getNodes(ns, mode, tagName){
5009         var result = [], ri = -1, cs;
5010         if(!ns){
5011             return result;
5012         }
5013         tagName = tagName || "*";
5014         if(typeof ns.getElementsByTagName != "undefined"){
5015             ns = [ns];
5016         }
5017         if(!mode){
5018             for(var i = 0, ni; ni = ns[i]; i++){
5019                 cs = ni.getElementsByTagName(tagName);
5020                 for(var j = 0, ci; ci = cs[j]; j++){
5021                     result[++ri] = ci;
5022                 }
5023             }
5024         }else if(mode == "/" || mode == ">"){
5025             var utag = tagName.toUpperCase();
5026             for(var i = 0, ni, cn; ni = ns[i]; i++){
5027                 cn = ni.children || ni.childNodes;
5028                 for(var j = 0, cj; cj = cn[j]; j++){
5029                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5030                         result[++ri] = cj;
5031                     }
5032                 }
5033             }
5034         }else if(mode == "+"){
5035             var utag = tagName.toUpperCase();
5036             for(var i = 0, n; n = ns[i]; i++){
5037                 while((n = n.nextSibling) && n.nodeType != 1);
5038                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5039                     result[++ri] = n;
5040                 }
5041             }
5042         }else if(mode == "~"){
5043             for(var i = 0, n; n = ns[i]; i++){
5044                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5045                 if(n){
5046                     result[++ri] = n;
5047                 }
5048             }
5049         }
5050         return result;
5051     };
5052
5053     function concat(a, b){
5054         if(b.slice){
5055             return a.concat(b);
5056         }
5057         for(var i = 0, l = b.length; i < l; i++){
5058             a[a.length] = b[i];
5059         }
5060         return a;
5061     }
5062
5063     function byTag(cs, tagName){
5064         if(cs.tagName || cs == document){
5065             cs = [cs];
5066         }
5067         if(!tagName){
5068             return cs;
5069         }
5070         var r = [], ri = -1;
5071         tagName = tagName.toLowerCase();
5072         for(var i = 0, ci; ci = cs[i]; i++){
5073             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5074                 r[++ri] = ci;
5075             }
5076         }
5077         return r;
5078     };
5079
5080     function byId(cs, attr, id){
5081         if(cs.tagName || cs == document){
5082             cs = [cs];
5083         }
5084         if(!id){
5085             return cs;
5086         }
5087         var r = [], ri = -1;
5088         for(var i = 0,ci; ci = cs[i]; i++){
5089             if(ci && ci.id == id){
5090                 r[++ri] = ci;
5091                 return r;
5092             }
5093         }
5094         return r;
5095     };
5096
5097     function byAttribute(cs, attr, value, op, custom){
5098         var r = [], ri = -1, st = custom=="{";
5099         var f = Roo.DomQuery.operators[op];
5100         for(var i = 0, ci; ci = cs[i]; i++){
5101             var a;
5102             if(st){
5103                 a = Roo.DomQuery.getStyle(ci, attr);
5104             }
5105             else if(attr == "class" || attr == "className"){
5106                 a = ci.className;
5107             }else if(attr == "for"){
5108                 a = ci.htmlFor;
5109             }else if(attr == "href"){
5110                 a = ci.getAttribute("href", 2);
5111             }else{
5112                 a = ci.getAttribute(attr);
5113             }
5114             if((f && f(a, value)) || (!f && a)){
5115                 r[++ri] = ci;
5116             }
5117         }
5118         return r;
5119     };
5120
5121     function byPseudo(cs, name, value){
5122         return Roo.DomQuery.pseudos[name](cs, value);
5123     };
5124
5125     // This is for IE MSXML which does not support expandos.
5126     // IE runs the same speed using setAttribute, however FF slows way down
5127     // and Safari completely fails so they need to continue to use expandos.
5128     var isIE = window.ActiveXObject ? true : false;
5129
5130     // this eval is stop the compressor from
5131     // renaming the variable to something shorter
5132     
5133     /** eval:var:batch */
5134     var batch = 30803; 
5135
5136     var key = 30803;
5137
5138     function nodupIEXml(cs){
5139         var d = ++key;
5140         cs[0].setAttribute("_nodup", d);
5141         var r = [cs[0]];
5142         for(var i = 1, len = cs.length; i < len; i++){
5143             var c = cs[i];
5144             if(!c.getAttribute("_nodup") != d){
5145                 c.setAttribute("_nodup", d);
5146                 r[r.length] = c;
5147             }
5148         }
5149         for(var i = 0, len = cs.length; i < len; i++){
5150             cs[i].removeAttribute("_nodup");
5151         }
5152         return r;
5153     }
5154
5155     function nodup(cs){
5156         if(!cs){
5157             return [];
5158         }
5159         var len = cs.length, c, i, r = cs, cj, ri = -1;
5160         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5161             return cs;
5162         }
5163         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5164             return nodupIEXml(cs);
5165         }
5166         var d = ++key;
5167         cs[0]._nodup = d;
5168         for(i = 1; c = cs[i]; i++){
5169             if(c._nodup != d){
5170                 c._nodup = d;
5171             }else{
5172                 r = [];
5173                 for(var j = 0; j < i; j++){
5174                     r[++ri] = cs[j];
5175                 }
5176                 for(j = i+1; cj = cs[j]; j++){
5177                     if(cj._nodup != d){
5178                         cj._nodup = d;
5179                         r[++ri] = cj;
5180                     }
5181                 }
5182                 return r;
5183             }
5184         }
5185         return r;
5186     }
5187
5188     function quickDiffIEXml(c1, c2){
5189         var d = ++key;
5190         for(var i = 0, len = c1.length; i < len; i++){
5191             c1[i].setAttribute("_qdiff", d);
5192         }
5193         var r = [];
5194         for(var i = 0, len = c2.length; i < len; i++){
5195             if(c2[i].getAttribute("_qdiff") != d){
5196                 r[r.length] = c2[i];
5197             }
5198         }
5199         for(var i = 0, len = c1.length; i < len; i++){
5200            c1[i].removeAttribute("_qdiff");
5201         }
5202         return r;
5203     }
5204
5205     function quickDiff(c1, c2){
5206         var len1 = c1.length;
5207         if(!len1){
5208             return c2;
5209         }
5210         if(isIE && c1[0].selectSingleNode){
5211             return quickDiffIEXml(c1, c2);
5212         }
5213         var d = ++key;
5214         for(var i = 0; i < len1; i++){
5215             c1[i]._qdiff = d;
5216         }
5217         var r = [];
5218         for(var i = 0, len = c2.length; i < len; i++){
5219             if(c2[i]._qdiff != d){
5220                 r[r.length] = c2[i];
5221             }
5222         }
5223         return r;
5224     }
5225
5226     function quickId(ns, mode, root, id){
5227         if(ns == root){
5228            var d = root.ownerDocument || root;
5229            return d.getElementById(id);
5230         }
5231         ns = getNodes(ns, mode, "*");
5232         return byId(ns, null, id);
5233     }
5234
5235     return {
5236         getStyle : function(el, name){
5237             return Roo.fly(el).getStyle(name);
5238         },
5239         /**
5240          * Compiles a selector/xpath query into a reusable function. The returned function
5241          * takes one parameter "root" (optional), which is the context node from where the query should start.
5242          * @param {String} selector The selector/xpath query
5243          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5244          * @return {Function}
5245          */
5246         compile : function(path, type){
5247             type = type || "select";
5248             
5249             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5250             var q = path, mode, lq;
5251             var tk = Roo.DomQuery.matchers;
5252             var tklen = tk.length;
5253             var mm;
5254
5255             // accept leading mode switch
5256             var lmode = q.match(modeRe);
5257             if(lmode && lmode[1]){
5258                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5259                 q = q.replace(lmode[1], "");
5260             }
5261             // strip leading slashes
5262             while(path.substr(0, 1)=="/"){
5263                 path = path.substr(1);
5264             }
5265
5266             while(q && lq != q){
5267                 lq = q;
5268                 var tm = q.match(tagTokenRe);
5269                 if(type == "select"){
5270                     if(tm){
5271                         if(tm[1] == "#"){
5272                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5273                         }else{
5274                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5275                         }
5276                         q = q.replace(tm[0], "");
5277                     }else if(q.substr(0, 1) != '@'){
5278                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5279                     }
5280                 }else{
5281                     if(tm){
5282                         if(tm[1] == "#"){
5283                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5284                         }else{
5285                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5286                         }
5287                         q = q.replace(tm[0], "");
5288                     }
5289                 }
5290                 while(!(mm = q.match(modeRe))){
5291                     var matched = false;
5292                     for(var j = 0; j < tklen; j++){
5293                         var t = tk[j];
5294                         var m = q.match(t.re);
5295                         if(m){
5296                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5297                                                     return m[i];
5298                                                 });
5299                             q = q.replace(m[0], "");
5300                             matched = true;
5301                             break;
5302                         }
5303                     }
5304                     // prevent infinite loop on bad selector
5305                     if(!matched){
5306                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5307                     }
5308                 }
5309                 if(mm[1]){
5310                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5311                     q = q.replace(mm[1], "");
5312                 }
5313             }
5314             fn[fn.length] = "return nodup(n);\n}";
5315             
5316              /** 
5317               * list of variables that need from compression as they are used by eval.
5318              *  eval:var:batch 
5319              *  eval:var:nodup
5320              *  eval:var:byTag
5321              *  eval:var:ById
5322              *  eval:var:getNodes
5323              *  eval:var:quickId
5324              *  eval:var:mode
5325              *  eval:var:root
5326              *  eval:var:n
5327              *  eval:var:byClassName
5328              *  eval:var:byPseudo
5329              *  eval:var:byAttribute
5330              *  eval:var:attrValue
5331              * 
5332              **/ 
5333             eval(fn.join(""));
5334             return f;
5335         },
5336
5337         /**
5338          * Selects a group of elements.
5339          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5340          * @param {Node} root (optional) The start of the query (defaults to document).
5341          * @return {Array}
5342          */
5343         select : function(path, root, type){
5344             if(!root || root == document){
5345                 root = document;
5346             }
5347             if(typeof root == "string"){
5348                 root = document.getElementById(root);
5349             }
5350             var paths = path.split(",");
5351             var results = [];
5352             for(var i = 0, len = paths.length; i < len; i++){
5353                 var p = paths[i].replace(trimRe, "");
5354                 if(!cache[p]){
5355                     cache[p] = Roo.DomQuery.compile(p);
5356                     if(!cache[p]){
5357                         throw p + " is not a valid selector";
5358                     }
5359                 }
5360                 var result = cache[p](root);
5361                 if(result && result != document){
5362                     results = results.concat(result);
5363                 }
5364             }
5365             if(paths.length > 1){
5366                 return nodup(results);
5367             }
5368             return results;
5369         },
5370
5371         /**
5372          * Selects a single element.
5373          * @param {String} selector The selector/xpath query
5374          * @param {Node} root (optional) The start of the query (defaults to document).
5375          * @return {Element}
5376          */
5377         selectNode : function(path, root){
5378             return Roo.DomQuery.select(path, root)[0];
5379         },
5380
5381         /**
5382          * Selects the value of a node, optionally replacing null with the defaultValue.
5383          * @param {String} selector The selector/xpath query
5384          * @param {Node} root (optional) The start of the query (defaults to document).
5385          * @param {String} defaultValue
5386          */
5387         selectValue : function(path, root, defaultValue){
5388             path = path.replace(trimRe, "");
5389             if(!valueCache[path]){
5390                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5391             }
5392             var n = valueCache[path](root);
5393             n = n[0] ? n[0] : n;
5394             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5395             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5396         },
5397
5398         /**
5399          * Selects the value of a node, parsing integers and floats.
5400          * @param {String} selector The selector/xpath query
5401          * @param {Node} root (optional) The start of the query (defaults to document).
5402          * @param {Number} defaultValue
5403          * @return {Number}
5404          */
5405         selectNumber : function(path, root, defaultValue){
5406             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5407             return parseFloat(v);
5408         },
5409
5410         /**
5411          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5412          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5413          * @param {String} selector The simple selector to test
5414          * @return {Boolean}
5415          */
5416         is : function(el, ss){
5417             if(typeof el == "string"){
5418                 el = document.getElementById(el);
5419             }
5420             var isArray = (el instanceof Array);
5421             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5422             return isArray ? (result.length == el.length) : (result.length > 0);
5423         },
5424
5425         /**
5426          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5427          * @param {Array} el An array of elements to filter
5428          * @param {String} selector The simple selector to test
5429          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5430          * the selector instead of the ones that match
5431          * @return {Array}
5432          */
5433         filter : function(els, ss, nonMatches){
5434             ss = ss.replace(trimRe, "");
5435             if(!simpleCache[ss]){
5436                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5437             }
5438             var result = simpleCache[ss](els);
5439             return nonMatches ? quickDiff(result, els) : result;
5440         },
5441
5442         /**
5443          * Collection of matching regular expressions and code snippets.
5444          */
5445         matchers : [{
5446                 re: /^\.([\w-]+)/,
5447                 select: 'n = byClassName(n, null, " {1} ");'
5448             }, {
5449                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5450                 select: 'n = byPseudo(n, "{1}", "{2}");'
5451             },{
5452                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5453                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5454             }, {
5455                 re: /^#([\w-]+)/,
5456                 select: 'n = byId(n, null, "{1}");'
5457             },{
5458                 re: /^@([\w-]+)/,
5459                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5460             }
5461         ],
5462
5463         /**
5464          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5465          * 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;.
5466          */
5467         operators : {
5468             "=" : function(a, v){
5469                 return a == v;
5470             },
5471             "!=" : function(a, v){
5472                 return a != v;
5473             },
5474             "^=" : function(a, v){
5475                 return a && a.substr(0, v.length) == v;
5476             },
5477             "$=" : function(a, v){
5478                 return a && a.substr(a.length-v.length) == v;
5479             },
5480             "*=" : function(a, v){
5481                 return a && a.indexOf(v) !== -1;
5482             },
5483             "%=" : function(a, v){
5484                 return (a % v) == 0;
5485             },
5486             "|=" : function(a, v){
5487                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5488             },
5489             "~=" : function(a, v){
5490                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5491             }
5492         },
5493
5494         /**
5495          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5496          * and the argument (if any) supplied in the selector.
5497          */
5498         pseudos : {
5499             "first-child" : function(c){
5500                 var r = [], ri = -1, n;
5501                 for(var i = 0, ci; ci = n = c[i]; i++){
5502                     while((n = n.previousSibling) && n.nodeType != 1);
5503                     if(!n){
5504                         r[++ri] = ci;
5505                     }
5506                 }
5507                 return r;
5508             },
5509
5510             "last-child" : function(c){
5511                 var r = [], ri = -1, n;
5512                 for(var i = 0, ci; ci = n = c[i]; i++){
5513                     while((n = n.nextSibling) && n.nodeType != 1);
5514                     if(!n){
5515                         r[++ri] = ci;
5516                     }
5517                 }
5518                 return r;
5519             },
5520
5521             "nth-child" : function(c, a) {
5522                 var r = [], ri = -1;
5523                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5524                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5525                 for(var i = 0, n; n = c[i]; i++){
5526                     var pn = n.parentNode;
5527                     if (batch != pn._batch) {
5528                         var j = 0;
5529                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5530                             if(cn.nodeType == 1){
5531                                cn.nodeIndex = ++j;
5532                             }
5533                         }
5534                         pn._batch = batch;
5535                     }
5536                     if (f == 1) {
5537                         if (l == 0 || n.nodeIndex == l){
5538                             r[++ri] = n;
5539                         }
5540                     } else if ((n.nodeIndex + l) % f == 0){
5541                         r[++ri] = n;
5542                     }
5543                 }
5544
5545                 return r;
5546             },
5547
5548             "only-child" : function(c){
5549                 var r = [], ri = -1;;
5550                 for(var i = 0, ci; ci = c[i]; i++){
5551                     if(!prev(ci) && !next(ci)){
5552                         r[++ri] = ci;
5553                     }
5554                 }
5555                 return r;
5556             },
5557
5558             "empty" : function(c){
5559                 var r = [], ri = -1;
5560                 for(var i = 0, ci; ci = c[i]; i++){
5561                     var cns = ci.childNodes, j = 0, cn, empty = true;
5562                     while(cn = cns[j]){
5563                         ++j;
5564                         if(cn.nodeType == 1 || cn.nodeType == 3){
5565                             empty = false;
5566                             break;
5567                         }
5568                     }
5569                     if(empty){
5570                         r[++ri] = ci;
5571                     }
5572                 }
5573                 return r;
5574             },
5575
5576             "contains" : function(c, v){
5577                 var r = [], ri = -1;
5578                 for(var i = 0, ci; ci = c[i]; i++){
5579                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5580                         r[++ri] = ci;
5581                     }
5582                 }
5583                 return r;
5584             },
5585
5586             "nodeValue" : function(c, v){
5587                 var r = [], ri = -1;
5588                 for(var i = 0, ci; ci = c[i]; i++){
5589                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5590                         r[++ri] = ci;
5591                     }
5592                 }
5593                 return r;
5594             },
5595
5596             "checked" : function(c){
5597                 var r = [], ri = -1;
5598                 for(var i = 0, ci; ci = c[i]; i++){
5599                     if(ci.checked == true){
5600                         r[++ri] = ci;
5601                     }
5602                 }
5603                 return r;
5604             },
5605
5606             "not" : function(c, ss){
5607                 return Roo.DomQuery.filter(c, ss, true);
5608             },
5609
5610             "odd" : function(c){
5611                 return this["nth-child"](c, "odd");
5612             },
5613
5614             "even" : function(c){
5615                 return this["nth-child"](c, "even");
5616             },
5617
5618             "nth" : function(c, a){
5619                 return c[a-1] || [];
5620             },
5621
5622             "first" : function(c){
5623                 return c[0] || [];
5624             },
5625
5626             "last" : function(c){
5627                 return c[c.length-1] || [];
5628             },
5629
5630             "has" : function(c, ss){
5631                 var s = Roo.DomQuery.select;
5632                 var r = [], ri = -1;
5633                 for(var i = 0, ci; ci = c[i]; i++){
5634                     if(s(ss, ci).length > 0){
5635                         r[++ri] = ci;
5636                     }
5637                 }
5638                 return r;
5639             },
5640
5641             "next" : 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 = next(ci);
5646                     if(n && is(n, ss)){
5647                         r[++ri] = ci;
5648                     }
5649                 }
5650                 return r;
5651             },
5652
5653             "prev" : function(c, ss){
5654                 var is = Roo.DomQuery.is;
5655                 var r = [], ri = -1;
5656                 for(var i = 0, ci; ci = c[i]; i++){
5657                     var n = prev(ci);
5658                     if(n && is(n, ss)){
5659                         r[++ri] = ci;
5660                     }
5661                 }
5662                 return r;
5663             }
5664         }
5665     };
5666 }();
5667
5668 /**
5669  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5670  * @param {String} path The selector/xpath query
5671  * @param {Node} root (optional) The start of the query (defaults to document).
5672  * @return {Array}
5673  * @member Roo
5674  * @method query
5675  */
5676 Roo.query = Roo.DomQuery.select;
5677 /*
5678  * Based on:
5679  * Ext JS Library 1.1.1
5680  * Copyright(c) 2006-2007, Ext JS, LLC.
5681  *
5682  * Originally Released Under LGPL - original licence link has changed is not relivant.
5683  *
5684  * Fork - LGPL
5685  * <script type="text/javascript">
5686  */
5687
5688 /**
5689  * @class Roo.util.Observable
5690  * Base class that provides a common interface for publishing events. Subclasses are expected to
5691  * to have a property "events" with all the events defined.<br>
5692  * For example:
5693  * <pre><code>
5694  Employee = function(name){
5695     this.name = name;
5696     this.addEvents({
5697         "fired" : true,
5698         "quit" : true
5699     });
5700  }
5701  Roo.extend(Employee, Roo.util.Observable);
5702 </code></pre>
5703  * @param {Object} config properties to use (incuding events / listeners)
5704  */
5705
5706 Roo.util.Observable = function(cfg){
5707     
5708     cfg = cfg|| {};
5709     this.addEvents(cfg.events || {});
5710     if (cfg.events) {
5711         delete cfg.events; // make sure
5712     }
5713      
5714     Roo.apply(this, cfg);
5715     
5716     if(this.listeners){
5717         this.on(this.listeners);
5718         delete this.listeners;
5719     }
5720 };
5721 Roo.util.Observable.prototype = {
5722     /** 
5723  * @cfg {Object} listeners  list of events and functions to call for this object, 
5724  * For example :
5725  * <pre><code>
5726     listeners :  { 
5727        'click' : function(e) {
5728            ..... 
5729         } ,
5730         .... 
5731     } 
5732   </code></pre>
5733  */
5734     
5735     
5736     /**
5737      * Fires the specified event with the passed parameters (minus the event name).
5738      * @param {String} eventName
5739      * @param {Object...} args Variable number of parameters are passed to handlers
5740      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5741      */
5742     fireEvent : function(){
5743         var ce = this.events[arguments[0].toLowerCase()];
5744         if(typeof ce == "object"){
5745             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5746         }else{
5747             return true;
5748         }
5749     },
5750
5751     // private
5752     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5753
5754     /**
5755      * Appends an event handler to this component
5756      * @param {String}   eventName The type of event to listen for
5757      * @param {Function} handler The method the event invokes
5758      * @param {Object}   scope (optional) The scope in which to execute the handler
5759      * function. The handler function's "this" context.
5760      * @param {Object}   options (optional) An object containing handler configuration
5761      * properties. This may contain any of the following properties:<ul>
5762      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5763      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5764      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5765      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5766      * by the specified number of milliseconds. If the event fires again within that time, the original
5767      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5768      * </ul><br>
5769      * <p>
5770      * <b>Combining Options</b><br>
5771      * Using the options argument, it is possible to combine different types of listeners:<br>
5772      * <br>
5773      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5774                 <pre><code>
5775                 el.on('click', this.onClick, this, {
5776                         single: true,
5777                 delay: 100,
5778                 forumId: 4
5779                 });
5780                 </code></pre>
5781      * <p>
5782      * <b>Attaching multiple handlers in 1 call</b><br>
5783      * The method also allows for a single argument to be passed which is a config object containing properties
5784      * which specify multiple handlers.
5785      * <pre><code>
5786                 el.on({
5787                         'click': {
5788                         fn: this.onClick,
5789                         scope: this,
5790                         delay: 100
5791                 }, 
5792                 'mouseover': {
5793                         fn: this.onMouseOver,
5794                         scope: this
5795                 },
5796                 'mouseout': {
5797                         fn: this.onMouseOut,
5798                         scope: this
5799                 }
5800                 });
5801                 </code></pre>
5802      * <p>
5803      * Or a shorthand syntax which passes the same scope object to all handlers:
5804         <pre><code>
5805                 el.on({
5806                         'click': this.onClick,
5807                 'mouseover': this.onMouseOver,
5808                 'mouseout': this.onMouseOut,
5809                 scope: this
5810                 });
5811                 </code></pre>
5812      */
5813     addListener : function(eventName, fn, scope, o){
5814         if(typeof eventName == "object"){
5815             o = eventName;
5816             for(var e in o){
5817                 if(this.filterOptRe.test(e)){
5818                     continue;
5819                 }
5820                 if(typeof o[e] == "function"){
5821                     // shared options
5822                     this.addListener(e, o[e], o.scope,  o);
5823                 }else{
5824                     // individual options
5825                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5826                 }
5827             }
5828             return;
5829         }
5830         o = (!o || typeof o == "boolean") ? {} : o;
5831         eventName = eventName.toLowerCase();
5832         var ce = this.events[eventName] || true;
5833         if(typeof ce == "boolean"){
5834             ce = new Roo.util.Event(this, eventName);
5835             this.events[eventName] = ce;
5836         }
5837         ce.addListener(fn, scope, o);
5838     },
5839
5840     /**
5841      * Removes a listener
5842      * @param {String}   eventName     The type of event to listen for
5843      * @param {Function} handler        The handler to remove
5844      * @param {Object}   scope  (optional) The scope (this object) for the handler
5845      */
5846     removeListener : function(eventName, fn, scope){
5847         var ce = this.events[eventName.toLowerCase()];
5848         if(typeof ce == "object"){
5849             ce.removeListener(fn, scope);
5850         }
5851     },
5852
5853     /**
5854      * Removes all listeners for this object
5855      */
5856     purgeListeners : function(){
5857         for(var evt in this.events){
5858             if(typeof this.events[evt] == "object"){
5859                  this.events[evt].clearListeners();
5860             }
5861         }
5862     },
5863
5864     relayEvents : function(o, events){
5865         var createHandler = function(ename){
5866             return function(){
5867                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5868             };
5869         };
5870         for(var i = 0, len = events.length; i < len; i++){
5871             var ename = events[i];
5872             if(!this.events[ename]){ this.events[ename] = true; };
5873             o.on(ename, createHandler(ename), this);
5874         }
5875     },
5876
5877     /**
5878      * Used to define events on this Observable
5879      * @param {Object} object The object with the events defined
5880      */
5881     addEvents : function(o){
5882         if(!this.events){
5883             this.events = {};
5884         }
5885         Roo.applyIf(this.events, o);
5886     },
5887
5888     /**
5889      * Checks to see if this object has any listeners for a specified event
5890      * @param {String} eventName The name of the event to check for
5891      * @return {Boolean} True if the event is being listened for, else false
5892      */
5893     hasListener : function(eventName){
5894         var e = this.events[eventName];
5895         return typeof e == "object" && e.listeners.length > 0;
5896     }
5897 };
5898 /**
5899  * Appends an event handler to this element (shorthand for addListener)
5900  * @param {String}   eventName     The type of event to listen for
5901  * @param {Function} handler        The method the event invokes
5902  * @param {Object}   scope (optional) The scope in which to execute the handler
5903  * function. The handler function's "this" context.
5904  * @param {Object}   options  (optional)
5905  * @method
5906  */
5907 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5908 /**
5909  * Removes a listener (shorthand for removeListener)
5910  * @param {String}   eventName     The type of event to listen for
5911  * @param {Function} handler        The handler to remove
5912  * @param {Object}   scope  (optional) The scope (this object) for the handler
5913  * @method
5914  */
5915 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5916
5917 /**
5918  * Starts capture on the specified Observable. All events will be passed
5919  * to the supplied function with the event name + standard signature of the event
5920  * <b>before</b> the event is fired. If the supplied function returns false,
5921  * the event will not fire.
5922  * @param {Observable} o The Observable to capture
5923  * @param {Function} fn The function to call
5924  * @param {Object} scope (optional) The scope (this object) for the fn
5925  * @static
5926  */
5927 Roo.util.Observable.capture = function(o, fn, scope){
5928     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5929 };
5930
5931 /**
5932  * Removes <b>all</b> added captures from the Observable.
5933  * @param {Observable} o The Observable to release
5934  * @static
5935  */
5936 Roo.util.Observable.releaseCapture = function(o){
5937     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5938 };
5939
5940 (function(){
5941
5942     var createBuffered = function(h, o, scope){
5943         var task = new Roo.util.DelayedTask();
5944         return function(){
5945             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5946         };
5947     };
5948
5949     var createSingle = function(h, e, fn, scope){
5950         return function(){
5951             e.removeListener(fn, scope);
5952             return h.apply(scope, arguments);
5953         };
5954     };
5955
5956     var createDelayed = function(h, o, scope){
5957         return function(){
5958             var args = Array.prototype.slice.call(arguments, 0);
5959             setTimeout(function(){
5960                 h.apply(scope, args);
5961             }, o.delay || 10);
5962         };
5963     };
5964
5965     Roo.util.Event = function(obj, name){
5966         this.name = name;
5967         this.obj = obj;
5968         this.listeners = [];
5969     };
5970
5971     Roo.util.Event.prototype = {
5972         addListener : function(fn, scope, options){
5973             var o = options || {};
5974             scope = scope || this.obj;
5975             if(!this.isListening(fn, scope)){
5976                 var l = {fn: fn, scope: scope, options: o};
5977                 var h = fn;
5978                 if(o.delay){
5979                     h = createDelayed(h, o, scope);
5980                 }
5981                 if(o.single){
5982                     h = createSingle(h, this, fn, scope);
5983                 }
5984                 if(o.buffer){
5985                     h = createBuffered(h, o, scope);
5986                 }
5987                 l.fireFn = h;
5988                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5989                     this.listeners.push(l);
5990                 }else{
5991                     this.listeners = this.listeners.slice(0);
5992                     this.listeners.push(l);
5993                 }
5994             }
5995         },
5996
5997         findListener : function(fn, scope){
5998             scope = scope || this.obj;
5999             var ls = this.listeners;
6000             for(var i = 0, len = ls.length; i < len; i++){
6001                 var l = ls[i];
6002                 if(l.fn == fn && l.scope == scope){
6003                     return i;
6004                 }
6005             }
6006             return -1;
6007         },
6008
6009         isListening : function(fn, scope){
6010             return this.findListener(fn, scope) != -1;
6011         },
6012
6013         removeListener : function(fn, scope){
6014             var index;
6015             if((index = this.findListener(fn, scope)) != -1){
6016                 if(!this.firing){
6017                     this.listeners.splice(index, 1);
6018                 }else{
6019                     this.listeners = this.listeners.slice(0);
6020                     this.listeners.splice(index, 1);
6021                 }
6022                 return true;
6023             }
6024             return false;
6025         },
6026
6027         clearListeners : function(){
6028             this.listeners = [];
6029         },
6030
6031         fire : function(){
6032             var ls = this.listeners, scope, len = ls.length;
6033             if(len > 0){
6034                 this.firing = true;
6035                 var args = Array.prototype.slice.call(arguments, 0);
6036                 for(var i = 0; i < len; i++){
6037                     var l = ls[i];
6038                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6039                         this.firing = false;
6040                         return false;
6041                     }
6042                 }
6043                 this.firing = false;
6044             }
6045             return true;
6046         }
6047     };
6048 })();/*
6049  * Based on:
6050  * Ext JS Library 1.1.1
6051  * Copyright(c) 2006-2007, Ext JS, LLC.
6052  *
6053  * Originally Released Under LGPL - original licence link has changed is not relivant.
6054  *
6055  * Fork - LGPL
6056  * <script type="text/javascript">
6057  */
6058
6059 /**
6060  * @class Roo.EventManager
6061  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6062  * several useful events directly.
6063  * See {@link Roo.EventObject} for more details on normalized event objects.
6064  * @singleton
6065  */
6066 Roo.EventManager = function(){
6067     var docReadyEvent, docReadyProcId, docReadyState = false;
6068     var resizeEvent, resizeTask, textEvent, textSize;
6069     var E = Roo.lib.Event;
6070     var D = Roo.lib.Dom;
6071
6072     
6073     
6074
6075     var fireDocReady = function(){
6076         if(!docReadyState){
6077             docReadyState = true;
6078             Roo.isReady = true;
6079             if(docReadyProcId){
6080                 clearInterval(docReadyProcId);
6081             }
6082             if(Roo.isGecko || Roo.isOpera) {
6083                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6084             }
6085             if(Roo.isIE){
6086                 var defer = document.getElementById("ie-deferred-loader");
6087                 if(defer){
6088                     defer.onreadystatechange = null;
6089                     defer.parentNode.removeChild(defer);
6090                 }
6091             }
6092             if(docReadyEvent){
6093                 docReadyEvent.fire();
6094                 docReadyEvent.clearListeners();
6095             }
6096         }
6097     };
6098     
6099     var initDocReady = function(){
6100         docReadyEvent = new Roo.util.Event();
6101         if(Roo.isGecko || Roo.isOpera) {
6102             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6103         }else if(Roo.isIE){
6104             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6105             var defer = document.getElementById("ie-deferred-loader");
6106             defer.onreadystatechange = function(){
6107                 if(this.readyState == "complete"){
6108                     fireDocReady();
6109                 }
6110             };
6111         }else if(Roo.isSafari){ 
6112             docReadyProcId = setInterval(function(){
6113                 var rs = document.readyState;
6114                 if(rs == "complete") {
6115                     fireDocReady();     
6116                  }
6117             }, 10);
6118         }
6119         // no matter what, make sure it fires on load
6120         E.on(window, "load", fireDocReady);
6121     };
6122
6123     var createBuffered = function(h, o){
6124         var task = new Roo.util.DelayedTask(h);
6125         return function(e){
6126             // create new event object impl so new events don't wipe out properties
6127             e = new Roo.EventObjectImpl(e);
6128             task.delay(o.buffer, h, null, [e]);
6129         };
6130     };
6131
6132     var createSingle = function(h, el, ename, fn){
6133         return function(e){
6134             Roo.EventManager.removeListener(el, ename, fn);
6135             h(e);
6136         };
6137     };
6138
6139     var createDelayed = function(h, o){
6140         return function(e){
6141             // create new event object impl so new events don't wipe out properties
6142             e = new Roo.EventObjectImpl(e);
6143             setTimeout(function(){
6144                 h(e);
6145             }, o.delay || 10);
6146         };
6147     };
6148     var transitionEndVal = false;
6149     
6150     var transitionEnd = function()
6151     {
6152         if (transitionEndVal) {
6153             return transitionEndVal;
6154         }
6155         var el = document.createElement('div');
6156
6157         var transEndEventNames = {
6158             WebkitTransition : 'webkitTransitionEnd',
6159             MozTransition    : 'transitionend',
6160             OTransition      : 'oTransitionEnd otransitionend',
6161             transition       : 'transitionend'
6162         };
6163     
6164         for (var name in transEndEventNames) {
6165             if (el.style[name] !== undefined) {
6166                 transitionEndVal = transEndEventNames[name];
6167                 return  transitionEndVal ;
6168             }
6169         }
6170     }
6171     
6172
6173     var listen = function(element, ename, opt, fn, scope){
6174         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6175         fn = fn || o.fn; scope = scope || o.scope;
6176         var el = Roo.getDom(element);
6177         
6178         
6179         if(!el){
6180             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6181         }
6182         
6183         if (ename == 'transitionend') {
6184             ename = transitionEnd();
6185         }
6186         var h = function(e){
6187             e = Roo.EventObject.setEvent(e);
6188             var t;
6189             if(o.delegate){
6190                 t = e.getTarget(o.delegate, el);
6191                 if(!t){
6192                     return;
6193                 }
6194             }else{
6195                 t = e.target;
6196             }
6197             if(o.stopEvent === true){
6198                 e.stopEvent();
6199             }
6200             if(o.preventDefault === true){
6201                e.preventDefault();
6202             }
6203             if(o.stopPropagation === true){
6204                 e.stopPropagation();
6205             }
6206
6207             if(o.normalized === false){
6208                 e = e.browserEvent;
6209             }
6210
6211             fn.call(scope || el, e, t, o);
6212         };
6213         if(o.delay){
6214             h = createDelayed(h, o);
6215         }
6216         if(o.single){
6217             h = createSingle(h, el, ename, fn);
6218         }
6219         if(o.buffer){
6220             h = createBuffered(h, o);
6221         }
6222         fn._handlers = fn._handlers || [];
6223         
6224         
6225         fn._handlers.push([Roo.id(el), ename, h]);
6226         
6227         
6228          
6229         E.on(el, ename, h);
6230         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6231             el.addEventListener("DOMMouseScroll", h, false);
6232             E.on(window, 'unload', function(){
6233                 el.removeEventListener("DOMMouseScroll", h, false);
6234             });
6235         }
6236         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6237             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6238         }
6239         return h;
6240     };
6241
6242     var stopListening = function(el, ename, fn){
6243         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6244         if(hds){
6245             for(var i = 0, len = hds.length; i < len; i++){
6246                 var h = hds[i];
6247                 if(h[0] == id && h[1] == ename){
6248                     hd = h[2];
6249                     hds.splice(i, 1);
6250                     break;
6251                 }
6252             }
6253         }
6254         E.un(el, ename, hd);
6255         el = Roo.getDom(el);
6256         if(ename == "mousewheel" && el.addEventListener){
6257             el.removeEventListener("DOMMouseScroll", hd, false);
6258         }
6259         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6260             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6261         }
6262     };
6263
6264     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6265     
6266     var pub = {
6267         
6268         
6269         /** 
6270          * Fix for doc tools
6271          * @scope Roo.EventManager
6272          */
6273         
6274         
6275         /** 
6276          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6277          * object with a Roo.EventObject
6278          * @param {Function} fn        The method the event invokes
6279          * @param {Object}   scope    An object that becomes the scope of the handler
6280          * @param {boolean}  override If true, the obj passed in becomes
6281          *                             the execution scope of the listener
6282          * @return {Function} The wrapped function
6283          * @deprecated
6284          */
6285         wrap : function(fn, scope, override){
6286             return function(e){
6287                 Roo.EventObject.setEvent(e);
6288                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6289             };
6290         },
6291         
6292         /**
6293      * Appends an event handler to an element (shorthand for addListener)
6294      * @param {String/HTMLElement}   element        The html element or id to assign the
6295      * @param {String}   eventName The type of event to listen for
6296      * @param {Function} handler The method the event invokes
6297      * @param {Object}   scope (optional) The scope in which to execute the handler
6298      * function. The handler function's "this" context.
6299      * @param {Object}   options (optional) An object containing handler configuration
6300      * properties. This may contain any of the following properties:<ul>
6301      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6302      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6303      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6304      * <li>preventDefault {Boolean} True to prevent the default action</li>
6305      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6306      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6307      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6308      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6309      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6310      * by the specified number of milliseconds. If the event fires again within that time, the original
6311      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6312      * </ul><br>
6313      * <p>
6314      * <b>Combining Options</b><br>
6315      * Using the options argument, it is possible to combine different types of listeners:<br>
6316      * <br>
6317      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6318      * Code:<pre><code>
6319 el.on('click', this.onClick, this, {
6320     single: true,
6321     delay: 100,
6322     stopEvent : true,
6323     forumId: 4
6324 });</code></pre>
6325      * <p>
6326      * <b>Attaching multiple handlers in 1 call</b><br>
6327       * The method also allows for a single argument to be passed which is a config object containing properties
6328      * which specify multiple handlers.
6329      * <p>
6330      * Code:<pre><code>
6331 el.on({
6332     'click' : {
6333         fn: this.onClick
6334         scope: this,
6335         delay: 100
6336     },
6337     'mouseover' : {
6338         fn: this.onMouseOver
6339         scope: this
6340     },
6341     'mouseout' : {
6342         fn: this.onMouseOut
6343         scope: this
6344     }
6345 });</code></pre>
6346      * <p>
6347      * Or a shorthand syntax:<br>
6348      * Code:<pre><code>
6349 el.on({
6350     'click' : this.onClick,
6351     'mouseover' : this.onMouseOver,
6352     'mouseout' : this.onMouseOut
6353     scope: this
6354 });</code></pre>
6355      */
6356         addListener : function(element, eventName, fn, scope, options){
6357             if(typeof eventName == "object"){
6358                 var o = eventName;
6359                 for(var e in o){
6360                     if(propRe.test(e)){
6361                         continue;
6362                     }
6363                     if(typeof o[e] == "function"){
6364                         // shared options
6365                         listen(element, e, o, o[e], o.scope);
6366                     }else{
6367                         // individual options
6368                         listen(element, e, o[e]);
6369                     }
6370                 }
6371                 return;
6372             }
6373             return listen(element, eventName, options, fn, scope);
6374         },
6375         
6376         /**
6377          * Removes an event handler
6378          *
6379          * @param {String/HTMLElement}   element        The id or html element to remove the 
6380          *                             event from
6381          * @param {String}   eventName     The type of event
6382          * @param {Function} fn
6383          * @return {Boolean} True if a listener was actually removed
6384          */
6385         removeListener : function(element, eventName, fn){
6386             return stopListening(element, eventName, fn);
6387         },
6388         
6389         /**
6390          * Fires when the document is ready (before onload and before images are loaded). Can be 
6391          * accessed shorthanded Roo.onReady().
6392          * @param {Function} fn        The method the event invokes
6393          * @param {Object}   scope    An  object that becomes the scope of the handler
6394          * @param {boolean}  options
6395          */
6396         onDocumentReady : function(fn, scope, options){
6397             if(docReadyState){ // if it already fired
6398                 docReadyEvent.addListener(fn, scope, options);
6399                 docReadyEvent.fire();
6400                 docReadyEvent.clearListeners();
6401                 return;
6402             }
6403             if(!docReadyEvent){
6404                 initDocReady();
6405             }
6406             docReadyEvent.addListener(fn, scope, options);
6407         },
6408         
6409         /**
6410          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6411          * @param {Function} fn        The method the event invokes
6412          * @param {Object}   scope    An object that becomes the scope of the handler
6413          * @param {boolean}  options
6414          */
6415         onWindowResize : function(fn, scope, options){
6416             if(!resizeEvent){
6417                 resizeEvent = new Roo.util.Event();
6418                 resizeTask = new Roo.util.DelayedTask(function(){
6419                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6420                 });
6421                 E.on(window, "resize", function(){
6422                     if(Roo.isIE){
6423                         resizeTask.delay(50);
6424                     }else{
6425                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6426                     }
6427                 });
6428             }
6429             resizeEvent.addListener(fn, scope, options);
6430         },
6431
6432         /**
6433          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6434          * @param {Function} fn        The method the event invokes
6435          * @param {Object}   scope    An object that becomes the scope of the handler
6436          * @param {boolean}  options
6437          */
6438         onTextResize : function(fn, scope, options){
6439             if(!textEvent){
6440                 textEvent = new Roo.util.Event();
6441                 var textEl = new Roo.Element(document.createElement('div'));
6442                 textEl.dom.className = 'x-text-resize';
6443                 textEl.dom.innerHTML = 'X';
6444                 textEl.appendTo(document.body);
6445                 textSize = textEl.dom.offsetHeight;
6446                 setInterval(function(){
6447                     if(textEl.dom.offsetHeight != textSize){
6448                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6449                     }
6450                 }, this.textResizeInterval);
6451             }
6452             textEvent.addListener(fn, scope, options);
6453         },
6454
6455         /**
6456          * Removes the passed window resize listener.
6457          * @param {Function} fn        The method the event invokes
6458          * @param {Object}   scope    The scope of handler
6459          */
6460         removeResizeListener : function(fn, scope){
6461             if(resizeEvent){
6462                 resizeEvent.removeListener(fn, scope);
6463             }
6464         },
6465
6466         // private
6467         fireResize : function(){
6468             if(resizeEvent){
6469                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6470             }   
6471         },
6472         /**
6473          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6474          */
6475         ieDeferSrc : false,
6476         /**
6477          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6478          */
6479         textResizeInterval : 50
6480     };
6481     
6482     /**
6483      * Fix for doc tools
6484      * @scopeAlias pub=Roo.EventManager
6485      */
6486     
6487      /**
6488      * Appends an event handler to an element (shorthand for addListener)
6489      * @param {String/HTMLElement}   element        The html element or id to assign the
6490      * @param {String}   eventName The type of event to listen for
6491      * @param {Function} handler The method the event invokes
6492      * @param {Object}   scope (optional) The scope in which to execute the handler
6493      * function. The handler function's "this" context.
6494      * @param {Object}   options (optional) An object containing handler configuration
6495      * properties. This may contain any of the following properties:<ul>
6496      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6497      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6498      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6499      * <li>preventDefault {Boolean} True to prevent the default action</li>
6500      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6501      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6502      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6503      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6504      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6505      * by the specified number of milliseconds. If the event fires again within that time, the original
6506      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6507      * </ul><br>
6508      * <p>
6509      * <b>Combining Options</b><br>
6510      * Using the options argument, it is possible to combine different types of listeners:<br>
6511      * <br>
6512      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6513      * Code:<pre><code>
6514 el.on('click', this.onClick, this, {
6515     single: true,
6516     delay: 100,
6517     stopEvent : true,
6518     forumId: 4
6519 });</code></pre>
6520      * <p>
6521      * <b>Attaching multiple handlers in 1 call</b><br>
6522       * The method also allows for a single argument to be passed which is a config object containing properties
6523      * which specify multiple handlers.
6524      * <p>
6525      * Code:<pre><code>
6526 el.on({
6527     'click' : {
6528         fn: this.onClick
6529         scope: this,
6530         delay: 100
6531     },
6532     'mouseover' : {
6533         fn: this.onMouseOver
6534         scope: this
6535     },
6536     'mouseout' : {
6537         fn: this.onMouseOut
6538         scope: this
6539     }
6540 });</code></pre>
6541      * <p>
6542      * Or a shorthand syntax:<br>
6543      * Code:<pre><code>
6544 el.on({
6545     'click' : this.onClick,
6546     'mouseover' : this.onMouseOver,
6547     'mouseout' : this.onMouseOut
6548     scope: this
6549 });</code></pre>
6550      */
6551     pub.on = pub.addListener;
6552     pub.un = pub.removeListener;
6553
6554     pub.stoppedMouseDownEvent = new Roo.util.Event();
6555     return pub;
6556 }();
6557 /**
6558   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6559   * @param {Function} fn        The method the event invokes
6560   * @param {Object}   scope    An  object that becomes the scope of the handler
6561   * @param {boolean}  override If true, the obj passed in becomes
6562   *                             the execution scope of the listener
6563   * @member Roo
6564   * @method onReady
6565  */
6566 Roo.onReady = Roo.EventManager.onDocumentReady;
6567
6568 Roo.onReady(function(){
6569     var bd = Roo.get(document.body);
6570     if(!bd){ return; }
6571
6572     var cls = [
6573             Roo.isIE ? "roo-ie"
6574             : Roo.isGecko ? "roo-gecko"
6575             : Roo.isOpera ? "roo-opera"
6576             : Roo.isSafari ? "roo-safari" : ""];
6577
6578     if(Roo.isMac){
6579         cls.push("roo-mac");
6580     }
6581     if(Roo.isLinux){
6582         cls.push("roo-linux");
6583     }
6584     if(Roo.isIOS){
6585         cls.push("roo-ios");
6586     }
6587     if(Roo.isBorderBox){
6588         cls.push('roo-border-box');
6589     }
6590     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6591         var p = bd.dom.parentNode;
6592         if(p){
6593             p.className += ' roo-strict';
6594         }
6595     }
6596     bd.addClass(cls.join(' '));
6597 });
6598
6599 /**
6600  * @class Roo.EventObject
6601  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6602  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6603  * Example:
6604  * <pre><code>
6605  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6606     e.preventDefault();
6607     var target = e.getTarget();
6608     ...
6609  }
6610  var myDiv = Roo.get("myDiv");
6611  myDiv.on("click", handleClick);
6612  //or
6613  Roo.EventManager.on("myDiv", 'click', handleClick);
6614  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6615  </code></pre>
6616  * @singleton
6617  */
6618 Roo.EventObject = function(){
6619     
6620     var E = Roo.lib.Event;
6621     
6622     // safari keypress events for special keys return bad keycodes
6623     var safariKeys = {
6624         63234 : 37, // left
6625         63235 : 39, // right
6626         63232 : 38, // up
6627         63233 : 40, // down
6628         63276 : 33, // page up
6629         63277 : 34, // page down
6630         63272 : 46, // delete
6631         63273 : 36, // home
6632         63275 : 35  // end
6633     };
6634
6635     // normalize button clicks
6636     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6637                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6638
6639     Roo.EventObjectImpl = function(e){
6640         if(e){
6641             this.setEvent(e.browserEvent || e);
6642         }
6643     };
6644     Roo.EventObjectImpl.prototype = {
6645         /**
6646          * Used to fix doc tools.
6647          * @scope Roo.EventObject.prototype
6648          */
6649             
6650
6651         
6652         
6653         /** The normal browser event */
6654         browserEvent : null,
6655         /** The button pressed in a mouse event */
6656         button : -1,
6657         /** True if the shift key was down during the event */
6658         shiftKey : false,
6659         /** True if the control key was down during the event */
6660         ctrlKey : false,
6661         /** True if the alt key was down during the event */
6662         altKey : false,
6663
6664         /** Key constant 
6665         * @type Number */
6666         BACKSPACE : 8,
6667         /** Key constant 
6668         * @type Number */
6669         TAB : 9,
6670         /** Key constant 
6671         * @type Number */
6672         RETURN : 13,
6673         /** Key constant 
6674         * @type Number */
6675         ENTER : 13,
6676         /** Key constant 
6677         * @type Number */
6678         SHIFT : 16,
6679         /** Key constant 
6680         * @type Number */
6681         CONTROL : 17,
6682         /** Key constant 
6683         * @type Number */
6684         ESC : 27,
6685         /** Key constant 
6686         * @type Number */
6687         SPACE : 32,
6688         /** Key constant 
6689         * @type Number */
6690         PAGEUP : 33,
6691         /** Key constant 
6692         * @type Number */
6693         PAGEDOWN : 34,
6694         /** Key constant 
6695         * @type Number */
6696         END : 35,
6697         /** Key constant 
6698         * @type Number */
6699         HOME : 36,
6700         /** Key constant 
6701         * @type Number */
6702         LEFT : 37,
6703         /** Key constant 
6704         * @type Number */
6705         UP : 38,
6706         /** Key constant 
6707         * @type Number */
6708         RIGHT : 39,
6709         /** Key constant 
6710         * @type Number */
6711         DOWN : 40,
6712         /** Key constant 
6713         * @type Number */
6714         DELETE : 46,
6715         /** Key constant 
6716         * @type Number */
6717         F5 : 116,
6718
6719            /** @private */
6720         setEvent : function(e){
6721             if(e == this || (e && e.browserEvent)){ // already wrapped
6722                 return e;
6723             }
6724             this.browserEvent = e;
6725             if(e){
6726                 // normalize buttons
6727                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6728                 if(e.type == 'click' && this.button == -1){
6729                     this.button = 0;
6730                 }
6731                 this.type = e.type;
6732                 this.shiftKey = e.shiftKey;
6733                 // mac metaKey behaves like ctrlKey
6734                 this.ctrlKey = e.ctrlKey || e.metaKey;
6735                 this.altKey = e.altKey;
6736                 // in getKey these will be normalized for the mac
6737                 this.keyCode = e.keyCode;
6738                 // keyup warnings on firefox.
6739                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6740                 // cache the target for the delayed and or buffered events
6741                 this.target = E.getTarget(e);
6742                 // same for XY
6743                 this.xy = E.getXY(e);
6744             }else{
6745                 this.button = -1;
6746                 this.shiftKey = false;
6747                 this.ctrlKey = false;
6748                 this.altKey = false;
6749                 this.keyCode = 0;
6750                 this.charCode =0;
6751                 this.target = null;
6752                 this.xy = [0, 0];
6753             }
6754             return this;
6755         },
6756
6757         /**
6758          * Stop the event (preventDefault and stopPropagation)
6759          */
6760         stopEvent : function(){
6761             if(this.browserEvent){
6762                 if(this.browserEvent.type == 'mousedown'){
6763                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6764                 }
6765                 E.stopEvent(this.browserEvent);
6766             }
6767         },
6768
6769         /**
6770          * Prevents the browsers default handling of the event.
6771          */
6772         preventDefault : function(){
6773             if(this.browserEvent){
6774                 E.preventDefault(this.browserEvent);
6775             }
6776         },
6777
6778         /** @private */
6779         isNavKeyPress : function(){
6780             var k = this.keyCode;
6781             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6782             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6783         },
6784
6785         isSpecialKey : function(){
6786             var k = this.keyCode;
6787             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6788             (k == 16) || (k == 17) ||
6789             (k >= 18 && k <= 20) ||
6790             (k >= 33 && k <= 35) ||
6791             (k >= 36 && k <= 39) ||
6792             (k >= 44 && k <= 45);
6793         },
6794         /**
6795          * Cancels bubbling of the event.
6796          */
6797         stopPropagation : function(){
6798             if(this.browserEvent){
6799                 if(this.type == 'mousedown'){
6800                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6801                 }
6802                 E.stopPropagation(this.browserEvent);
6803             }
6804         },
6805
6806         /**
6807          * Gets the key code for the event.
6808          * @return {Number}
6809          */
6810         getCharCode : function(){
6811             return this.charCode || this.keyCode;
6812         },
6813
6814         /**
6815          * Returns a normalized keyCode for the event.
6816          * @return {Number} The key code
6817          */
6818         getKey : function(){
6819             var k = this.keyCode || this.charCode;
6820             return Roo.isSafari ? (safariKeys[k] || k) : k;
6821         },
6822
6823         /**
6824          * Gets the x coordinate of the event.
6825          * @return {Number}
6826          */
6827         getPageX : function(){
6828             return this.xy[0];
6829         },
6830
6831         /**
6832          * Gets the y coordinate of the event.
6833          * @return {Number}
6834          */
6835         getPageY : function(){
6836             return this.xy[1];
6837         },
6838
6839         /**
6840          * Gets the time of the event.
6841          * @return {Number}
6842          */
6843         getTime : function(){
6844             if(this.browserEvent){
6845                 return E.getTime(this.browserEvent);
6846             }
6847             return null;
6848         },
6849
6850         /**
6851          * Gets the page coordinates of the event.
6852          * @return {Array} The xy values like [x, y]
6853          */
6854         getXY : function(){
6855             return this.xy;
6856         },
6857
6858         /**
6859          * Gets the target for the event.
6860          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6861          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6862                 search as a number or element (defaults to 10 || document.body)
6863          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6864          * @return {HTMLelement}
6865          */
6866         getTarget : function(selector, maxDepth, returnEl){
6867             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6868         },
6869         /**
6870          * Gets the related target.
6871          * @return {HTMLElement}
6872          */
6873         getRelatedTarget : function(){
6874             if(this.browserEvent){
6875                 return E.getRelatedTarget(this.browserEvent);
6876             }
6877             return null;
6878         },
6879
6880         /**
6881          * Normalizes mouse wheel delta across browsers
6882          * @return {Number} The delta
6883          */
6884         getWheelDelta : function(){
6885             var e = this.browserEvent;
6886             var delta = 0;
6887             if(e.wheelDelta){ /* IE/Opera. */
6888                 delta = e.wheelDelta/120;
6889             }else if(e.detail){ /* Mozilla case. */
6890                 delta = -e.detail/3;
6891             }
6892             return delta;
6893         },
6894
6895         /**
6896          * Returns true if the control, meta, shift or alt key was pressed during this event.
6897          * @return {Boolean}
6898          */
6899         hasModifier : function(){
6900             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6901         },
6902
6903         /**
6904          * Returns true if the target of this event equals el or is a child of el
6905          * @param {String/HTMLElement/Element} el
6906          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6907          * @return {Boolean}
6908          */
6909         within : function(el, related){
6910             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6911             return t && Roo.fly(el).contains(t);
6912         },
6913
6914         getPoint : function(){
6915             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6916         }
6917     };
6918
6919     return new Roo.EventObjectImpl();
6920 }();
6921             
6922     /*
6923  * Based on:
6924  * Ext JS Library 1.1.1
6925  * Copyright(c) 2006-2007, Ext JS, LLC.
6926  *
6927  * Originally Released Under LGPL - original licence link has changed is not relivant.
6928  *
6929  * Fork - LGPL
6930  * <script type="text/javascript">
6931  */
6932
6933  
6934 // was in Composite Element!??!?!
6935  
6936 (function(){
6937     var D = Roo.lib.Dom;
6938     var E = Roo.lib.Event;
6939     var A = Roo.lib.Anim;
6940
6941     // local style camelizing for speed
6942     var propCache = {};
6943     var camelRe = /(-[a-z])/gi;
6944     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6945     var view = document.defaultView;
6946
6947 /**
6948  * @class Roo.Element
6949  * Represents an Element in the DOM.<br><br>
6950  * Usage:<br>
6951 <pre><code>
6952 var el = Roo.get("my-div");
6953
6954 // or with getEl
6955 var el = getEl("my-div");
6956
6957 // or with a DOM element
6958 var el = Roo.get(myDivElement);
6959 </code></pre>
6960  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6961  * each call instead of constructing a new one.<br><br>
6962  * <b>Animations</b><br />
6963  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6964  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6965 <pre>
6966 Option    Default   Description
6967 --------- --------  ---------------------------------------------
6968 duration  .35       The duration of the animation in seconds
6969 easing    easeOut   The YUI easing method
6970 callback  none      A function to execute when the anim completes
6971 scope     this      The scope (this) of the callback function
6972 </pre>
6973 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6974 * manipulate the animation. Here's an example:
6975 <pre><code>
6976 var el = Roo.get("my-div");
6977
6978 // no animation
6979 el.setWidth(100);
6980
6981 // default animation
6982 el.setWidth(100, true);
6983
6984 // animation with some options set
6985 el.setWidth(100, {
6986     duration: 1,
6987     callback: this.foo,
6988     scope: this
6989 });
6990
6991 // using the "anim" property to get the Anim object
6992 var opt = {
6993     duration: 1,
6994     callback: this.foo,
6995     scope: this
6996 };
6997 el.setWidth(100, opt);
6998 ...
6999 if(opt.anim.isAnimated()){
7000     opt.anim.stop();
7001 }
7002 </code></pre>
7003 * <b> Composite (Collections of) Elements</b><br />
7004  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7005  * @constructor Create a new Element directly.
7006  * @param {String/HTMLElement} element
7007  * @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).
7008  */
7009     Roo.Element = function(element, forceNew){
7010         var dom = typeof element == "string" ?
7011                 document.getElementById(element) : element;
7012         if(!dom){ // invalid id/element
7013             return null;
7014         }
7015         var id = dom.id;
7016         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7017             return Roo.Element.cache[id];
7018         }
7019
7020         /**
7021          * The DOM element
7022          * @type HTMLElement
7023          */
7024         this.dom = dom;
7025
7026         /**
7027          * The DOM element ID
7028          * @type String
7029          */
7030         this.id = id || Roo.id(dom);
7031     };
7032
7033     var El = Roo.Element;
7034
7035     El.prototype = {
7036         /**
7037          * The element's default display mode  (defaults to "")
7038          * @type String
7039          */
7040         originalDisplay : "",
7041
7042         visibilityMode : 1,
7043         /**
7044          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7045          * @type String
7046          */
7047         defaultUnit : "px",
7048         
7049         pxReg : /^\d+(?:\.\d*)?px$/i,
7050         /**
7051          * Sets the element's visibility mode. When setVisible() is called it
7052          * will use this to determine whether to set the visibility or the display property.
7053          * @param visMode Element.VISIBILITY or Element.DISPLAY
7054          * @return {Roo.Element} this
7055          */
7056         setVisibilityMode : function(visMode){
7057             this.visibilityMode = visMode;
7058             return this;
7059         },
7060         /**
7061          * Convenience method for setVisibilityMode(Element.DISPLAY)
7062          * @param {String} display (optional) What to set display to when visible
7063          * @return {Roo.Element} this
7064          */
7065         enableDisplayMode : function(display){
7066             this.setVisibilityMode(El.DISPLAY);
7067             if(typeof display != "undefined") this.originalDisplay = display;
7068             return this;
7069         },
7070
7071         /**
7072          * 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)
7073          * @param {String} selector The simple selector to test
7074          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7075                 search as a number or element (defaults to 10 || document.body)
7076          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7077          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7078          */
7079         findParent : function(simpleSelector, maxDepth, returnEl){
7080             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7081             maxDepth = maxDepth || 50;
7082             if(typeof maxDepth != "number"){
7083                 stopEl = Roo.getDom(maxDepth);
7084                 maxDepth = 10;
7085             }
7086             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7087                 if(dq.is(p, simpleSelector)){
7088                     return returnEl ? Roo.get(p) : p;
7089                 }
7090                 depth++;
7091                 p = p.parentNode;
7092             }
7093             return null;
7094         },
7095
7096
7097         /**
7098          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7099          * @param {String} selector The simple selector to test
7100          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7101                 search as a number or element (defaults to 10 || document.body)
7102          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7103          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7104          */
7105         findParentNode : function(simpleSelector, maxDepth, returnEl){
7106             var p = Roo.fly(this.dom.parentNode, '_internal');
7107             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7108         },
7109
7110         /**
7111          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7112          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7113          * @param {String} selector The simple selector to test
7114          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7115                 search as a number or element (defaults to 10 || document.body)
7116          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7117          */
7118         up : function(simpleSelector, maxDepth){
7119             return this.findParentNode(simpleSelector, maxDepth, true);
7120         },
7121
7122
7123
7124         /**
7125          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7126          * @param {String} selector The simple selector to test
7127          * @return {Boolean} True if this element matches the selector, else false
7128          */
7129         is : function(simpleSelector){
7130             return Roo.DomQuery.is(this.dom, simpleSelector);
7131         },
7132
7133         /**
7134          * Perform animation on this element.
7135          * @param {Object} args The YUI animation control args
7136          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7137          * @param {Function} onComplete (optional) Function to call when animation completes
7138          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7139          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7140          * @return {Roo.Element} this
7141          */
7142         animate : function(args, duration, onComplete, easing, animType){
7143             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7144             return this;
7145         },
7146
7147         /*
7148          * @private Internal animation call
7149          */
7150         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7151             animType = animType || 'run';
7152             opt = opt || {};
7153             var anim = Roo.lib.Anim[animType](
7154                 this.dom, args,
7155                 (opt.duration || defaultDur) || .35,
7156                 (opt.easing || defaultEase) || 'easeOut',
7157                 function(){
7158                     Roo.callback(cb, this);
7159                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7160                 },
7161                 this
7162             );
7163             opt.anim = anim;
7164             return anim;
7165         },
7166
7167         // private legacy anim prep
7168         preanim : function(a, i){
7169             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7170         },
7171
7172         /**
7173          * Removes worthless text nodes
7174          * @param {Boolean} forceReclean (optional) By default the element
7175          * keeps track if it has been cleaned already so
7176          * you can call this over and over. However, if you update the element and
7177          * need to force a reclean, you can pass true.
7178          */
7179         clean : function(forceReclean){
7180             if(this.isCleaned && forceReclean !== true){
7181                 return this;
7182             }
7183             var ns = /\S/;
7184             var d = this.dom, n = d.firstChild, ni = -1;
7185             while(n){
7186                 var nx = n.nextSibling;
7187                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7188                     d.removeChild(n);
7189                 }else{
7190                     n.nodeIndex = ++ni;
7191                 }
7192                 n = nx;
7193             }
7194             this.isCleaned = true;
7195             return this;
7196         },
7197
7198         // private
7199         calcOffsetsTo : function(el){
7200             el = Roo.get(el);
7201             var d = el.dom;
7202             var restorePos = false;
7203             if(el.getStyle('position') == 'static'){
7204                 el.position('relative');
7205                 restorePos = true;
7206             }
7207             var x = 0, y =0;
7208             var op = this.dom;
7209             while(op && op != d && op.tagName != 'HTML'){
7210                 x+= op.offsetLeft;
7211                 y+= op.offsetTop;
7212                 op = op.offsetParent;
7213             }
7214             if(restorePos){
7215                 el.position('static');
7216             }
7217             return [x, y];
7218         },
7219
7220         /**
7221          * Scrolls this element into view within the passed container.
7222          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7223          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7224          * @return {Roo.Element} this
7225          */
7226         scrollIntoView : function(container, hscroll){
7227             var c = Roo.getDom(container) || document.body;
7228             var el = this.dom;
7229
7230             var o = this.calcOffsetsTo(c),
7231                 l = o[0],
7232                 t = o[1],
7233                 b = t+el.offsetHeight,
7234                 r = l+el.offsetWidth;
7235
7236             var ch = c.clientHeight;
7237             var ct = parseInt(c.scrollTop, 10);
7238             var cl = parseInt(c.scrollLeft, 10);
7239             var cb = ct + ch;
7240             var cr = cl + c.clientWidth;
7241
7242             if(t < ct){
7243                 c.scrollTop = t;
7244             }else if(b > cb){
7245                 c.scrollTop = b-ch;
7246             }
7247
7248             if(hscroll !== false){
7249                 if(l < cl){
7250                     c.scrollLeft = l;
7251                 }else if(r > cr){
7252                     c.scrollLeft = r-c.clientWidth;
7253                 }
7254             }
7255             return this;
7256         },
7257
7258         // private
7259         scrollChildIntoView : function(child, hscroll){
7260             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7261         },
7262
7263         /**
7264          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7265          * the new height may not be available immediately.
7266          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7267          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7268          * @param {Function} onComplete (optional) Function to call when animation completes
7269          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7270          * @return {Roo.Element} this
7271          */
7272         autoHeight : function(animate, duration, onComplete, easing){
7273             var oldHeight = this.getHeight();
7274             this.clip();
7275             this.setHeight(1); // force clipping
7276             setTimeout(function(){
7277                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7278                 if(!animate){
7279                     this.setHeight(height);
7280                     this.unclip();
7281                     if(typeof onComplete == "function"){
7282                         onComplete();
7283                     }
7284                 }else{
7285                     this.setHeight(oldHeight); // restore original height
7286                     this.setHeight(height, animate, duration, function(){
7287                         this.unclip();
7288                         if(typeof onComplete == "function") onComplete();
7289                     }.createDelegate(this), easing);
7290                 }
7291             }.createDelegate(this), 0);
7292             return this;
7293         },
7294
7295         /**
7296          * Returns true if this element is an ancestor of the passed element
7297          * @param {HTMLElement/String} el The element to check
7298          * @return {Boolean} True if this element is an ancestor of el, else false
7299          */
7300         contains : function(el){
7301             if(!el){return false;}
7302             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7303         },
7304
7305         /**
7306          * Checks whether the element is currently visible using both visibility and display properties.
7307          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7308          * @return {Boolean} True if the element is currently visible, else false
7309          */
7310         isVisible : function(deep) {
7311             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7312             if(deep !== true || !vis){
7313                 return vis;
7314             }
7315             var p = this.dom.parentNode;
7316             while(p && p.tagName.toLowerCase() != "body"){
7317                 if(!Roo.fly(p, '_isVisible').isVisible()){
7318                     return false;
7319                 }
7320                 p = p.parentNode;
7321             }
7322             return true;
7323         },
7324
7325         /**
7326          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7327          * @param {String} selector The CSS selector
7328          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7329          * @return {CompositeElement/CompositeElementLite} The composite element
7330          */
7331         select : function(selector, unique){
7332             return El.select(selector, unique, this.dom);
7333         },
7334
7335         /**
7336          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7337          * @param {String} selector The CSS selector
7338          * @return {Array} An array of the matched nodes
7339          */
7340         query : function(selector, unique){
7341             return Roo.DomQuery.select(selector, this.dom);
7342         },
7343
7344         /**
7345          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7346          * @param {String} selector The CSS selector
7347          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7348          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7349          */
7350         child : function(selector, returnDom){
7351             var n = Roo.DomQuery.selectNode(selector, this.dom);
7352             return returnDom ? n : Roo.get(n);
7353         },
7354
7355         /**
7356          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7357          * @param {String} selector The CSS selector
7358          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7359          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7360          */
7361         down : function(selector, returnDom){
7362             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7363             return returnDom ? n : Roo.get(n);
7364         },
7365
7366         /**
7367          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7368          * @param {String} group The group the DD object is member of
7369          * @param {Object} config The DD config object
7370          * @param {Object} overrides An object containing methods to override/implement on the DD object
7371          * @return {Roo.dd.DD} The DD object
7372          */
7373         initDD : function(group, config, overrides){
7374             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7375             return Roo.apply(dd, overrides);
7376         },
7377
7378         /**
7379          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7380          * @param {String} group The group the DDProxy object is member of
7381          * @param {Object} config The DDProxy config object
7382          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7383          * @return {Roo.dd.DDProxy} The DDProxy object
7384          */
7385         initDDProxy : function(group, config, overrides){
7386             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7387             return Roo.apply(dd, overrides);
7388         },
7389
7390         /**
7391          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7392          * @param {String} group The group the DDTarget object is member of
7393          * @param {Object} config The DDTarget config object
7394          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7395          * @return {Roo.dd.DDTarget} The DDTarget object
7396          */
7397         initDDTarget : function(group, config, overrides){
7398             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7399             return Roo.apply(dd, overrides);
7400         },
7401
7402         /**
7403          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7404          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7405          * @param {Boolean} visible Whether the element is visible
7406          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7407          * @return {Roo.Element} this
7408          */
7409          setVisible : function(visible, animate){
7410             if(!animate || !A){
7411                 if(this.visibilityMode == El.DISPLAY){
7412                     this.setDisplayed(visible);
7413                 }else{
7414                     this.fixDisplay();
7415                     this.dom.style.visibility = visible ? "visible" : "hidden";
7416                 }
7417             }else{
7418                 // closure for composites
7419                 var dom = this.dom;
7420                 var visMode = this.visibilityMode;
7421                 if(visible){
7422                     this.setOpacity(.01);
7423                     this.setVisible(true);
7424                 }
7425                 this.anim({opacity: { to: (visible?1:0) }},
7426                       this.preanim(arguments, 1),
7427                       null, .35, 'easeIn', function(){
7428                          if(!visible){
7429                              if(visMode == El.DISPLAY){
7430                                  dom.style.display = "none";
7431                              }else{
7432                                  dom.style.visibility = "hidden";
7433                              }
7434                              Roo.get(dom).setOpacity(1);
7435                          }
7436                      });
7437             }
7438             return this;
7439         },
7440
7441         /**
7442          * Returns true if display is not "none"
7443          * @return {Boolean}
7444          */
7445         isDisplayed : function() {
7446             return this.getStyle("display") != "none";
7447         },
7448
7449         /**
7450          * Toggles the element's visibility or display, depending on visibility mode.
7451          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7452          * @return {Roo.Element} this
7453          */
7454         toggle : function(animate){
7455             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7456             return this;
7457         },
7458
7459         /**
7460          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7461          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7462          * @return {Roo.Element} this
7463          */
7464         setDisplayed : function(value) {
7465             if(typeof value == "boolean"){
7466                value = value ? this.originalDisplay : "none";
7467             }
7468             this.setStyle("display", value);
7469             return this;
7470         },
7471
7472         /**
7473          * Tries to focus the element. Any exceptions are caught and ignored.
7474          * @return {Roo.Element} this
7475          */
7476         focus : function() {
7477             try{
7478                 this.dom.focus();
7479             }catch(e){}
7480             return this;
7481         },
7482
7483         /**
7484          * Tries to blur the element. Any exceptions are caught and ignored.
7485          * @return {Roo.Element} this
7486          */
7487         blur : function() {
7488             try{
7489                 this.dom.blur();
7490             }catch(e){}
7491             return this;
7492         },
7493
7494         /**
7495          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7496          * @param {String/Array} className The CSS class to add, or an array of classes
7497          * @return {Roo.Element} this
7498          */
7499         addClass : function(className){
7500             if(className instanceof Array){
7501                 for(var i = 0, len = className.length; i < len; i++) {
7502                     this.addClass(className[i]);
7503                 }
7504             }else{
7505                 if(className && !this.hasClass(className)){
7506                     this.dom.className = this.dom.className + " " + className;
7507                 }
7508             }
7509             return this;
7510         },
7511
7512         /**
7513          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7514          * @param {String/Array} className The CSS class to add, or an array of classes
7515          * @return {Roo.Element} this
7516          */
7517         radioClass : function(className){
7518             var siblings = this.dom.parentNode.childNodes;
7519             for(var i = 0; i < siblings.length; i++) {
7520                 var s = siblings[i];
7521                 if(s.nodeType == 1){
7522                     Roo.get(s).removeClass(className);
7523                 }
7524             }
7525             this.addClass(className);
7526             return this;
7527         },
7528
7529         /**
7530          * Removes one or more CSS classes from the element.
7531          * @param {String/Array} className The CSS class to remove, or an array of classes
7532          * @return {Roo.Element} this
7533          */
7534         removeClass : function(className){
7535             if(!className || !this.dom.className){
7536                 return this;
7537             }
7538             if(className instanceof Array){
7539                 for(var i = 0, len = className.length; i < len; i++) {
7540                     this.removeClass(className[i]);
7541                 }
7542             }else{
7543                 if(this.hasClass(className)){
7544                     var re = this.classReCache[className];
7545                     if (!re) {
7546                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7547                        this.classReCache[className] = re;
7548                     }
7549                     this.dom.className =
7550                         this.dom.className.replace(re, " ");
7551                 }
7552             }
7553             return this;
7554         },
7555
7556         // private
7557         classReCache: {},
7558
7559         /**
7560          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7561          * @param {String} className The CSS class to toggle
7562          * @return {Roo.Element} this
7563          */
7564         toggleClass : function(className){
7565             if(this.hasClass(className)){
7566                 this.removeClass(className);
7567             }else{
7568                 this.addClass(className);
7569             }
7570             return this;
7571         },
7572
7573         /**
7574          * Checks if the specified CSS class exists on this element's DOM node.
7575          * @param {String} className The CSS class to check for
7576          * @return {Boolean} True if the class exists, else false
7577          */
7578         hasClass : function(className){
7579             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7580         },
7581
7582         /**
7583          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7584          * @param {String} oldClassName The CSS class to replace
7585          * @param {String} newClassName The replacement CSS class
7586          * @return {Roo.Element} this
7587          */
7588         replaceClass : function(oldClassName, newClassName){
7589             this.removeClass(oldClassName);
7590             this.addClass(newClassName);
7591             return this;
7592         },
7593
7594         /**
7595          * Returns an object with properties matching the styles requested.
7596          * For example, el.getStyles('color', 'font-size', 'width') might return
7597          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7598          * @param {String} style1 A style name
7599          * @param {String} style2 A style name
7600          * @param {String} etc.
7601          * @return {Object} The style object
7602          */
7603         getStyles : function(){
7604             var a = arguments, len = a.length, r = {};
7605             for(var i = 0; i < len; i++){
7606                 r[a[i]] = this.getStyle(a[i]);
7607             }
7608             return r;
7609         },
7610
7611         /**
7612          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7613          * @param {String} property The style property whose value is returned.
7614          * @return {String} The current value of the style property for this element.
7615          */
7616         getStyle : function(){
7617             return view && view.getComputedStyle ?
7618                 function(prop){
7619                     var el = this.dom, v, cs, camel;
7620                     if(prop == 'float'){
7621                         prop = "cssFloat";
7622                     }
7623                     if(el.style && (v = el.style[prop])){
7624                         return v;
7625                     }
7626                     if(cs = view.getComputedStyle(el, "")){
7627                         if(!(camel = propCache[prop])){
7628                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7629                         }
7630                         return cs[camel];
7631                     }
7632                     return null;
7633                 } :
7634                 function(prop){
7635                     var el = this.dom, v, cs, camel;
7636                     if(prop == 'opacity'){
7637                         if(typeof el.style.filter == 'string'){
7638                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7639                             if(m){
7640                                 var fv = parseFloat(m[1]);
7641                                 if(!isNaN(fv)){
7642                                     return fv ? fv / 100 : 0;
7643                                 }
7644                             }
7645                         }
7646                         return 1;
7647                     }else if(prop == 'float'){
7648                         prop = "styleFloat";
7649                     }
7650                     if(!(camel = propCache[prop])){
7651                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7652                     }
7653                     if(v = el.style[camel]){
7654                         return v;
7655                     }
7656                     if(cs = el.currentStyle){
7657                         return cs[camel];
7658                     }
7659                     return null;
7660                 };
7661         }(),
7662
7663         /**
7664          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7665          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7666          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7667          * @return {Roo.Element} this
7668          */
7669         setStyle : function(prop, value){
7670             if(typeof prop == "string"){
7671                 
7672                 if (prop == 'float') {
7673                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7674                     return this;
7675                 }
7676                 
7677                 var camel;
7678                 if(!(camel = propCache[prop])){
7679                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7680                 }
7681                 
7682                 if(camel == 'opacity') {
7683                     this.setOpacity(value);
7684                 }else{
7685                     this.dom.style[camel] = value;
7686                 }
7687             }else{
7688                 for(var style in prop){
7689                     if(typeof prop[style] != "function"){
7690                        this.setStyle(style, prop[style]);
7691                     }
7692                 }
7693             }
7694             return this;
7695         },
7696
7697         /**
7698          * More flexible version of {@link #setStyle} for setting style properties.
7699          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7700          * a function which returns such a specification.
7701          * @return {Roo.Element} this
7702          */
7703         applyStyles : function(style){
7704             Roo.DomHelper.applyStyles(this.dom, style);
7705             return this;
7706         },
7707
7708         /**
7709           * 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).
7710           * @return {Number} The X position of the element
7711           */
7712         getX : function(){
7713             return D.getX(this.dom);
7714         },
7715
7716         /**
7717           * 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).
7718           * @return {Number} The Y position of the element
7719           */
7720         getY : function(){
7721             return D.getY(this.dom);
7722         },
7723
7724         /**
7725           * 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).
7726           * @return {Array} The XY position of the element
7727           */
7728         getXY : function(){
7729             return D.getXY(this.dom);
7730         },
7731
7732         /**
7733          * 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).
7734          * @param {Number} The X position of the element
7735          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7736          * @return {Roo.Element} this
7737          */
7738         setX : function(x, animate){
7739             if(!animate || !A){
7740                 D.setX(this.dom, x);
7741             }else{
7742                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7743             }
7744             return this;
7745         },
7746
7747         /**
7748          * 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).
7749          * @param {Number} The Y position of the element
7750          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7751          * @return {Roo.Element} this
7752          */
7753         setY : function(y, animate){
7754             if(!animate || !A){
7755                 D.setY(this.dom, y);
7756             }else{
7757                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7758             }
7759             return this;
7760         },
7761
7762         /**
7763          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7764          * @param {String} left The left CSS property value
7765          * @return {Roo.Element} this
7766          */
7767         setLeft : function(left){
7768             this.setStyle("left", this.addUnits(left));
7769             return this;
7770         },
7771
7772         /**
7773          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7774          * @param {String} top The top CSS property value
7775          * @return {Roo.Element} this
7776          */
7777         setTop : function(top){
7778             this.setStyle("top", this.addUnits(top));
7779             return this;
7780         },
7781
7782         /**
7783          * Sets the element's CSS right style.
7784          * @param {String} right The right CSS property value
7785          * @return {Roo.Element} this
7786          */
7787         setRight : function(right){
7788             this.setStyle("right", this.addUnits(right));
7789             return this;
7790         },
7791
7792         /**
7793          * Sets the element's CSS bottom style.
7794          * @param {String} bottom The bottom CSS property value
7795          * @return {Roo.Element} this
7796          */
7797         setBottom : function(bottom){
7798             this.setStyle("bottom", this.addUnits(bottom));
7799             return this;
7800         },
7801
7802         /**
7803          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7804          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7805          * @param {Array} pos Contains X & Y [x, y] values 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         setXY : function(pos, animate){
7810             if(!animate || !A){
7811                 D.setXY(this.dom, pos);
7812             }else{
7813                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7814             }
7815             return this;
7816         },
7817
7818         /**
7819          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7820          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7821          * @param {Number} x X value for new position (coordinates are page-based)
7822          * @param {Number} y Y value for new position (coordinates are page-based)
7823          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7824          * @return {Roo.Element} this
7825          */
7826         setLocation : function(x, y, animate){
7827             this.setXY([x, y], this.preanim(arguments, 2));
7828             return this;
7829         },
7830
7831         /**
7832          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7833          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7834          * @param {Number} x X value for new position (coordinates are page-based)
7835          * @param {Number} y Y value for new position (coordinates are page-based)
7836          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7837          * @return {Roo.Element} this
7838          */
7839         moveTo : function(x, y, animate){
7840             this.setXY([x, y], this.preanim(arguments, 2));
7841             return this;
7842         },
7843
7844         /**
7845          * Returns the region of the given element.
7846          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7847          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7848          */
7849         getRegion : function(){
7850             return D.getRegion(this.dom);
7851         },
7852
7853         /**
7854          * Returns the offset height of the element
7855          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7856          * @return {Number} The element's height
7857          */
7858         getHeight : function(contentHeight){
7859             var h = this.dom.offsetHeight || 0;
7860             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7861         },
7862
7863         /**
7864          * Returns the offset width of the element
7865          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7866          * @return {Number} The element's width
7867          */
7868         getWidth : function(contentWidth){
7869             var w = this.dom.offsetWidth || 0;
7870             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7871         },
7872
7873         /**
7874          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7875          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7876          * if a height has not been set using CSS.
7877          * @return {Number}
7878          */
7879         getComputedHeight : function(){
7880             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7881             if(!h){
7882                 h = parseInt(this.getStyle('height'), 10) || 0;
7883                 if(!this.isBorderBox()){
7884                     h += this.getFrameWidth('tb');
7885                 }
7886             }
7887             return h;
7888         },
7889
7890         /**
7891          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7892          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7893          * if a width has not been set using CSS.
7894          * @return {Number}
7895          */
7896         getComputedWidth : function(){
7897             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7898             if(!w){
7899                 w = parseInt(this.getStyle('width'), 10) || 0;
7900                 if(!this.isBorderBox()){
7901                     w += this.getFrameWidth('lr');
7902                 }
7903             }
7904             return w;
7905         },
7906
7907         /**
7908          * Returns the size of the element.
7909          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7910          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7911          */
7912         getSize : function(contentSize){
7913             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7914         },
7915
7916         /**
7917          * Returns the width and height of the viewport.
7918          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7919          */
7920         getViewSize : function(){
7921             var d = this.dom, doc = document, aw = 0, ah = 0;
7922             if(d == doc || d == doc.body){
7923                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7924             }else{
7925                 return {
7926                     width : d.clientWidth,
7927                     height: d.clientHeight
7928                 };
7929             }
7930         },
7931
7932         /**
7933          * Returns the value of the "value" attribute
7934          * @param {Boolean} asNumber true to parse the value as a number
7935          * @return {String/Number}
7936          */
7937         getValue : function(asNumber){
7938             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7939         },
7940
7941         // private
7942         adjustWidth : function(width){
7943             if(typeof width == "number"){
7944                 if(this.autoBoxAdjust && !this.isBorderBox()){
7945                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7946                 }
7947                 if(width < 0){
7948                     width = 0;
7949                 }
7950             }
7951             return width;
7952         },
7953
7954         // private
7955         adjustHeight : function(height){
7956             if(typeof height == "number"){
7957                if(this.autoBoxAdjust && !this.isBorderBox()){
7958                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7959                }
7960                if(height < 0){
7961                    height = 0;
7962                }
7963             }
7964             return height;
7965         },
7966
7967         /**
7968          * Set the width of the element
7969          * @param {Number} width The new width
7970          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7971          * @return {Roo.Element} this
7972          */
7973         setWidth : function(width, animate){
7974             width = this.adjustWidth(width);
7975             if(!animate || !A){
7976                 this.dom.style.width = this.addUnits(width);
7977             }else{
7978                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7979             }
7980             return this;
7981         },
7982
7983         /**
7984          * Set the height of the element
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          setHeight : function(height, animate){
7990             height = this.adjustHeight(height);
7991             if(!animate || !A){
7992                 this.dom.style.height = this.addUnits(height);
7993             }else{
7994                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7995             }
7996             return this;
7997         },
7998
7999         /**
8000          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8001          * @param {Number} width The new width
8002          * @param {Number} height The new height
8003          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8004          * @return {Roo.Element} this
8005          */
8006          setSize : function(width, height, animate){
8007             if(typeof width == "object"){ // in case of object from getSize()
8008                 height = width.height; width = width.width;
8009             }
8010             width = this.adjustWidth(width); height = this.adjustHeight(height);
8011             if(!animate || !A){
8012                 this.dom.style.width = this.addUnits(width);
8013                 this.dom.style.height = this.addUnits(height);
8014             }else{
8015                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8016             }
8017             return this;
8018         },
8019
8020         /**
8021          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8022          * @param {Number} x X value for new position (coordinates are page-based)
8023          * @param {Number} y Y value for new position (coordinates are page-based)
8024          * @param {Number} width The new width
8025          * @param {Number} height The new height
8026          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8027          * @return {Roo.Element} this
8028          */
8029         setBounds : function(x, y, width, height, animate){
8030             if(!animate || !A){
8031                 this.setSize(width, height);
8032                 this.setLocation(x, y);
8033             }else{
8034                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8035                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8036                               this.preanim(arguments, 4), 'motion');
8037             }
8038             return this;
8039         },
8040
8041         /**
8042          * 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.
8043          * @param {Roo.lib.Region} region The region to fill
8044          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8045          * @return {Roo.Element} this
8046          */
8047         setRegion : function(region, animate){
8048             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8049             return this;
8050         },
8051
8052         /**
8053          * Appends an event handler
8054          *
8055          * @param {String}   eventName     The type of event to append
8056          * @param {Function} fn        The method the event invokes
8057          * @param {Object} scope       (optional) The scope (this object) of the fn
8058          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8059          */
8060         addListener : function(eventName, fn, scope, options){
8061             if (this.dom) {
8062                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8063             }
8064         },
8065
8066         /**
8067          * Removes an event handler from this element
8068          * @param {String} eventName the type of event to remove
8069          * @param {Function} fn the method the event invokes
8070          * @return {Roo.Element} this
8071          */
8072         removeListener : function(eventName, fn){
8073             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8074             return this;
8075         },
8076
8077         /**
8078          * Removes all previous added listeners from this element
8079          * @return {Roo.Element} this
8080          */
8081         removeAllListeners : function(){
8082             E.purgeElement(this.dom);
8083             return this;
8084         },
8085
8086         relayEvent : function(eventName, observable){
8087             this.on(eventName, function(e){
8088                 observable.fireEvent(eventName, e);
8089             });
8090         },
8091
8092         /**
8093          * Set the opacity of the element
8094          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8095          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8096          * @return {Roo.Element} this
8097          */
8098          setOpacity : function(opacity, animate){
8099             if(!animate || !A){
8100                 var s = this.dom.style;
8101                 if(Roo.isIE){
8102                     s.zoom = 1;
8103                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8104                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8105                 }else{
8106                     s.opacity = opacity;
8107                 }
8108             }else{
8109                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8110             }
8111             return this;
8112         },
8113
8114         /**
8115          * Gets the left X coordinate
8116          * @param {Boolean} local True to get the local css position instead of page coordinate
8117          * @return {Number}
8118          */
8119         getLeft : function(local){
8120             if(!local){
8121                 return this.getX();
8122             }else{
8123                 
8124                 return parseInt(this.getStyle("left"), 10) || 0;
8125                 
8126 //                var x = this.getStyle("left");
8127 //                
8128 //                if(!x || x === 'AUTO'){
8129 //                    return 0;
8130 //                }
8131 //                
8132 //                if(this.pxReg.test(x)){
8133 //                    return parseFloat(x);
8134 //                }
8135 //                
8136 //                x = this.getX();
8137 //                
8138 //                var  par = this.dom.offsetParent ? Roo.fly(this.dom.offsetParent) : false;
8139 //                
8140 //                 if (par !== false) {
8141 //                    x -= par.getX();
8142 //                }
8143 //
8144 //                return x;
8145             }
8146         },
8147
8148         /**
8149          * Gets the right X coordinate of the element (element X position + element width)
8150          * @param {Boolean} local True to get the local css position instead of page coordinate
8151          * @return {Number}
8152          */
8153         getRight : function(local){
8154             if(!local){
8155                 return this.getX() + this.getWidth();
8156             }else{
8157                 return (this.getLeft(true) + this.getWidth()) || 0;
8158             }
8159         },
8160
8161         /**
8162          * Gets the top Y coordinate
8163          * @param {Boolean} local True to get the local css position instead of page coordinate
8164          * @return {Number}
8165          */
8166         getTop : function(local) {
8167             if(!local){
8168                 return this.getY();
8169             }else{
8170                 return parseInt(this.getStyle("top"), 10) || 0;
8171             }
8172         },
8173
8174         /**
8175          * Gets the bottom Y coordinate of the element (element Y position + element height)
8176          * @param {Boolean} local True to get the local css position instead of page coordinate
8177          * @return {Number}
8178          */
8179         getBottom : function(local){
8180             if(!local){
8181                 return this.getY() + this.getHeight();
8182             }else{
8183                 return (this.getTop(true) + this.getHeight()) || 0;
8184             }
8185         },
8186
8187         /**
8188         * Initializes positioning on this element. If a desired position is not passed, it will make the
8189         * the element positioned relative IF it is not already positioned.
8190         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8191         * @param {Number} zIndex (optional) The zIndex to apply
8192         * @param {Number} x (optional) Set the page X position
8193         * @param {Number} y (optional) Set the page Y position
8194         */
8195         position : function(pos, zIndex, x, y){
8196             if(!pos){
8197                if(this.getStyle('position') == 'static'){
8198                    this.setStyle('position', 'relative');
8199                }
8200             }else{
8201                 this.setStyle("position", pos);
8202             }
8203             if(zIndex){
8204                 this.setStyle("z-index", zIndex);
8205             }
8206             if(x !== undefined && y !== undefined){
8207                 this.setXY([x, y]);
8208             }else if(x !== undefined){
8209                 this.setX(x);
8210             }else if(y !== undefined){
8211                 this.setY(y);
8212             }
8213         },
8214
8215         /**
8216         * Clear positioning back to the default when the document was loaded
8217         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8218         * @return {Roo.Element} this
8219          */
8220         clearPositioning : function(value){
8221             value = value ||'';
8222             this.setStyle({
8223                 "left": value,
8224                 "right": value,
8225                 "top": value,
8226                 "bottom": value,
8227                 "z-index": "",
8228                 "position" : "static"
8229             });
8230             return this;
8231         },
8232
8233         /**
8234         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8235         * snapshot before performing an update and then restoring the element.
8236         * @return {Object}
8237         */
8238         getPositioning : function(){
8239             var l = this.getStyle("left");
8240             var t = this.getStyle("top");
8241             return {
8242                 "position" : this.getStyle("position"),
8243                 "left" : l,
8244                 "right" : l ? "" : this.getStyle("right"),
8245                 "top" : t,
8246                 "bottom" : t ? "" : this.getStyle("bottom"),
8247                 "z-index" : this.getStyle("z-index")
8248             };
8249         },
8250
8251         /**
8252          * Gets the width of the border(s) for the specified side(s)
8253          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8254          * passing lr would get the border (l)eft width + the border (r)ight width.
8255          * @return {Number} The width of the sides passed added together
8256          */
8257         getBorderWidth : function(side){
8258             return this.addStyles(side, El.borders);
8259         },
8260
8261         /**
8262          * Gets the width of the padding(s) for the specified side(s)
8263          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8264          * passing lr would get the padding (l)eft + the padding (r)ight.
8265          * @return {Number} The padding of the sides passed added together
8266          */
8267         getPadding : function(side){
8268             return this.addStyles(side, El.paddings);
8269         },
8270
8271         /**
8272         * Set positioning with an object returned by getPositioning().
8273         * @param {Object} posCfg
8274         * @return {Roo.Element} this
8275          */
8276         setPositioning : function(pc){
8277             this.applyStyles(pc);
8278             if(pc.right == "auto"){
8279                 this.dom.style.right = "";
8280             }
8281             if(pc.bottom == "auto"){
8282                 this.dom.style.bottom = "";
8283             }
8284             return this;
8285         },
8286
8287         // private
8288         fixDisplay : function(){
8289             if(this.getStyle("display") == "none"){
8290                 this.setStyle("visibility", "hidden");
8291                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8292                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8293                     this.setStyle("display", "block");
8294                 }
8295             }
8296         },
8297
8298         /**
8299          * Quick set left and top adding default units
8300          * @param {String} left The left CSS property value
8301          * @param {String} top The top CSS property value
8302          * @return {Roo.Element} this
8303          */
8304          setLeftTop : function(left, top){
8305             this.dom.style.left = this.addUnits(left);
8306             this.dom.style.top = this.addUnits(top);
8307             return this;
8308         },
8309
8310         /**
8311          * Move this element relative to its current position.
8312          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8313          * @param {Number} distance How far to move the element in pixels
8314          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8315          * @return {Roo.Element} this
8316          */
8317          move : function(direction, distance, animate){
8318             var xy = this.getXY();
8319             direction = direction.toLowerCase();
8320             switch(direction){
8321                 case "l":
8322                 case "left":
8323                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8324                     break;
8325                case "r":
8326                case "right":
8327                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8328                     break;
8329                case "t":
8330                case "top":
8331                case "up":
8332                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8333                     break;
8334                case "b":
8335                case "bottom":
8336                case "down":
8337                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8338                     break;
8339             }
8340             return this;
8341         },
8342
8343         /**
8344          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8345          * @return {Roo.Element} this
8346          */
8347         clip : function(){
8348             if(!this.isClipped){
8349                this.isClipped = true;
8350                this.originalClip = {
8351                    "o": this.getStyle("overflow"),
8352                    "x": this.getStyle("overflow-x"),
8353                    "y": this.getStyle("overflow-y")
8354                };
8355                this.setStyle("overflow", "hidden");
8356                this.setStyle("overflow-x", "hidden");
8357                this.setStyle("overflow-y", "hidden");
8358             }
8359             return this;
8360         },
8361
8362         /**
8363          *  Return clipping (overflow) to original clipping before clip() was called
8364          * @return {Roo.Element} this
8365          */
8366         unclip : function(){
8367             if(this.isClipped){
8368                 this.isClipped = false;
8369                 var o = this.originalClip;
8370                 if(o.o){this.setStyle("overflow", o.o);}
8371                 if(o.x){this.setStyle("overflow-x", o.x);}
8372                 if(o.y){this.setStyle("overflow-y", o.y);}
8373             }
8374             return this;
8375         },
8376
8377
8378         /**
8379          * Gets the x,y coordinates specified by the anchor position on the element.
8380          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8381          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8382          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8383          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8384          * @return {Array} [x, y] An array containing the element's x and y coordinates
8385          */
8386         getAnchorXY : function(anchor, local, s){
8387             //Passing a different size is useful for pre-calculating anchors,
8388             //especially for anchored animations that change the el size.
8389
8390             var w, h, vp = false;
8391             if(!s){
8392                 var d = this.dom;
8393                 if(d == document.body || d == document){
8394                     vp = true;
8395                     w = D.getViewWidth(); h = D.getViewHeight();
8396                 }else{
8397                     w = this.getWidth(); h = this.getHeight();
8398                 }
8399             }else{
8400                 w = s.width;  h = s.height;
8401             }
8402             var x = 0, y = 0, r = Math.round;
8403             switch((anchor || "tl").toLowerCase()){
8404                 case "c":
8405                     x = r(w*.5);
8406                     y = r(h*.5);
8407                 break;
8408                 case "t":
8409                     x = r(w*.5);
8410                     y = 0;
8411                 break;
8412                 case "l":
8413                     x = 0;
8414                     y = r(h*.5);
8415                 break;
8416                 case "r":
8417                     x = w;
8418                     y = r(h*.5);
8419                 break;
8420                 case "b":
8421                     x = r(w*.5);
8422                     y = h;
8423                 break;
8424                 case "tl":
8425                     x = 0;
8426                     y = 0;
8427                 break;
8428                 case "bl":
8429                     x = 0;
8430                     y = h;
8431                 break;
8432                 case "br":
8433                     x = w;
8434                     y = h;
8435                 break;
8436                 case "tr":
8437                     x = w;
8438                     y = 0;
8439                 break;
8440             }
8441             if(local === true){
8442                 return [x, y];
8443             }
8444             if(vp){
8445                 var sc = this.getScroll();
8446                 return [x + sc.left, y + sc.top];
8447             }
8448             //Add the element's offset xy
8449             var o = this.getXY();
8450             return [x+o[0], y+o[1]];
8451         },
8452
8453         /**
8454          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8455          * supported position values.
8456          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8457          * @param {String} position The position to align to.
8458          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8459          * @return {Array} [x, y]
8460          */
8461         getAlignToXY : function(el, p, o){
8462             el = Roo.get(el);
8463             var d = this.dom;
8464             if(!el.dom){
8465                 throw "Element.alignTo with an element that doesn't exist";
8466             }
8467             var c = false; //constrain to viewport
8468             var p1 = "", p2 = "";
8469             o = o || [0,0];
8470
8471             if(!p){
8472                 p = "tl-bl";
8473             }else if(p == "?"){
8474                 p = "tl-bl?";
8475             }else if(p.indexOf("-") == -1){
8476                 p = "tl-" + p;
8477             }
8478             p = p.toLowerCase();
8479             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8480             if(!m){
8481                throw "Element.alignTo with an invalid alignment " + p;
8482             }
8483             p1 = m[1]; p2 = m[2]; c = !!m[3];
8484
8485             //Subtract the aligned el's internal xy from the target's offset xy
8486             //plus custom offset to get the aligned el's new offset xy
8487             var a1 = this.getAnchorXY(p1, true);
8488             var a2 = el.getAnchorXY(p2, false);
8489             var x = a2[0] - a1[0] + o[0];
8490             var y = a2[1] - a1[1] + o[1];
8491             if(c){
8492                 //constrain the aligned el to viewport if necessary
8493                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8494                 // 5px of margin for ie
8495                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8496
8497                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8498                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8499                 //otherwise swap the aligned el to the opposite border of the target.
8500                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8501                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8502                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8503                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8504
8505                var doc = document;
8506                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8507                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8508
8509                if((x+w) > dw + scrollX){
8510                     x = swapX ? r.left-w : dw+scrollX-w;
8511                 }
8512                if(x < scrollX){
8513                    x = swapX ? r.right : scrollX;
8514                }
8515                if((y+h) > dh + scrollY){
8516                     y = swapY ? r.top-h : dh+scrollY-h;
8517                 }
8518                if (y < scrollY){
8519                    y = swapY ? r.bottom : scrollY;
8520                }
8521             }
8522             return [x,y];
8523         },
8524
8525         // private
8526         getConstrainToXY : function(){
8527             var os = {top:0, left:0, bottom:0, right: 0};
8528
8529             return function(el, local, offsets, proposedXY){
8530                 el = Roo.get(el);
8531                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8532
8533                 var vw, vh, vx = 0, vy = 0;
8534                 if(el.dom == document.body || el.dom == document){
8535                     vw = Roo.lib.Dom.getViewWidth();
8536                     vh = Roo.lib.Dom.getViewHeight();
8537                 }else{
8538                     vw = el.dom.clientWidth;
8539                     vh = el.dom.clientHeight;
8540                     if(!local){
8541                         var vxy = el.getXY();
8542                         vx = vxy[0];
8543                         vy = vxy[1];
8544                     }
8545                 }
8546
8547                 var s = el.getScroll();
8548
8549                 vx += offsets.left + s.left;
8550                 vy += offsets.top + s.top;
8551
8552                 vw -= offsets.right;
8553                 vh -= offsets.bottom;
8554
8555                 var vr = vx+vw;
8556                 var vb = vy+vh;
8557
8558                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8559                 var x = xy[0], y = xy[1];
8560                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8561
8562                 // only move it if it needs it
8563                 var moved = false;
8564
8565                 // first validate right/bottom
8566                 if((x + w) > vr){
8567                     x = vr - w;
8568                     moved = true;
8569                 }
8570                 if((y + h) > vb){
8571                     y = vb - h;
8572                     moved = true;
8573                 }
8574                 // then make sure top/left isn't negative
8575                 if(x < vx){
8576                     x = vx;
8577                     moved = true;
8578                 }
8579                 if(y < vy){
8580                     y = vy;
8581                     moved = true;
8582                 }
8583                 return moved ? [x, y] : false;
8584             };
8585         }(),
8586
8587         // private
8588         adjustForConstraints : function(xy, parent, offsets){
8589             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8590         },
8591
8592         /**
8593          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8594          * document it aligns it to the viewport.
8595          * The position parameter is optional, and can be specified in any one of the following formats:
8596          * <ul>
8597          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8598          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8599          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8600          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8601          *   <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
8602          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8603          * </ul>
8604          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8605          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8606          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8607          * that specified in order to enforce the viewport constraints.
8608          * Following are all of the supported anchor positions:
8609     <pre>
8610     Value  Description
8611     -----  -----------------------------
8612     tl     The top left corner (default)
8613     t      The center of the top edge
8614     tr     The top right corner
8615     l      The center of the left edge
8616     c      In the center of the element
8617     r      The center of the right edge
8618     bl     The bottom left corner
8619     b      The center of the bottom edge
8620     br     The bottom right corner
8621     </pre>
8622     Example Usage:
8623     <pre><code>
8624     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8625     el.alignTo("other-el");
8626
8627     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8628     el.alignTo("other-el", "tr?");
8629
8630     // align the bottom right corner of el with the center left edge of other-el
8631     el.alignTo("other-el", "br-l?");
8632
8633     // align the center of el with the bottom left corner of other-el and
8634     // adjust the x position by -6 pixels (and the y position by 0)
8635     el.alignTo("other-el", "c-bl", [-6, 0]);
8636     </code></pre>
8637          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8638          * @param {String} position The position to align to.
8639          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8640          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8641          * @return {Roo.Element} this
8642          */
8643         alignTo : function(element, position, offsets, animate){
8644             var xy = this.getAlignToXY(element, position, offsets);
8645             this.setXY(xy, this.preanim(arguments, 3));
8646             return this;
8647         },
8648
8649         /**
8650          * Anchors an element to another element and realigns it when the window is resized.
8651          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8652          * @param {String} position The position to align to.
8653          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8654          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8655          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8656          * is a number, it is used as the buffer delay (defaults to 50ms).
8657          * @param {Function} callback The function to call after the animation finishes
8658          * @return {Roo.Element} this
8659          */
8660         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8661             var action = function(){
8662                 this.alignTo(el, alignment, offsets, animate);
8663                 Roo.callback(callback, this);
8664             };
8665             Roo.EventManager.onWindowResize(action, this);
8666             var tm = typeof monitorScroll;
8667             if(tm != 'undefined'){
8668                 Roo.EventManager.on(window, 'scroll', action, this,
8669                     {buffer: tm == 'number' ? monitorScroll : 50});
8670             }
8671             action.call(this); // align immediately
8672             return this;
8673         },
8674         /**
8675          * Clears any opacity settings from this element. Required in some cases for IE.
8676          * @return {Roo.Element} this
8677          */
8678         clearOpacity : function(){
8679             if (window.ActiveXObject) {
8680                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8681                     this.dom.style.filter = "";
8682                 }
8683             } else {
8684                 this.dom.style.opacity = "";
8685                 this.dom.style["-moz-opacity"] = "";
8686                 this.dom.style["-khtml-opacity"] = "";
8687             }
8688             return this;
8689         },
8690
8691         /**
8692          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8693          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8694          * @return {Roo.Element} this
8695          */
8696         hide : function(animate){
8697             this.setVisible(false, this.preanim(arguments, 0));
8698             return this;
8699         },
8700
8701         /**
8702         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8703         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8704          * @return {Roo.Element} this
8705          */
8706         show : function(animate){
8707             this.setVisible(true, this.preanim(arguments, 0));
8708             return this;
8709         },
8710
8711         /**
8712          * @private Test if size has a unit, otherwise appends the default
8713          */
8714         addUnits : function(size){
8715             return Roo.Element.addUnits(size, this.defaultUnit);
8716         },
8717
8718         /**
8719          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8720          * @return {Roo.Element} this
8721          */
8722         beginMeasure : function(){
8723             var el = this.dom;
8724             if(el.offsetWidth || el.offsetHeight){
8725                 return this; // offsets work already
8726             }
8727             var changed = [];
8728             var p = this.dom, b = document.body; // start with this element
8729             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8730                 var pe = Roo.get(p);
8731                 if(pe.getStyle('display') == 'none'){
8732                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8733                     p.style.visibility = "hidden";
8734                     p.style.display = "block";
8735                 }
8736                 p = p.parentNode;
8737             }
8738             this._measureChanged = changed;
8739             return this;
8740
8741         },
8742
8743         /**
8744          * Restores displays to before beginMeasure was called
8745          * @return {Roo.Element} this
8746          */
8747         endMeasure : function(){
8748             var changed = this._measureChanged;
8749             if(changed){
8750                 for(var i = 0, len = changed.length; i < len; i++) {
8751                     var r = changed[i];
8752                     r.el.style.visibility = r.visibility;
8753                     r.el.style.display = "none";
8754                 }
8755                 this._measureChanged = null;
8756             }
8757             return this;
8758         },
8759
8760         /**
8761         * Update the innerHTML of this element, optionally searching for and processing scripts
8762         * @param {String} html The new HTML
8763         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8764         * @param {Function} callback For async script loading you can be noticed when the update completes
8765         * @return {Roo.Element} this
8766          */
8767         update : function(html, loadScripts, callback){
8768             if(typeof html == "undefined"){
8769                 html = "";
8770             }
8771             if(loadScripts !== true){
8772                 this.dom.innerHTML = html;
8773                 if(typeof callback == "function"){
8774                     callback();
8775                 }
8776                 return this;
8777             }
8778             var id = Roo.id();
8779             var dom = this.dom;
8780
8781             html += '<span id="' + id + '"></span>';
8782
8783             E.onAvailable(id, function(){
8784                 var hd = document.getElementsByTagName("head")[0];
8785                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8786                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8787                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8788
8789                 var match;
8790                 while(match = re.exec(html)){
8791                     var attrs = match[1];
8792                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8793                     if(srcMatch && srcMatch[2]){
8794                        var s = document.createElement("script");
8795                        s.src = srcMatch[2];
8796                        var typeMatch = attrs.match(typeRe);
8797                        if(typeMatch && typeMatch[2]){
8798                            s.type = typeMatch[2];
8799                        }
8800                        hd.appendChild(s);
8801                     }else if(match[2] && match[2].length > 0){
8802                         if(window.execScript) {
8803                            window.execScript(match[2]);
8804                         } else {
8805                             /**
8806                              * eval:var:id
8807                              * eval:var:dom
8808                              * eval:var:html
8809                              * 
8810                              */
8811                            window.eval(match[2]);
8812                         }
8813                     }
8814                 }
8815                 var el = document.getElementById(id);
8816                 if(el){el.parentNode.removeChild(el);}
8817                 if(typeof callback == "function"){
8818                     callback();
8819                 }
8820             });
8821             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8822             return this;
8823         },
8824
8825         /**
8826          * Direct access to the UpdateManager update() method (takes the same parameters).
8827          * @param {String/Function} url The url for this request or a function to call to get the url
8828          * @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}
8829          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8830          * @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.
8831          * @return {Roo.Element} this
8832          */
8833         load : function(){
8834             var um = this.getUpdateManager();
8835             um.update.apply(um, arguments);
8836             return this;
8837         },
8838
8839         /**
8840         * Gets this element's UpdateManager
8841         * @return {Roo.UpdateManager} The UpdateManager
8842         */
8843         getUpdateManager : function(){
8844             if(!this.updateManager){
8845                 this.updateManager = new Roo.UpdateManager(this);
8846             }
8847             return this.updateManager;
8848         },
8849
8850         /**
8851          * Disables text selection for this element (normalized across browsers)
8852          * @return {Roo.Element} this
8853          */
8854         unselectable : function(){
8855             this.dom.unselectable = "on";
8856             this.swallowEvent("selectstart", true);
8857             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8858             this.addClass("x-unselectable");
8859             return this;
8860         },
8861
8862         /**
8863         * Calculates the x, y to center this element on the screen
8864         * @return {Array} The x, y values [x, y]
8865         */
8866         getCenterXY : function(){
8867             return this.getAlignToXY(document, 'c-c');
8868         },
8869
8870         /**
8871         * Centers the Element in either the viewport, or another Element.
8872         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8873         */
8874         center : function(centerIn){
8875             this.alignTo(centerIn || document, 'c-c');
8876             return this;
8877         },
8878
8879         /**
8880          * Tests various css rules/browsers to determine if this element uses a border box
8881          * @return {Boolean}
8882          */
8883         isBorderBox : function(){
8884             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8885         },
8886
8887         /**
8888          * Return a box {x, y, width, height} that can be used to set another elements
8889          * size/location to match this element.
8890          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8891          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8892          * @return {Object} box An object in the format {x, y, width, height}
8893          */
8894         getBox : function(contentBox, local){
8895             var xy;
8896             if(!local){
8897                 xy = this.getXY();
8898             }else{
8899                 var left = parseInt(this.getStyle("left"), 10) || 0;
8900                 var top = parseInt(this.getStyle("top"), 10) || 0;
8901                 xy = [left, top];
8902             }
8903             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8904             if(!contentBox){
8905                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8906             }else{
8907                 var l = this.getBorderWidth("l")+this.getPadding("l");
8908                 var r = this.getBorderWidth("r")+this.getPadding("r");
8909                 var t = this.getBorderWidth("t")+this.getPadding("t");
8910                 var b = this.getBorderWidth("b")+this.getPadding("b");
8911                 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)};
8912             }
8913             bx.right = bx.x + bx.width;
8914             bx.bottom = bx.y + bx.height;
8915             return bx;
8916         },
8917
8918         /**
8919          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8920          for more information about the sides.
8921          * @param {String} sides
8922          * @return {Number}
8923          */
8924         getFrameWidth : function(sides, onlyContentBox){
8925             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8926         },
8927
8928         /**
8929          * 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.
8930          * @param {Object} box The box to fill {x, y, width, height}
8931          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8932          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8933          * @return {Roo.Element} this
8934          */
8935         setBox : function(box, adjust, animate){
8936             var w = box.width, h = box.height;
8937             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8938                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8939                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8940             }
8941             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8942             return this;
8943         },
8944
8945         /**
8946          * Forces the browser to repaint this element
8947          * @return {Roo.Element} this
8948          */
8949          repaint : function(){
8950             var dom = this.dom;
8951             this.addClass("x-repaint");
8952             setTimeout(function(){
8953                 Roo.get(dom).removeClass("x-repaint");
8954             }, 1);
8955             return this;
8956         },
8957
8958         /**
8959          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8960          * then it returns the calculated width of the sides (see getPadding)
8961          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8962          * @return {Object/Number}
8963          */
8964         getMargins : function(side){
8965             if(!side){
8966                 return {
8967                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8968                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8969                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8970                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8971                 };
8972             }else{
8973                 return this.addStyles(side, El.margins);
8974              }
8975         },
8976
8977         // private
8978         addStyles : function(sides, styles){
8979             var val = 0, v, w;
8980             for(var i = 0, len = sides.length; i < len; i++){
8981                 v = this.getStyle(styles[sides.charAt(i)]);
8982                 if(v){
8983                      w = parseInt(v, 10);
8984                      if(w){ val += w; }
8985                 }
8986             }
8987             return val;
8988         },
8989
8990         /**
8991          * Creates a proxy element of this element
8992          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8993          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8994          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8995          * @return {Roo.Element} The new proxy element
8996          */
8997         createProxy : function(config, renderTo, matchBox){
8998             if(renderTo){
8999                 renderTo = Roo.getDom(renderTo);
9000             }else{
9001                 renderTo = document.body;
9002             }
9003             config = typeof config == "object" ?
9004                 config : {tag : "div", cls: config};
9005             var proxy = Roo.DomHelper.append(renderTo, config, true);
9006             if(matchBox){
9007                proxy.setBox(this.getBox());
9008             }
9009             return proxy;
9010         },
9011
9012         /**
9013          * Puts a mask over this element to disable user interaction. Requires core.css.
9014          * This method can only be applied to elements which accept child nodes.
9015          * @param {String} msg (optional) A message to display in the mask
9016          * @param {String} msgCls (optional) A css class to apply to the msg element
9017          * @return {Element} The mask  element
9018          */
9019         mask : function(msg, msgCls)
9020         {
9021             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9022                 this.setStyle("position", "relative");
9023             }
9024             if(!this._mask){
9025                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9026             }
9027             this.addClass("x-masked");
9028             this._mask.setDisplayed(true);
9029             
9030             // we wander
9031             var z = 0;
9032             var dom = this.dom
9033             while (dom && dom.style) {
9034                 if (!isNaN(parseInt(dom.style.zIndex))) {
9035                     z = Math.max(z, parseInt(dom.style.zIndex));
9036                 }
9037                 dom = dom.parentNode;
9038             }
9039             // if we are masking the body - then it hides everything..
9040             if (this.dom == document.body) {
9041                 z = 1000000;
9042                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9043                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9044             }
9045            
9046             if(typeof msg == 'string'){
9047                 if(!this._maskMsg){
9048                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9049                 }
9050                 var mm = this._maskMsg;
9051                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9052                 if (mm.dom.firstChild) { // weird IE issue?
9053                     mm.dom.firstChild.innerHTML = msg;
9054                 }
9055                 mm.setDisplayed(true);
9056                 mm.center(this);
9057                 mm.setStyle('z-index', z + 102);
9058             }
9059             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9060                 this._mask.setHeight(this.getHeight());
9061             }
9062             this._mask.setStyle('z-index', z + 100);
9063             
9064             return this._mask;
9065         },
9066
9067         /**
9068          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9069          * it is cached for reuse.
9070          */
9071         unmask : function(removeEl){
9072             if(this._mask){
9073                 if(removeEl === true){
9074                     this._mask.remove();
9075                     delete this._mask;
9076                     if(this._maskMsg){
9077                         this._maskMsg.remove();
9078                         delete this._maskMsg;
9079                     }
9080                 }else{
9081                     this._mask.setDisplayed(false);
9082                     if(this._maskMsg){
9083                         this._maskMsg.setDisplayed(false);
9084                     }
9085                 }
9086             }
9087             this.removeClass("x-masked");
9088         },
9089
9090         /**
9091          * Returns true if this element is masked
9092          * @return {Boolean}
9093          */
9094         isMasked : function(){
9095             return this._mask && this._mask.isVisible();
9096         },
9097
9098         /**
9099          * Creates an iframe shim for this element to keep selects and other windowed objects from
9100          * showing through.
9101          * @return {Roo.Element} The new shim element
9102          */
9103         createShim : function(){
9104             var el = document.createElement('iframe');
9105             el.frameBorder = 'no';
9106             el.className = 'roo-shim';
9107             if(Roo.isIE && Roo.isSecure){
9108                 el.src = Roo.SSL_SECURE_URL;
9109             }
9110             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9111             shim.autoBoxAdjust = false;
9112             return shim;
9113         },
9114
9115         /**
9116          * Removes this element from the DOM and deletes it from the cache
9117          */
9118         remove : function(){
9119             if(this.dom.parentNode){
9120                 this.dom.parentNode.removeChild(this.dom);
9121             }
9122             delete El.cache[this.dom.id];
9123         },
9124
9125         /**
9126          * Sets up event handlers to add and remove a css class when the mouse is over this element
9127          * @param {String} className
9128          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9129          * mouseout events for children elements
9130          * @return {Roo.Element} this
9131          */
9132         addClassOnOver : function(className, preventFlicker){
9133             this.on("mouseover", function(){
9134                 Roo.fly(this, '_internal').addClass(className);
9135             }, this.dom);
9136             var removeFn = function(e){
9137                 if(preventFlicker !== true || !e.within(this, true)){
9138                     Roo.fly(this, '_internal').removeClass(className);
9139                 }
9140             };
9141             this.on("mouseout", removeFn, this.dom);
9142             return this;
9143         },
9144
9145         /**
9146          * Sets up event handlers to add and remove a css class when this element has the focus
9147          * @param {String} className
9148          * @return {Roo.Element} this
9149          */
9150         addClassOnFocus : function(className){
9151             this.on("focus", function(){
9152                 Roo.fly(this, '_internal').addClass(className);
9153             }, this.dom);
9154             this.on("blur", function(){
9155                 Roo.fly(this, '_internal').removeClass(className);
9156             }, this.dom);
9157             return this;
9158         },
9159         /**
9160          * 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)
9161          * @param {String} className
9162          * @return {Roo.Element} this
9163          */
9164         addClassOnClick : function(className){
9165             var dom = this.dom;
9166             this.on("mousedown", function(){
9167                 Roo.fly(dom, '_internal').addClass(className);
9168                 var d = Roo.get(document);
9169                 var fn = function(){
9170                     Roo.fly(dom, '_internal').removeClass(className);
9171                     d.removeListener("mouseup", fn);
9172                 };
9173                 d.on("mouseup", fn);
9174             });
9175             return this;
9176         },
9177
9178         /**
9179          * Stops the specified event from bubbling and optionally prevents the default action
9180          * @param {String} eventName
9181          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9182          * @return {Roo.Element} this
9183          */
9184         swallowEvent : function(eventName, preventDefault){
9185             var fn = function(e){
9186                 e.stopPropagation();
9187                 if(preventDefault){
9188                     e.preventDefault();
9189                 }
9190             };
9191             if(eventName instanceof Array){
9192                 for(var i = 0, len = eventName.length; i < len; i++){
9193                      this.on(eventName[i], fn);
9194                 }
9195                 return this;
9196             }
9197             this.on(eventName, fn);
9198             return this;
9199         },
9200
9201         /**
9202          * @private
9203          */
9204       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9205
9206         /**
9207          * Sizes this element to its parent element's dimensions performing
9208          * neccessary box adjustments.
9209          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9210          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9211          * @return {Roo.Element} this
9212          */
9213         fitToParent : function(monitorResize, targetParent) {
9214           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9215           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9216           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9217             return;
9218           }
9219           var p = Roo.get(targetParent || this.dom.parentNode);
9220           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9221           if (monitorResize === true) {
9222             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9223             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9224           }
9225           return this;
9226         },
9227
9228         /**
9229          * Gets the next sibling, skipping text nodes
9230          * @return {HTMLElement} The next sibling or null
9231          */
9232         getNextSibling : function(){
9233             var n = this.dom.nextSibling;
9234             while(n && n.nodeType != 1){
9235                 n = n.nextSibling;
9236             }
9237             return n;
9238         },
9239
9240         /**
9241          * Gets the previous sibling, skipping text nodes
9242          * @return {HTMLElement} The previous sibling or null
9243          */
9244         getPrevSibling : function(){
9245             var n = this.dom.previousSibling;
9246             while(n && n.nodeType != 1){
9247                 n = n.previousSibling;
9248             }
9249             return n;
9250         },
9251
9252
9253         /**
9254          * Appends the passed element(s) to this element
9255          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9256          * @return {Roo.Element} this
9257          */
9258         appendChild: function(el){
9259             el = Roo.get(el);
9260             el.appendTo(this);
9261             return this;
9262         },
9263
9264         /**
9265          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9266          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9267          * automatically generated with the specified attributes.
9268          * @param {HTMLElement} insertBefore (optional) a child element of this element
9269          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9270          * @return {Roo.Element} The new child element
9271          */
9272         createChild: function(config, insertBefore, returnDom){
9273             config = config || {tag:'div'};
9274             if(insertBefore){
9275                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9276             }
9277             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9278         },
9279
9280         /**
9281          * Appends this element to the passed element
9282          * @param {String/HTMLElement/Element} el The new parent element
9283          * @return {Roo.Element} this
9284          */
9285         appendTo: function(el){
9286             el = Roo.getDom(el);
9287             el.appendChild(this.dom);
9288             return this;
9289         },
9290
9291         /**
9292          * Inserts this element before the passed element in the DOM
9293          * @param {String/HTMLElement/Element} el The element to insert before
9294          * @return {Roo.Element} this
9295          */
9296         insertBefore: function(el){
9297             el = Roo.getDom(el);
9298             el.parentNode.insertBefore(this.dom, el);
9299             return this;
9300         },
9301
9302         /**
9303          * Inserts this element after the passed element in the DOM
9304          * @param {String/HTMLElement/Element} el The element to insert after
9305          * @return {Roo.Element} this
9306          */
9307         insertAfter: function(el){
9308             el = Roo.getDom(el);
9309             el.parentNode.insertBefore(this.dom, el.nextSibling);
9310             return this;
9311         },
9312
9313         /**
9314          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9315          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9316          * @return {Roo.Element} The new child
9317          */
9318         insertFirst: function(el, returnDom){
9319             el = el || {};
9320             if(typeof el == 'object' && !el.nodeType){ // dh config
9321                 return this.createChild(el, this.dom.firstChild, returnDom);
9322             }else{
9323                 el = Roo.getDom(el);
9324                 this.dom.insertBefore(el, this.dom.firstChild);
9325                 return !returnDom ? Roo.get(el) : el;
9326             }
9327         },
9328
9329         /**
9330          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9331          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9332          * @param {String} where (optional) 'before' or 'after' defaults to before
9333          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9334          * @return {Roo.Element} the inserted Element
9335          */
9336         insertSibling: function(el, where, returnDom){
9337             where = where ? where.toLowerCase() : 'before';
9338             el = el || {};
9339             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9340
9341             if(typeof el == 'object' && !el.nodeType){ // dh config
9342                 if(where == 'after' && !this.dom.nextSibling){
9343                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9344                 }else{
9345                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9346                 }
9347
9348             }else{
9349                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9350                             where == 'before' ? this.dom : this.dom.nextSibling);
9351                 if(!returnDom){
9352                     rt = Roo.get(rt);
9353                 }
9354             }
9355             return rt;
9356         },
9357
9358         /**
9359          * Creates and wraps this element with another element
9360          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9361          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9362          * @return {HTMLElement/Element} The newly created wrapper element
9363          */
9364         wrap: function(config, returnDom){
9365             if(!config){
9366                 config = {tag: "div"};
9367             }
9368             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9369             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9370             return newEl;
9371         },
9372
9373         /**
9374          * Replaces the passed element with this element
9375          * @param {String/HTMLElement/Element} el The element to replace
9376          * @return {Roo.Element} this
9377          */
9378         replace: function(el){
9379             el = Roo.get(el);
9380             this.insertBefore(el);
9381             el.remove();
9382             return this;
9383         },
9384
9385         /**
9386          * Inserts an html fragment into this element
9387          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9388          * @param {String} html The HTML fragment
9389          * @param {Boolean} returnEl True to return an Roo.Element
9390          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9391          */
9392         insertHtml : function(where, html, returnEl){
9393             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9394             return returnEl ? Roo.get(el) : el;
9395         },
9396
9397         /**
9398          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9399          * @param {Object} o The object with the attributes
9400          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9401          * @return {Roo.Element} this
9402          */
9403         set : function(o, useSet){
9404             var el = this.dom;
9405             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9406             for(var attr in o){
9407                 if(attr == "style" || typeof o[attr] == "function") continue;
9408                 if(attr=="cls"){
9409                     el.className = o["cls"];
9410                 }else{
9411                     if(useSet) el.setAttribute(attr, o[attr]);
9412                     else el[attr] = o[attr];
9413                 }
9414             }
9415             if(o.style){
9416                 Roo.DomHelper.applyStyles(el, o.style);
9417             }
9418             return this;
9419         },
9420
9421         /**
9422          * Convenience method for constructing a KeyMap
9423          * @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:
9424          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9425          * @param {Function} fn The function to call
9426          * @param {Object} scope (optional) The scope of the function
9427          * @return {Roo.KeyMap} The KeyMap created
9428          */
9429         addKeyListener : function(key, fn, scope){
9430             var config;
9431             if(typeof key != "object" || key instanceof Array){
9432                 config = {
9433                     key: key,
9434                     fn: fn,
9435                     scope: scope
9436                 };
9437             }else{
9438                 config = {
9439                     key : key.key,
9440                     shift : key.shift,
9441                     ctrl : key.ctrl,
9442                     alt : key.alt,
9443                     fn: fn,
9444                     scope: scope
9445                 };
9446             }
9447             return new Roo.KeyMap(this, config);
9448         },
9449
9450         /**
9451          * Creates a KeyMap for this element
9452          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9453          * @return {Roo.KeyMap} The KeyMap created
9454          */
9455         addKeyMap : function(config){
9456             return new Roo.KeyMap(this, config);
9457         },
9458
9459         /**
9460          * Returns true if this element is scrollable.
9461          * @return {Boolean}
9462          */
9463          isScrollable : function(){
9464             var dom = this.dom;
9465             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9466         },
9467
9468         /**
9469          * 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().
9470          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9471          * @param {Number} value The new scroll value
9472          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9473          * @return {Element} this
9474          */
9475
9476         scrollTo : function(side, value, animate){
9477             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9478             if(!animate || !A){
9479                 this.dom[prop] = value;
9480             }else{
9481                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9482                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9483             }
9484             return this;
9485         },
9486
9487         /**
9488          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9489          * within this element's scrollable range.
9490          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9491          * @param {Number} distance How far to scroll the element in pixels
9492          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9493          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9494          * was scrolled as far as it could go.
9495          */
9496          scroll : function(direction, distance, animate){
9497              if(!this.isScrollable()){
9498                  return;
9499              }
9500              var el = this.dom;
9501              var l = el.scrollLeft, t = el.scrollTop;
9502              var w = el.scrollWidth, h = el.scrollHeight;
9503              var cw = el.clientWidth, ch = el.clientHeight;
9504              direction = direction.toLowerCase();
9505              var scrolled = false;
9506              var a = this.preanim(arguments, 2);
9507              switch(direction){
9508                  case "l":
9509                  case "left":
9510                      if(w - l > cw){
9511                          var v = Math.min(l + distance, w-cw);
9512                          this.scrollTo("left", v, a);
9513                          scrolled = true;
9514                      }
9515                      break;
9516                 case "r":
9517                 case "right":
9518                      if(l > 0){
9519                          var v = Math.max(l - distance, 0);
9520                          this.scrollTo("left", v, a);
9521                          scrolled = true;
9522                      }
9523                      break;
9524                 case "t":
9525                 case "top":
9526                 case "up":
9527                      if(t > 0){
9528                          var v = Math.max(t - distance, 0);
9529                          this.scrollTo("top", v, a);
9530                          scrolled = true;
9531                      }
9532                      break;
9533                 case "b":
9534                 case "bottom":
9535                 case "down":
9536                      if(h - t > ch){
9537                          var v = Math.min(t + distance, h-ch);
9538                          this.scrollTo("top", v, a);
9539                          scrolled = true;
9540                      }
9541                      break;
9542              }
9543              return scrolled;
9544         },
9545
9546         /**
9547          * Translates the passed page coordinates into left/top css values for this element
9548          * @param {Number/Array} x The page x or an array containing [x, y]
9549          * @param {Number} y The page y
9550          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9551          */
9552         translatePoints : function(x, y){
9553             if(typeof x == 'object' || x instanceof Array){
9554                 y = x[1]; x = x[0];
9555             }
9556             var p = this.getStyle('position');
9557             var o = this.getXY();
9558
9559             var l = parseInt(this.getStyle('left'), 10);
9560             var t = parseInt(this.getStyle('top'), 10);
9561
9562             if(isNaN(l)){
9563                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9564             }
9565             if(isNaN(t)){
9566                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9567             }
9568
9569             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9570         },
9571
9572         /**
9573          * Returns the current scroll position of the element.
9574          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9575          */
9576         getScroll : function(){
9577             var d = this.dom, doc = document;
9578             if(d == doc || d == doc.body){
9579                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9580                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9581                 return {left: l, top: t};
9582             }else{
9583                 return {left: d.scrollLeft, top: d.scrollTop};
9584             }
9585         },
9586
9587         /**
9588          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9589          * are convert to standard 6 digit hex color.
9590          * @param {String} attr The css attribute
9591          * @param {String} defaultValue The default value to use when a valid color isn't found
9592          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9593          * YUI color anims.
9594          */
9595         getColor : function(attr, defaultValue, prefix){
9596             var v = this.getStyle(attr);
9597             if(!v || v == "transparent" || v == "inherit") {
9598                 return defaultValue;
9599             }
9600             var color = typeof prefix == "undefined" ? "#" : prefix;
9601             if(v.substr(0, 4) == "rgb("){
9602                 var rvs = v.slice(4, v.length -1).split(",");
9603                 for(var i = 0; i < 3; i++){
9604                     var h = parseInt(rvs[i]).toString(16);
9605                     if(h < 16){
9606                         h = "0" + h;
9607                     }
9608                     color += h;
9609                 }
9610             } else {
9611                 if(v.substr(0, 1) == "#"){
9612                     if(v.length == 4) {
9613                         for(var i = 1; i < 4; i++){
9614                             var c = v.charAt(i);
9615                             color +=  c + c;
9616                         }
9617                     }else if(v.length == 7){
9618                         color += v.substr(1);
9619                     }
9620                 }
9621             }
9622             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9623         },
9624
9625         /**
9626          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9627          * gradient background, rounded corners and a 4-way shadow.
9628          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9629          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9630          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9631          * @return {Roo.Element} this
9632          */
9633         boxWrap : function(cls){
9634             cls = cls || 'x-box';
9635             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9636             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9637             return el;
9638         },
9639
9640         /**
9641          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9642          * @param {String} namespace The namespace in which to look for the attribute
9643          * @param {String} name The attribute name
9644          * @return {String} The attribute value
9645          */
9646         getAttributeNS : Roo.isIE ? function(ns, name){
9647             var d = this.dom;
9648             var type = typeof d[ns+":"+name];
9649             if(type != 'undefined' && type != 'unknown'){
9650                 return d[ns+":"+name];
9651             }
9652             return d[name];
9653         } : function(ns, name){
9654             var d = this.dom;
9655             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9656         },
9657         
9658         
9659         /**
9660          * Sets or Returns the value the dom attribute value
9661          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9662          * @param {String} value (optional) The value to set the attribute to
9663          * @return {String} The attribute value
9664          */
9665         attr : function(name){
9666             if (arguments.length > 1) {
9667                 this.dom.setAttribute(name, arguments[1]);
9668                 return arguments[1];
9669             }
9670             if (typeof(name) == 'object') {
9671                 for(var i in name) {
9672                     this.attr(i, name[i]);
9673                 }
9674                 return name;
9675             }
9676             
9677             
9678             if (!this.dom.hasAttribute(name)) {
9679                 return undefined;
9680             }
9681             return this.dom.getAttribute(name);
9682         }
9683         
9684         
9685         
9686     };
9687
9688     var ep = El.prototype;
9689
9690     /**
9691      * Appends an event handler (Shorthand for addListener)
9692      * @param {String}   eventName     The type of event to append
9693      * @param {Function} fn        The method the event invokes
9694      * @param {Object} scope       (optional) The scope (this object) of the fn
9695      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9696      * @method
9697      */
9698     ep.on = ep.addListener;
9699         // backwards compat
9700     ep.mon = ep.addListener;
9701
9702     /**
9703      * Removes an event handler from this element (shorthand for removeListener)
9704      * @param {String} eventName the type of event to remove
9705      * @param {Function} fn the method the event invokes
9706      * @return {Roo.Element} this
9707      * @method
9708      */
9709     ep.un = ep.removeListener;
9710
9711     /**
9712      * true to automatically adjust width and height settings for box-model issues (default to true)
9713      */
9714     ep.autoBoxAdjust = true;
9715
9716     // private
9717     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9718
9719     // private
9720     El.addUnits = function(v, defaultUnit){
9721         if(v === "" || v == "auto"){
9722             return v;
9723         }
9724         if(v === undefined){
9725             return '';
9726         }
9727         if(typeof v == "number" || !El.unitPattern.test(v)){
9728             return v + (defaultUnit || 'px');
9729         }
9730         return v;
9731     };
9732
9733     // special markup used throughout Roo when box wrapping elements
9734     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>';
9735     /**
9736      * Visibility mode constant - Use visibility to hide element
9737      * @static
9738      * @type Number
9739      */
9740     El.VISIBILITY = 1;
9741     /**
9742      * Visibility mode constant - Use display to hide element
9743      * @static
9744      * @type Number
9745      */
9746     El.DISPLAY = 2;
9747
9748     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9749     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9750     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9751
9752
9753
9754     /**
9755      * @private
9756      */
9757     El.cache = {};
9758
9759     var docEl;
9760
9761     /**
9762      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9763      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9764      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9765      * @return {Element} The Element object
9766      * @static
9767      */
9768     El.get = function(el){
9769         var ex, elm, id;
9770         if(!el){ return null; }
9771         if(typeof el == "string"){ // element id
9772             if(!(elm = document.getElementById(el))){
9773                 return null;
9774             }
9775             if(ex = El.cache[el]){
9776                 ex.dom = elm;
9777             }else{
9778                 ex = El.cache[el] = new El(elm);
9779             }
9780             return ex;
9781         }else if(el.tagName){ // dom element
9782             if(!(id = el.id)){
9783                 id = Roo.id(el);
9784             }
9785             if(ex = El.cache[id]){
9786                 ex.dom = el;
9787             }else{
9788                 ex = El.cache[id] = new El(el);
9789             }
9790             return ex;
9791         }else if(el instanceof El){
9792             if(el != docEl){
9793                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9794                                                               // catch case where it hasn't been appended
9795                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9796             }
9797             return el;
9798         }else if(el.isComposite){
9799             return el;
9800         }else if(el instanceof Array){
9801             return El.select(el);
9802         }else if(el == document){
9803             // create a bogus element object representing the document object
9804             if(!docEl){
9805                 var f = function(){};
9806                 f.prototype = El.prototype;
9807                 docEl = new f();
9808                 docEl.dom = document;
9809             }
9810             return docEl;
9811         }
9812         return null;
9813     };
9814
9815     // private
9816     El.uncache = function(el){
9817         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9818             if(a[i]){
9819                 delete El.cache[a[i].id || a[i]];
9820             }
9821         }
9822     };
9823
9824     // private
9825     // Garbage collection - uncache elements/purge listeners on orphaned elements
9826     // so we don't hold a reference and cause the browser to retain them
9827     El.garbageCollect = function(){
9828         if(!Roo.enableGarbageCollector){
9829             clearInterval(El.collectorThread);
9830             return;
9831         }
9832         for(var eid in El.cache){
9833             var el = El.cache[eid], d = el.dom;
9834             // -------------------------------------------------------
9835             // Determining what is garbage:
9836             // -------------------------------------------------------
9837             // !d
9838             // dom node is null, definitely garbage
9839             // -------------------------------------------------------
9840             // !d.parentNode
9841             // no parentNode == direct orphan, definitely garbage
9842             // -------------------------------------------------------
9843             // !d.offsetParent && !document.getElementById(eid)
9844             // display none elements have no offsetParent so we will
9845             // also try to look it up by it's id. However, check
9846             // offsetParent first so we don't do unneeded lookups.
9847             // This enables collection of elements that are not orphans
9848             // directly, but somewhere up the line they have an orphan
9849             // parent.
9850             // -------------------------------------------------------
9851             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9852                 delete El.cache[eid];
9853                 if(d && Roo.enableListenerCollection){
9854                     E.purgeElement(d);
9855                 }
9856             }
9857         }
9858     }
9859     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9860
9861
9862     // dom is optional
9863     El.Flyweight = function(dom){
9864         this.dom = dom;
9865     };
9866     El.Flyweight.prototype = El.prototype;
9867
9868     El._flyweights = {};
9869     /**
9870      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9871      * the dom node can be overwritten by other code.
9872      * @param {String/HTMLElement} el The dom node or id
9873      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9874      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9875      * @static
9876      * @return {Element} The shared Element object
9877      */
9878     El.fly = function(el, named){
9879         named = named || '_global';
9880         el = Roo.getDom(el);
9881         if(!el){
9882             return null;
9883         }
9884         if(!El._flyweights[named]){
9885             El._flyweights[named] = new El.Flyweight();
9886         }
9887         El._flyweights[named].dom = el;
9888         return El._flyweights[named];
9889     };
9890
9891     /**
9892      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9893      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9894      * Shorthand of {@link Roo.Element#get}
9895      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9896      * @return {Element} The Element object
9897      * @member Roo
9898      * @method get
9899      */
9900     Roo.get = El.get;
9901     /**
9902      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9903      * the dom node can be overwritten by other code.
9904      * Shorthand of {@link Roo.Element#fly}
9905      * @param {String/HTMLElement} el The dom node or id
9906      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9907      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9908      * @static
9909      * @return {Element} The shared Element object
9910      * @member Roo
9911      * @method fly
9912      */
9913     Roo.fly = El.fly;
9914
9915     // speedy lookup for elements never to box adjust
9916     var noBoxAdjust = Roo.isStrict ? {
9917         select:1
9918     } : {
9919         input:1, select:1, textarea:1
9920     };
9921     if(Roo.isIE || Roo.isGecko){
9922         noBoxAdjust['button'] = 1;
9923     }
9924
9925
9926     Roo.EventManager.on(window, 'unload', function(){
9927         delete El.cache;
9928         delete El._flyweights;
9929     });
9930 })();
9931
9932
9933
9934
9935 if(Roo.DomQuery){
9936     Roo.Element.selectorFunction = Roo.DomQuery.select;
9937 }
9938
9939 Roo.Element.select = function(selector, unique, root){
9940     var els;
9941     if(typeof selector == "string"){
9942         els = Roo.Element.selectorFunction(selector, root);
9943     }else if(selector.length !== undefined){
9944         els = selector;
9945     }else{
9946         throw "Invalid selector";
9947     }
9948     if(unique === true){
9949         return new Roo.CompositeElement(els);
9950     }else{
9951         return new Roo.CompositeElementLite(els);
9952     }
9953 };
9954 /**
9955  * Selects elements based on the passed CSS selector to enable working on them as 1.
9956  * @param {String/Array} selector The CSS selector or an array of elements
9957  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9958  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9959  * @return {CompositeElementLite/CompositeElement}
9960  * @member Roo
9961  * @method select
9962  */
9963 Roo.select = Roo.Element.select;
9964
9965
9966
9967
9968
9969
9970
9971
9972
9973
9974
9975
9976
9977
9978 /*
9979  * Based on:
9980  * Ext JS Library 1.1.1
9981  * Copyright(c) 2006-2007, Ext JS, LLC.
9982  *
9983  * Originally Released Under LGPL - original licence link has changed is not relivant.
9984  *
9985  * Fork - LGPL
9986  * <script type="text/javascript">
9987  */
9988
9989
9990
9991 //Notifies Element that fx methods are available
9992 Roo.enableFx = true;
9993
9994 /**
9995  * @class Roo.Fx
9996  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9997  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9998  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9999  * Element effects to work.</p><br/>
10000  *
10001  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
10002  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
10003  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
10004  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
10005  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
10006  * expected results and should be done with care.</p><br/>
10007  *
10008  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
10009  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
10010 <pre>
10011 Value  Description
10012 -----  -----------------------------
10013 tl     The top left corner
10014 t      The center of the top edge
10015 tr     The top right corner
10016 l      The center of the left edge
10017 r      The center of the right edge
10018 bl     The bottom left corner
10019 b      The center of the bottom edge
10020 br     The bottom right corner
10021 </pre>
10022  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10023  * below are common options that can be passed to any Fx method.</b>
10024  * @cfg {Function} callback A function called when the effect is finished
10025  * @cfg {Object} scope The scope of the effect function
10026  * @cfg {String} easing A valid Easing value for the effect
10027  * @cfg {String} afterCls A css class to apply after the effect
10028  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10029  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10030  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10031  * effects that end with the element being visually hidden, ignored otherwise)
10032  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10033  * a function which returns such a specification that will be applied to the Element after the effect finishes
10034  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10035  * @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
10036  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10037  */
10038 Roo.Fx = {
10039         /**
10040          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10041          * origin for the slide effect.  This function automatically handles wrapping the element with
10042          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10043          * Usage:
10044          *<pre><code>
10045 // default: slide the element in from the top
10046 el.slideIn();
10047
10048 // custom: slide the element in from the right with a 2-second duration
10049 el.slideIn('r', { duration: 2 });
10050
10051 // common config options shown with default values
10052 el.slideIn('t', {
10053     easing: 'easeOut',
10054     duration: .5
10055 });
10056 </code></pre>
10057          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10058          * @param {Object} options (optional) Object literal with any of the Fx config options
10059          * @return {Roo.Element} The Element
10060          */
10061     slideIn : function(anchor, o){
10062         var el = this.getFxEl();
10063         o = o || {};
10064
10065         el.queueFx(o, function(){
10066
10067             anchor = anchor || "t";
10068
10069             // fix display to visibility
10070             this.fixDisplay();
10071
10072             // restore values after effect
10073             var r = this.getFxRestore();
10074             var b = this.getBox();
10075             // fixed size for slide
10076             this.setSize(b);
10077
10078             // wrap if needed
10079             var wrap = this.fxWrap(r.pos, o, "hidden");
10080
10081             var st = this.dom.style;
10082             st.visibility = "visible";
10083             st.position = "absolute";
10084
10085             // clear out temp styles after slide and unwrap
10086             var after = function(){
10087                 el.fxUnwrap(wrap, r.pos, o);
10088                 st.width = r.width;
10089                 st.height = r.height;
10090                 el.afterFx(o);
10091             };
10092             // time to calc the positions
10093             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10094
10095             switch(anchor.toLowerCase()){
10096                 case "t":
10097                     wrap.setSize(b.width, 0);
10098                     st.left = st.bottom = "0";
10099                     a = {height: bh};
10100                 break;
10101                 case "l":
10102                     wrap.setSize(0, b.height);
10103                     st.right = st.top = "0";
10104                     a = {width: bw};
10105                 break;
10106                 case "r":
10107                     wrap.setSize(0, b.height);
10108                     wrap.setX(b.right);
10109                     st.left = st.top = "0";
10110                     a = {width: bw, points: pt};
10111                 break;
10112                 case "b":
10113                     wrap.setSize(b.width, 0);
10114                     wrap.setY(b.bottom);
10115                     st.left = st.top = "0";
10116                     a = {height: bh, points: pt};
10117                 break;
10118                 case "tl":
10119                     wrap.setSize(0, 0);
10120                     st.right = st.bottom = "0";
10121                     a = {width: bw, height: bh};
10122                 break;
10123                 case "bl":
10124                     wrap.setSize(0, 0);
10125                     wrap.setY(b.y+b.height);
10126                     st.right = st.top = "0";
10127                     a = {width: bw, height: bh, points: pt};
10128                 break;
10129                 case "br":
10130                     wrap.setSize(0, 0);
10131                     wrap.setXY([b.right, b.bottom]);
10132                     st.left = st.top = "0";
10133                     a = {width: bw, height: bh, points: pt};
10134                 break;
10135                 case "tr":
10136                     wrap.setSize(0, 0);
10137                     wrap.setX(b.x+b.width);
10138                     st.left = st.bottom = "0";
10139                     a = {width: bw, height: bh, points: pt};
10140                 break;
10141             }
10142             this.dom.style.visibility = "visible";
10143             wrap.show();
10144
10145             arguments.callee.anim = wrap.fxanim(a,
10146                 o,
10147                 'motion',
10148                 .5,
10149                 'easeOut', after);
10150         });
10151         return this;
10152     },
10153     
10154         /**
10155          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10156          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10157          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10158          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10159          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10160          * Usage:
10161          *<pre><code>
10162 // default: slide the element out to the top
10163 el.slideOut();
10164
10165 // custom: slide the element out to the right with a 2-second duration
10166 el.slideOut('r', { duration: 2 });
10167
10168 // common config options shown with default values
10169 el.slideOut('t', {
10170     easing: 'easeOut',
10171     duration: .5,
10172     remove: false,
10173     useDisplay: false
10174 });
10175 </code></pre>
10176          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10177          * @param {Object} options (optional) Object literal with any of the Fx config options
10178          * @return {Roo.Element} The Element
10179          */
10180     slideOut : function(anchor, o){
10181         var el = this.getFxEl();
10182         o = o || {};
10183
10184         el.queueFx(o, function(){
10185
10186             anchor = anchor || "t";
10187
10188             // restore values after effect
10189             var r = this.getFxRestore();
10190             
10191             var b = this.getBox();
10192             // fixed size for slide
10193             this.setSize(b);
10194
10195             // wrap if needed
10196             var wrap = this.fxWrap(r.pos, o, "visible");
10197
10198             var st = this.dom.style;
10199             st.visibility = "visible";
10200             st.position = "absolute";
10201
10202             wrap.setSize(b);
10203
10204             var after = function(){
10205                 if(o.useDisplay){
10206                     el.setDisplayed(false);
10207                 }else{
10208                     el.hide();
10209                 }
10210
10211                 el.fxUnwrap(wrap, r.pos, o);
10212
10213                 st.width = r.width;
10214                 st.height = r.height;
10215
10216                 el.afterFx(o);
10217             };
10218
10219             var a, zero = {to: 0};
10220             switch(anchor.toLowerCase()){
10221                 case "t":
10222                     st.left = st.bottom = "0";
10223                     a = {height: zero};
10224                 break;
10225                 case "l":
10226                     st.right = st.top = "0";
10227                     a = {width: zero};
10228                 break;
10229                 case "r":
10230                     st.left = st.top = "0";
10231                     a = {width: zero, points: {to:[b.right, b.y]}};
10232                 break;
10233                 case "b":
10234                     st.left = st.top = "0";
10235                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10236                 break;
10237                 case "tl":
10238                     st.right = st.bottom = "0";
10239                     a = {width: zero, height: zero};
10240                 break;
10241                 case "bl":
10242                     st.right = st.top = "0";
10243                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10244                 break;
10245                 case "br":
10246                     st.left = st.top = "0";
10247                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10248                 break;
10249                 case "tr":
10250                     st.left = st.bottom = "0";
10251                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10252                 break;
10253             }
10254
10255             arguments.callee.anim = wrap.fxanim(a,
10256                 o,
10257                 'motion',
10258                 .5,
10259                 "easeOut", after);
10260         });
10261         return this;
10262     },
10263
10264         /**
10265          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10266          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10267          * The element must be removed from the DOM using the 'remove' config option if desired.
10268          * Usage:
10269          *<pre><code>
10270 // default
10271 el.puff();
10272
10273 // common config options shown with default values
10274 el.puff({
10275     easing: 'easeOut',
10276     duration: .5,
10277     remove: false,
10278     useDisplay: false
10279 });
10280 </code></pre>
10281          * @param {Object} options (optional) Object literal with any of the Fx config options
10282          * @return {Roo.Element} The Element
10283          */
10284     puff : function(o){
10285         var el = this.getFxEl();
10286         o = o || {};
10287
10288         el.queueFx(o, function(){
10289             this.clearOpacity();
10290             this.show();
10291
10292             // restore values after effect
10293             var r = this.getFxRestore();
10294             var st = this.dom.style;
10295
10296             var after = function(){
10297                 if(o.useDisplay){
10298                     el.setDisplayed(false);
10299                 }else{
10300                     el.hide();
10301                 }
10302
10303                 el.clearOpacity();
10304
10305                 el.setPositioning(r.pos);
10306                 st.width = r.width;
10307                 st.height = r.height;
10308                 st.fontSize = '';
10309                 el.afterFx(o);
10310             };
10311
10312             var width = this.getWidth();
10313             var height = this.getHeight();
10314
10315             arguments.callee.anim = this.fxanim({
10316                     width : {to: this.adjustWidth(width * 2)},
10317                     height : {to: this.adjustHeight(height * 2)},
10318                     points : {by: [-(width * .5), -(height * .5)]},
10319                     opacity : {to: 0},
10320                     fontSize: {to:200, unit: "%"}
10321                 },
10322                 o,
10323                 'motion',
10324                 .5,
10325                 "easeOut", after);
10326         });
10327         return this;
10328     },
10329
10330         /**
10331          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10332          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10333          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10334          * Usage:
10335          *<pre><code>
10336 // default
10337 el.switchOff();
10338
10339 // all config options shown with default values
10340 el.switchOff({
10341     easing: 'easeIn',
10342     duration: .3,
10343     remove: false,
10344     useDisplay: false
10345 });
10346 </code></pre>
10347          * @param {Object} options (optional) Object literal with any of the Fx config options
10348          * @return {Roo.Element} The Element
10349          */
10350     switchOff : function(o){
10351         var el = this.getFxEl();
10352         o = o || {};
10353
10354         el.queueFx(o, function(){
10355             this.clearOpacity();
10356             this.clip();
10357
10358             // restore values after effect
10359             var r = this.getFxRestore();
10360             var st = this.dom.style;
10361
10362             var after = function(){
10363                 if(o.useDisplay){
10364                     el.setDisplayed(false);
10365                 }else{
10366                     el.hide();
10367                 }
10368
10369                 el.clearOpacity();
10370                 el.setPositioning(r.pos);
10371                 st.width = r.width;
10372                 st.height = r.height;
10373
10374                 el.afterFx(o);
10375             };
10376
10377             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10378                 this.clearOpacity();
10379                 (function(){
10380                     this.fxanim({
10381                         height:{to:1},
10382                         points:{by:[0, this.getHeight() * .5]}
10383                     }, o, 'motion', 0.3, 'easeIn', after);
10384                 }).defer(100, this);
10385             });
10386         });
10387         return this;
10388     },
10389
10390     /**
10391      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10392      * changed using the "attr" config option) and then fading back to the original color. If no original
10393      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10394      * Usage:
10395 <pre><code>
10396 // default: highlight background to yellow
10397 el.highlight();
10398
10399 // custom: highlight foreground text to blue for 2 seconds
10400 el.highlight("0000ff", { attr: 'color', duration: 2 });
10401
10402 // common config options shown with default values
10403 el.highlight("ffff9c", {
10404     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10405     endColor: (current color) or "ffffff",
10406     easing: 'easeIn',
10407     duration: 1
10408 });
10409 </code></pre>
10410      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10411      * @param {Object} options (optional) Object literal with any of the Fx config options
10412      * @return {Roo.Element} The Element
10413      */ 
10414     highlight : function(color, o){
10415         var el = this.getFxEl();
10416         o = o || {};
10417
10418         el.queueFx(o, function(){
10419             color = color || "ffff9c";
10420             attr = o.attr || "backgroundColor";
10421
10422             this.clearOpacity();
10423             this.show();
10424
10425             var origColor = this.getColor(attr);
10426             var restoreColor = this.dom.style[attr];
10427             endColor = (o.endColor || origColor) || "ffffff";
10428
10429             var after = function(){
10430                 el.dom.style[attr] = restoreColor;
10431                 el.afterFx(o);
10432             };
10433
10434             var a = {};
10435             a[attr] = {from: color, to: endColor};
10436             arguments.callee.anim = this.fxanim(a,
10437                 o,
10438                 'color',
10439                 1,
10440                 'easeIn', after);
10441         });
10442         return this;
10443     },
10444
10445    /**
10446     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10447     * Usage:
10448 <pre><code>
10449 // default: a single light blue ripple
10450 el.frame();
10451
10452 // custom: 3 red ripples lasting 3 seconds total
10453 el.frame("ff0000", 3, { duration: 3 });
10454
10455 // common config options shown with default values
10456 el.frame("C3DAF9", 1, {
10457     duration: 1 //duration of entire animation (not each individual ripple)
10458     // Note: Easing is not configurable and will be ignored if included
10459 });
10460 </code></pre>
10461     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10462     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10463     * @param {Object} options (optional) Object literal with any of the Fx config options
10464     * @return {Roo.Element} The Element
10465     */
10466     frame : function(color, count, o){
10467         var el = this.getFxEl();
10468         o = o || {};
10469
10470         el.queueFx(o, function(){
10471             color = color || "#C3DAF9";
10472             if(color.length == 6){
10473                 color = "#" + color;
10474             }
10475             count = count || 1;
10476             duration = o.duration || 1;
10477             this.show();
10478
10479             var b = this.getBox();
10480             var animFn = function(){
10481                 var proxy = this.createProxy({
10482
10483                      style:{
10484                         visbility:"hidden",
10485                         position:"absolute",
10486                         "z-index":"35000", // yee haw
10487                         border:"0px solid " + color
10488                      }
10489                   });
10490                 var scale = Roo.isBorderBox ? 2 : 1;
10491                 proxy.animate({
10492                     top:{from:b.y, to:b.y - 20},
10493                     left:{from:b.x, to:b.x - 20},
10494                     borderWidth:{from:0, to:10},
10495                     opacity:{from:1, to:0},
10496                     height:{from:b.height, to:(b.height + (20*scale))},
10497                     width:{from:b.width, to:(b.width + (20*scale))}
10498                 }, duration, function(){
10499                     proxy.remove();
10500                 });
10501                 if(--count > 0){
10502                      animFn.defer((duration/2)*1000, this);
10503                 }else{
10504                     el.afterFx(o);
10505                 }
10506             };
10507             animFn.call(this);
10508         });
10509         return this;
10510     },
10511
10512    /**
10513     * Creates a pause before any subsequent queued effects begin.  If there are
10514     * no effects queued after the pause it will have no effect.
10515     * Usage:
10516 <pre><code>
10517 el.pause(1);
10518 </code></pre>
10519     * @param {Number} seconds The length of time to pause (in seconds)
10520     * @return {Roo.Element} The Element
10521     */
10522     pause : function(seconds){
10523         var el = this.getFxEl();
10524         var o = {};
10525
10526         el.queueFx(o, function(){
10527             setTimeout(function(){
10528                 el.afterFx(o);
10529             }, seconds * 1000);
10530         });
10531         return this;
10532     },
10533
10534    /**
10535     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10536     * using the "endOpacity" config option.
10537     * Usage:
10538 <pre><code>
10539 // default: fade in from opacity 0 to 100%
10540 el.fadeIn();
10541
10542 // custom: fade in from opacity 0 to 75% over 2 seconds
10543 el.fadeIn({ endOpacity: .75, duration: 2});
10544
10545 // common config options shown with default values
10546 el.fadeIn({
10547     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10548     easing: 'easeOut',
10549     duration: .5
10550 });
10551 </code></pre>
10552     * @param {Object} options (optional) Object literal with any of the Fx config options
10553     * @return {Roo.Element} The Element
10554     */
10555     fadeIn : function(o){
10556         var el = this.getFxEl();
10557         o = o || {};
10558         el.queueFx(o, function(){
10559             this.setOpacity(0);
10560             this.fixDisplay();
10561             this.dom.style.visibility = 'visible';
10562             var to = o.endOpacity || 1;
10563             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10564                 o, null, .5, "easeOut", function(){
10565                 if(to == 1){
10566                     this.clearOpacity();
10567                 }
10568                 el.afterFx(o);
10569             });
10570         });
10571         return this;
10572     },
10573
10574    /**
10575     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10576     * using the "endOpacity" config option.
10577     * Usage:
10578 <pre><code>
10579 // default: fade out from the element's current opacity to 0
10580 el.fadeOut();
10581
10582 // custom: fade out from the element's current opacity to 25% over 2 seconds
10583 el.fadeOut({ endOpacity: .25, duration: 2});
10584
10585 // common config options shown with default values
10586 el.fadeOut({
10587     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10588     easing: 'easeOut',
10589     duration: .5
10590     remove: false,
10591     useDisplay: false
10592 });
10593 </code></pre>
10594     * @param {Object} options (optional) Object literal with any of the Fx config options
10595     * @return {Roo.Element} The Element
10596     */
10597     fadeOut : function(o){
10598         var el = this.getFxEl();
10599         o = o || {};
10600         el.queueFx(o, function(){
10601             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10602                 o, null, .5, "easeOut", function(){
10603                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10604                      this.dom.style.display = "none";
10605                 }else{
10606                      this.dom.style.visibility = "hidden";
10607                 }
10608                 this.clearOpacity();
10609                 el.afterFx(o);
10610             });
10611         });
10612         return this;
10613     },
10614
10615    /**
10616     * Animates the transition of an element's dimensions from a starting height/width
10617     * to an ending height/width.
10618     * Usage:
10619 <pre><code>
10620 // change height and width to 100x100 pixels
10621 el.scale(100, 100);
10622
10623 // common config options shown with default values.  The height and width will default to
10624 // the element's existing values if passed as null.
10625 el.scale(
10626     [element's width],
10627     [element's height], {
10628     easing: 'easeOut',
10629     duration: .35
10630 });
10631 </code></pre>
10632     * @param {Number} width  The new width (pass undefined to keep the original width)
10633     * @param {Number} height  The new height (pass undefined to keep the original height)
10634     * @param {Object} options (optional) Object literal with any of the Fx config options
10635     * @return {Roo.Element} The Element
10636     */
10637     scale : function(w, h, o){
10638         this.shift(Roo.apply({}, o, {
10639             width: w,
10640             height: h
10641         }));
10642         return this;
10643     },
10644
10645    /**
10646     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10647     * Any of these properties not specified in the config object will not be changed.  This effect 
10648     * requires that at least one new dimension, position or opacity setting must be passed in on
10649     * the config object in order for the function to have any effect.
10650     * Usage:
10651 <pre><code>
10652 // slide the element horizontally to x position 200 while changing the height and opacity
10653 el.shift({ x: 200, height: 50, opacity: .8 });
10654
10655 // common config options shown with default values.
10656 el.shift({
10657     width: [element's width],
10658     height: [element's height],
10659     x: [element's x position],
10660     y: [element's y position],
10661     opacity: [element's opacity],
10662     easing: 'easeOut',
10663     duration: .35
10664 });
10665 </code></pre>
10666     * @param {Object} options  Object literal with any of the Fx config options
10667     * @return {Roo.Element} The Element
10668     */
10669     shift : function(o){
10670         var el = this.getFxEl();
10671         o = o || {};
10672         el.queueFx(o, function(){
10673             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10674             if(w !== undefined){
10675                 a.width = {to: this.adjustWidth(w)};
10676             }
10677             if(h !== undefined){
10678                 a.height = {to: this.adjustHeight(h)};
10679             }
10680             if(x !== undefined || y !== undefined){
10681                 a.points = {to: [
10682                     x !== undefined ? x : this.getX(),
10683                     y !== undefined ? y : this.getY()
10684                 ]};
10685             }
10686             if(op !== undefined){
10687                 a.opacity = {to: op};
10688             }
10689             if(o.xy !== undefined){
10690                 a.points = {to: o.xy};
10691             }
10692             arguments.callee.anim = this.fxanim(a,
10693                 o, 'motion', .35, "easeOut", function(){
10694                 el.afterFx(o);
10695             });
10696         });
10697         return this;
10698     },
10699
10700         /**
10701          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10702          * ending point of the effect.
10703          * Usage:
10704          *<pre><code>
10705 // default: slide the element downward while fading out
10706 el.ghost();
10707
10708 // custom: slide the element out to the right with a 2-second duration
10709 el.ghost('r', { duration: 2 });
10710
10711 // common config options shown with default values
10712 el.ghost('b', {
10713     easing: 'easeOut',
10714     duration: .5
10715     remove: false,
10716     useDisplay: false
10717 });
10718 </code></pre>
10719          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10720          * @param {Object} options (optional) Object literal with any of the Fx config options
10721          * @return {Roo.Element} The Element
10722          */
10723     ghost : function(anchor, o){
10724         var el = this.getFxEl();
10725         o = o || {};
10726
10727         el.queueFx(o, function(){
10728             anchor = anchor || "b";
10729
10730             // restore values after effect
10731             var r = this.getFxRestore();
10732             var w = this.getWidth(),
10733                 h = this.getHeight();
10734
10735             var st = this.dom.style;
10736
10737             var after = function(){
10738                 if(o.useDisplay){
10739                     el.setDisplayed(false);
10740                 }else{
10741                     el.hide();
10742                 }
10743
10744                 el.clearOpacity();
10745                 el.setPositioning(r.pos);
10746                 st.width = r.width;
10747                 st.height = r.height;
10748
10749                 el.afterFx(o);
10750             };
10751
10752             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10753             switch(anchor.toLowerCase()){
10754                 case "t":
10755                     pt.by = [0, -h];
10756                 break;
10757                 case "l":
10758                     pt.by = [-w, 0];
10759                 break;
10760                 case "r":
10761                     pt.by = [w, 0];
10762                 break;
10763                 case "b":
10764                     pt.by = [0, h];
10765                 break;
10766                 case "tl":
10767                     pt.by = [-w, -h];
10768                 break;
10769                 case "bl":
10770                     pt.by = [-w, h];
10771                 break;
10772                 case "br":
10773                     pt.by = [w, h];
10774                 break;
10775                 case "tr":
10776                     pt.by = [w, -h];
10777                 break;
10778             }
10779
10780             arguments.callee.anim = this.fxanim(a,
10781                 o,
10782                 'motion',
10783                 .5,
10784                 "easeOut", after);
10785         });
10786         return this;
10787     },
10788
10789         /**
10790          * Ensures that all effects queued after syncFx is called on the element are
10791          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10792          * @return {Roo.Element} The Element
10793          */
10794     syncFx : function(){
10795         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10796             block : false,
10797             concurrent : true,
10798             stopFx : false
10799         });
10800         return this;
10801     },
10802
10803         /**
10804          * Ensures that all effects queued after sequenceFx is called on the element are
10805          * run in sequence.  This is the opposite of {@link #syncFx}.
10806          * @return {Roo.Element} The Element
10807          */
10808     sequenceFx : function(){
10809         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10810             block : false,
10811             concurrent : false,
10812             stopFx : false
10813         });
10814         return this;
10815     },
10816
10817         /* @private */
10818     nextFx : function(){
10819         var ef = this.fxQueue[0];
10820         if(ef){
10821             ef.call(this);
10822         }
10823     },
10824
10825         /**
10826          * Returns true if the element has any effects actively running or queued, else returns false.
10827          * @return {Boolean} True if element has active effects, else false
10828          */
10829     hasActiveFx : function(){
10830         return this.fxQueue && this.fxQueue[0];
10831     },
10832
10833         /**
10834          * Stops any running effects and clears the element's internal effects queue if it contains
10835          * any additional effects that haven't started yet.
10836          * @return {Roo.Element} The Element
10837          */
10838     stopFx : function(){
10839         if(this.hasActiveFx()){
10840             var cur = this.fxQueue[0];
10841             if(cur && cur.anim && cur.anim.isAnimated()){
10842                 this.fxQueue = [cur]; // clear out others
10843                 cur.anim.stop(true);
10844             }
10845         }
10846         return this;
10847     },
10848
10849         /* @private */
10850     beforeFx : function(o){
10851         if(this.hasActiveFx() && !o.concurrent){
10852            if(o.stopFx){
10853                this.stopFx();
10854                return true;
10855            }
10856            return false;
10857         }
10858         return true;
10859     },
10860
10861         /**
10862          * Returns true if the element is currently blocking so that no other effect can be queued
10863          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10864          * used to ensure that an effect initiated by a user action runs to completion prior to the
10865          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10866          * @return {Boolean} True if blocking, else false
10867          */
10868     hasFxBlock : function(){
10869         var q = this.fxQueue;
10870         return q && q[0] && q[0].block;
10871     },
10872
10873         /* @private */
10874     queueFx : function(o, fn){
10875         if(!this.fxQueue){
10876             this.fxQueue = [];
10877         }
10878         if(!this.hasFxBlock()){
10879             Roo.applyIf(o, this.fxDefaults);
10880             if(!o.concurrent){
10881                 var run = this.beforeFx(o);
10882                 fn.block = o.block;
10883                 this.fxQueue.push(fn);
10884                 if(run){
10885                     this.nextFx();
10886                 }
10887             }else{
10888                 fn.call(this);
10889             }
10890         }
10891         return this;
10892     },
10893
10894         /* @private */
10895     fxWrap : function(pos, o, vis){
10896         var wrap;
10897         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10898             var wrapXY;
10899             if(o.fixPosition){
10900                 wrapXY = this.getXY();
10901             }
10902             var div = document.createElement("div");
10903             div.style.visibility = vis;
10904             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10905             wrap.setPositioning(pos);
10906             if(wrap.getStyle("position") == "static"){
10907                 wrap.position("relative");
10908             }
10909             this.clearPositioning('auto');
10910             wrap.clip();
10911             wrap.dom.appendChild(this.dom);
10912             if(wrapXY){
10913                 wrap.setXY(wrapXY);
10914             }
10915         }
10916         return wrap;
10917     },
10918
10919         /* @private */
10920     fxUnwrap : function(wrap, pos, o){
10921         this.clearPositioning();
10922         this.setPositioning(pos);
10923         if(!o.wrap){
10924             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10925             wrap.remove();
10926         }
10927     },
10928
10929         /* @private */
10930     getFxRestore : function(){
10931         var st = this.dom.style;
10932         return {pos: this.getPositioning(), width: st.width, height : st.height};
10933     },
10934
10935         /* @private */
10936     afterFx : function(o){
10937         if(o.afterStyle){
10938             this.applyStyles(o.afterStyle);
10939         }
10940         if(o.afterCls){
10941             this.addClass(o.afterCls);
10942         }
10943         if(o.remove === true){
10944             this.remove();
10945         }
10946         Roo.callback(o.callback, o.scope, [this]);
10947         if(!o.concurrent){
10948             this.fxQueue.shift();
10949             this.nextFx();
10950         }
10951     },
10952
10953         /* @private */
10954     getFxEl : function(){ // support for composite element fx
10955         return Roo.get(this.dom);
10956     },
10957
10958         /* @private */
10959     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10960         animType = animType || 'run';
10961         opt = opt || {};
10962         var anim = Roo.lib.Anim[animType](
10963             this.dom, args,
10964             (opt.duration || defaultDur) || .35,
10965             (opt.easing || defaultEase) || 'easeOut',
10966             function(){
10967                 Roo.callback(cb, this);
10968             },
10969             this
10970         );
10971         opt.anim = anim;
10972         return anim;
10973     }
10974 };
10975
10976 // backwords compat
10977 Roo.Fx.resize = Roo.Fx.scale;
10978
10979 //When included, Roo.Fx is automatically applied to Element so that all basic
10980 //effects are available directly via the Element API
10981 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10982  * Based on:
10983  * Ext JS Library 1.1.1
10984  * Copyright(c) 2006-2007, Ext JS, LLC.
10985  *
10986  * Originally Released Under LGPL - original licence link has changed is not relivant.
10987  *
10988  * Fork - LGPL
10989  * <script type="text/javascript">
10990  */
10991
10992
10993 /**
10994  * @class Roo.CompositeElement
10995  * Standard composite class. Creates a Roo.Element for every element in the collection.
10996  * <br><br>
10997  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10998  * actions will be performed on all the elements in this collection.</b>
10999  * <br><br>
11000  * All methods return <i>this</i> and can be chained.
11001  <pre><code>
11002  var els = Roo.select("#some-el div.some-class", true);
11003  // or select directly from an existing element
11004  var el = Roo.get('some-el');
11005  el.select('div.some-class', true);
11006
11007  els.setWidth(100); // all elements become 100 width
11008  els.hide(true); // all elements fade out and hide
11009  // or
11010  els.setWidth(100).hide(true);
11011  </code></pre>
11012  */
11013 Roo.CompositeElement = function(els){
11014     this.elements = [];
11015     this.addElements(els);
11016 };
11017 Roo.CompositeElement.prototype = {
11018     isComposite: true,
11019     addElements : function(els){
11020         if(!els) return this;
11021         if(typeof els == "string"){
11022             els = Roo.Element.selectorFunction(els);
11023         }
11024         var yels = this.elements;
11025         var index = yels.length-1;
11026         for(var i = 0, len = els.length; i < len; i++) {
11027                 yels[++index] = Roo.get(els[i]);
11028         }
11029         return this;
11030     },
11031
11032     /**
11033     * Clears this composite and adds the elements returned by the passed selector.
11034     * @param {String/Array} els A string CSS selector, an array of elements or an element
11035     * @return {CompositeElement} this
11036     */
11037     fill : function(els){
11038         this.elements = [];
11039         this.add(els);
11040         return this;
11041     },
11042
11043     /**
11044     * Filters this composite to only elements that match the passed selector.
11045     * @param {String} selector A string CSS selector
11046     * @param {Boolean} inverse return inverse filter (not matches)
11047     * @return {CompositeElement} this
11048     */
11049     filter : function(selector, inverse){
11050         var els = [];
11051         inverse = inverse || false;
11052         this.each(function(el){
11053             var match = inverse ? !el.is(selector) : el.is(selector);
11054             if(match){
11055                 els[els.length] = el.dom;
11056             }
11057         });
11058         this.fill(els);
11059         return this;
11060     },
11061
11062     invoke : function(fn, args){
11063         var els = this.elements;
11064         for(var i = 0, len = els.length; i < len; i++) {
11065                 Roo.Element.prototype[fn].apply(els[i], args);
11066         }
11067         return this;
11068     },
11069     /**
11070     * Adds elements to this composite.
11071     * @param {String/Array} els A string CSS selector, an array of elements or an element
11072     * @return {CompositeElement} this
11073     */
11074     add : function(els){
11075         if(typeof els == "string"){
11076             this.addElements(Roo.Element.selectorFunction(els));
11077         }else if(els.length !== undefined){
11078             this.addElements(els);
11079         }else{
11080             this.addElements([els]);
11081         }
11082         return this;
11083     },
11084     /**
11085     * Calls the passed function passing (el, this, index) for each element in this composite.
11086     * @param {Function} fn The function to call
11087     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11088     * @return {CompositeElement} this
11089     */
11090     each : function(fn, scope){
11091         var els = this.elements;
11092         for(var i = 0, len = els.length; i < len; i++){
11093             if(fn.call(scope || els[i], els[i], this, i) === false) {
11094                 break;
11095             }
11096         }
11097         return this;
11098     },
11099
11100     /**
11101      * Returns the Element object at the specified index
11102      * @param {Number} index
11103      * @return {Roo.Element}
11104      */
11105     item : function(index){
11106         return this.elements[index] || null;
11107     },
11108
11109     /**
11110      * Returns the first Element
11111      * @return {Roo.Element}
11112      */
11113     first : function(){
11114         return this.item(0);
11115     },
11116
11117     /**
11118      * Returns the last Element
11119      * @return {Roo.Element}
11120      */
11121     last : function(){
11122         return this.item(this.elements.length-1);
11123     },
11124
11125     /**
11126      * Returns the number of elements in this composite
11127      * @return Number
11128      */
11129     getCount : function(){
11130         return this.elements.length;
11131     },
11132
11133     /**
11134      * Returns true if this composite contains the passed element
11135      * @return Boolean
11136      */
11137     contains : function(el){
11138         return this.indexOf(el) !== -1;
11139     },
11140
11141     /**
11142      * Returns true if this composite contains the passed element
11143      * @return Boolean
11144      */
11145     indexOf : function(el){
11146         return this.elements.indexOf(Roo.get(el));
11147     },
11148
11149
11150     /**
11151     * Removes the specified element(s).
11152     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11153     * or an array of any of those.
11154     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11155     * @return {CompositeElement} this
11156     */
11157     removeElement : function(el, removeDom){
11158         if(el instanceof Array){
11159             for(var i = 0, len = el.length; i < len; i++){
11160                 this.removeElement(el[i]);
11161             }
11162             return this;
11163         }
11164         var index = typeof el == 'number' ? el : this.indexOf(el);
11165         if(index !== -1){
11166             if(removeDom){
11167                 var d = this.elements[index];
11168                 if(d.dom){
11169                     d.remove();
11170                 }else{
11171                     d.parentNode.removeChild(d);
11172                 }
11173             }
11174             this.elements.splice(index, 1);
11175         }
11176         return this;
11177     },
11178
11179     /**
11180     * Replaces the specified element with the passed element.
11181     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11182     * to replace.
11183     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11184     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11185     * @return {CompositeElement} this
11186     */
11187     replaceElement : function(el, replacement, domReplace){
11188         var index = typeof el == 'number' ? el : this.indexOf(el);
11189         if(index !== -1){
11190             if(domReplace){
11191                 this.elements[index].replaceWith(replacement);
11192             }else{
11193                 this.elements.splice(index, 1, Roo.get(replacement))
11194             }
11195         }
11196         return this;
11197     },
11198
11199     /**
11200      * Removes all elements.
11201      */
11202     clear : function(){
11203         this.elements = [];
11204     }
11205 };
11206 (function(){
11207     Roo.CompositeElement.createCall = function(proto, fnName){
11208         if(!proto[fnName]){
11209             proto[fnName] = function(){
11210                 return this.invoke(fnName, arguments);
11211             };
11212         }
11213     };
11214     for(var fnName in Roo.Element.prototype){
11215         if(typeof Roo.Element.prototype[fnName] == "function"){
11216             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11217         }
11218     };
11219 })();
11220 /*
11221  * Based on:
11222  * Ext JS Library 1.1.1
11223  * Copyright(c) 2006-2007, Ext JS, LLC.
11224  *
11225  * Originally Released Under LGPL - original licence link has changed is not relivant.
11226  *
11227  * Fork - LGPL
11228  * <script type="text/javascript">
11229  */
11230
11231 /**
11232  * @class Roo.CompositeElementLite
11233  * @extends Roo.CompositeElement
11234  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11235  <pre><code>
11236  var els = Roo.select("#some-el div.some-class");
11237  // or select directly from an existing element
11238  var el = Roo.get('some-el');
11239  el.select('div.some-class');
11240
11241  els.setWidth(100); // all elements become 100 width
11242  els.hide(true); // all elements fade out and hide
11243  // or
11244  els.setWidth(100).hide(true);
11245  </code></pre><br><br>
11246  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11247  * actions will be performed on all the elements in this collection.</b>
11248  */
11249 Roo.CompositeElementLite = function(els){
11250     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11251     this.el = new Roo.Element.Flyweight();
11252 };
11253 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11254     addElements : function(els){
11255         if(els){
11256             if(els instanceof Array){
11257                 this.elements = this.elements.concat(els);
11258             }else{
11259                 var yels = this.elements;
11260                 var index = yels.length-1;
11261                 for(var i = 0, len = els.length; i < len; i++) {
11262                     yels[++index] = els[i];
11263                 }
11264             }
11265         }
11266         return this;
11267     },
11268     invoke : function(fn, args){
11269         var els = this.elements;
11270         var el = this.el;
11271         for(var i = 0, len = els.length; i < len; i++) {
11272             el.dom = els[i];
11273                 Roo.Element.prototype[fn].apply(el, args);
11274         }
11275         return this;
11276     },
11277     /**
11278      * Returns a flyweight Element of the dom element object at the specified index
11279      * @param {Number} index
11280      * @return {Roo.Element}
11281      */
11282     item : function(index){
11283         if(!this.elements[index]){
11284             return null;
11285         }
11286         this.el.dom = this.elements[index];
11287         return this.el;
11288     },
11289
11290     // fixes scope with flyweight
11291     addListener : function(eventName, handler, scope, opt){
11292         var els = this.elements;
11293         for(var i = 0, len = els.length; i < len; i++) {
11294             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11295         }
11296         return this;
11297     },
11298
11299     /**
11300     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11301     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11302     * a reference to the dom node, use el.dom.</b>
11303     * @param {Function} fn The function to call
11304     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11305     * @return {CompositeElement} this
11306     */
11307     each : function(fn, scope){
11308         var els = this.elements;
11309         var el = this.el;
11310         for(var i = 0, len = els.length; i < len; i++){
11311             el.dom = els[i];
11312                 if(fn.call(scope || el, el, this, i) === false){
11313                 break;
11314             }
11315         }
11316         return this;
11317     },
11318
11319     indexOf : function(el){
11320         return this.elements.indexOf(Roo.getDom(el));
11321     },
11322
11323     replaceElement : function(el, replacement, domReplace){
11324         var index = typeof el == 'number' ? el : this.indexOf(el);
11325         if(index !== -1){
11326             replacement = Roo.getDom(replacement);
11327             if(domReplace){
11328                 var d = this.elements[index];
11329                 d.parentNode.insertBefore(replacement, d);
11330                 d.parentNode.removeChild(d);
11331             }
11332             this.elements.splice(index, 1, replacement);
11333         }
11334         return this;
11335     }
11336 });
11337 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11338
11339 /*
11340  * Based on:
11341  * Ext JS Library 1.1.1
11342  * Copyright(c) 2006-2007, Ext JS, LLC.
11343  *
11344  * Originally Released Under LGPL - original licence link has changed is not relivant.
11345  *
11346  * Fork - LGPL
11347  * <script type="text/javascript">
11348  */
11349
11350  
11351
11352 /**
11353  * @class Roo.data.Connection
11354  * @extends Roo.util.Observable
11355  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11356  * either to a configured URL, or to a URL specified at request time.<br><br>
11357  * <p>
11358  * Requests made by this class are asynchronous, and will return immediately. No data from
11359  * the server will be available to the statement immediately following the {@link #request} call.
11360  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11361  * <p>
11362  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11363  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11364  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11365  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11366  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11367  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11368  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11369  * standard DOM methods.
11370  * @constructor
11371  * @param {Object} config a configuration object.
11372  */
11373 Roo.data.Connection = function(config){
11374     Roo.apply(this, config);
11375     this.addEvents({
11376         /**
11377          * @event beforerequest
11378          * Fires before a network request is made to retrieve a data object.
11379          * @param {Connection} conn This Connection object.
11380          * @param {Object} options The options config object passed to the {@link #request} method.
11381          */
11382         "beforerequest" : true,
11383         /**
11384          * @event requestcomplete
11385          * Fires if the request was successfully completed.
11386          * @param {Connection} conn This Connection object.
11387          * @param {Object} response The XHR object containing the response data.
11388          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11389          * @param {Object} options The options config object passed to the {@link #request} method.
11390          */
11391         "requestcomplete" : true,
11392         /**
11393          * @event requestexception
11394          * Fires if an error HTTP status was returned from the server.
11395          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11396          * @param {Connection} conn This Connection object.
11397          * @param {Object} response The XHR object containing the response data.
11398          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11399          * @param {Object} options The options config object passed to the {@link #request} method.
11400          */
11401         "requestexception" : true
11402     });
11403     Roo.data.Connection.superclass.constructor.call(this);
11404 };
11405
11406 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11407     /**
11408      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11409      */
11410     /**
11411      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11412      * extra parameters to each request made by this object. (defaults to undefined)
11413      */
11414     /**
11415      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11416      *  to each request made by this object. (defaults to undefined)
11417      */
11418     /**
11419      * @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)
11420      */
11421     /**
11422      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11423      */
11424     timeout : 30000,
11425     /**
11426      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11427      * @type Boolean
11428      */
11429     autoAbort:false,
11430
11431     /**
11432      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11433      * @type Boolean
11434      */
11435     disableCaching: true,
11436
11437     /**
11438      * Sends an HTTP request to a remote server.
11439      * @param {Object} options An object which may contain the following properties:<ul>
11440      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11441      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11442      * request, a url encoded string or a function to call to get either.</li>
11443      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11444      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11445      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11446      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11447      * <li>options {Object} The parameter to the request call.</li>
11448      * <li>success {Boolean} True if the request succeeded.</li>
11449      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11450      * </ul></li>
11451      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11452      * The callback is passed the following parameters:<ul>
11453      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11454      * <li>options {Object} The parameter to the request call.</li>
11455      * </ul></li>
11456      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11457      * The callback is passed the following parameters:<ul>
11458      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11459      * <li>options {Object} The parameter to the request call.</li>
11460      * </ul></li>
11461      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11462      * for the callback function. Defaults to the browser window.</li>
11463      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11464      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11465      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11466      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11467      * params for the post data. Any params will be appended to the URL.</li>
11468      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11469      * </ul>
11470      * @return {Number} transactionId
11471      */
11472     request : function(o){
11473         if(this.fireEvent("beforerequest", this, o) !== false){
11474             var p = o.params;
11475
11476             if(typeof p == "function"){
11477                 p = p.call(o.scope||window, o);
11478             }
11479             if(typeof p == "object"){
11480                 p = Roo.urlEncode(o.params);
11481             }
11482             if(this.extraParams){
11483                 var extras = Roo.urlEncode(this.extraParams);
11484                 p = p ? (p + '&' + extras) : extras;
11485             }
11486
11487             var url = o.url || this.url;
11488             if(typeof url == 'function'){
11489                 url = url.call(o.scope||window, o);
11490             }
11491
11492             if(o.form){
11493                 var form = Roo.getDom(o.form);
11494                 url = url || form.action;
11495
11496                 var enctype = form.getAttribute("enctype");
11497                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11498                     return this.doFormUpload(o, p, url);
11499                 }
11500                 var f = Roo.lib.Ajax.serializeForm(form);
11501                 p = p ? (p + '&' + f) : f;
11502             }
11503
11504             var hs = o.headers;
11505             if(this.defaultHeaders){
11506                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11507                 if(!o.headers){
11508                     o.headers = hs;
11509                 }
11510             }
11511
11512             var cb = {
11513                 success: this.handleResponse,
11514                 failure: this.handleFailure,
11515                 scope: this,
11516                 argument: {options: o},
11517                 timeout : o.timeout || this.timeout
11518             };
11519
11520             var method = o.method||this.method||(p ? "POST" : "GET");
11521
11522             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11523                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11524             }
11525
11526             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11527                 if(o.autoAbort){
11528                     this.abort();
11529                 }
11530             }else if(this.autoAbort !== false){
11531                 this.abort();
11532             }
11533
11534             if((method == 'GET' && p) || o.xmlData){
11535                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11536                 p = '';
11537             }
11538             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11539             return this.transId;
11540         }else{
11541             Roo.callback(o.callback, o.scope, [o, null, null]);
11542             return null;
11543         }
11544     },
11545
11546     /**
11547      * Determine whether this object has a request outstanding.
11548      * @param {Number} transactionId (Optional) defaults to the last transaction
11549      * @return {Boolean} True if there is an outstanding request.
11550      */
11551     isLoading : function(transId){
11552         if(transId){
11553             return Roo.lib.Ajax.isCallInProgress(transId);
11554         }else{
11555             return this.transId ? true : false;
11556         }
11557     },
11558
11559     /**
11560      * Aborts any outstanding request.
11561      * @param {Number} transactionId (Optional) defaults to the last transaction
11562      */
11563     abort : function(transId){
11564         if(transId || this.isLoading()){
11565             Roo.lib.Ajax.abort(transId || this.transId);
11566         }
11567     },
11568
11569     // private
11570     handleResponse : function(response){
11571         this.transId = false;
11572         var options = response.argument.options;
11573         response.argument = options ? options.argument : null;
11574         this.fireEvent("requestcomplete", this, response, options);
11575         Roo.callback(options.success, options.scope, [response, options]);
11576         Roo.callback(options.callback, options.scope, [options, true, response]);
11577     },
11578
11579     // private
11580     handleFailure : function(response, e){
11581         this.transId = false;
11582         var options = response.argument.options;
11583         response.argument = options ? options.argument : null;
11584         this.fireEvent("requestexception", this, response, options, e);
11585         Roo.callback(options.failure, options.scope, [response, options]);
11586         Roo.callback(options.callback, options.scope, [options, false, response]);
11587     },
11588
11589     // private
11590     doFormUpload : function(o, ps, url){
11591         var id = Roo.id();
11592         var frame = document.createElement('iframe');
11593         frame.id = id;
11594         frame.name = id;
11595         frame.className = 'x-hidden';
11596         if(Roo.isIE){
11597             frame.src = Roo.SSL_SECURE_URL;
11598         }
11599         document.body.appendChild(frame);
11600
11601         if(Roo.isIE){
11602            document.frames[id].name = id;
11603         }
11604
11605         var form = Roo.getDom(o.form);
11606         form.target = id;
11607         form.method = 'POST';
11608         form.enctype = form.encoding = 'multipart/form-data';
11609         if(url){
11610             form.action = url;
11611         }
11612
11613         var hiddens, hd;
11614         if(ps){ // add dynamic params
11615             hiddens = [];
11616             ps = Roo.urlDecode(ps, false);
11617             for(var k in ps){
11618                 if(ps.hasOwnProperty(k)){
11619                     hd = document.createElement('input');
11620                     hd.type = 'hidden';
11621                     hd.name = k;
11622                     hd.value = ps[k];
11623                     form.appendChild(hd);
11624                     hiddens.push(hd);
11625                 }
11626             }
11627         }
11628
11629         function cb(){
11630             var r = {  // bogus response object
11631                 responseText : '',
11632                 responseXML : null
11633             };
11634
11635             r.argument = o ? o.argument : null;
11636
11637             try { //
11638                 var doc;
11639                 if(Roo.isIE){
11640                     doc = frame.contentWindow.document;
11641                 }else {
11642                     doc = (frame.contentDocument || window.frames[id].document);
11643                 }
11644                 if(doc && doc.body){
11645                     r.responseText = doc.body.innerHTML;
11646                 }
11647                 if(doc && doc.XMLDocument){
11648                     r.responseXML = doc.XMLDocument;
11649                 }else {
11650                     r.responseXML = doc;
11651                 }
11652             }
11653             catch(e) {
11654                 // ignore
11655             }
11656
11657             Roo.EventManager.removeListener(frame, 'load', cb, this);
11658
11659             this.fireEvent("requestcomplete", this, r, o);
11660             Roo.callback(o.success, o.scope, [r, o]);
11661             Roo.callback(o.callback, o.scope, [o, true, r]);
11662
11663             setTimeout(function(){document.body.removeChild(frame);}, 100);
11664         }
11665
11666         Roo.EventManager.on(frame, 'load', cb, this);
11667         form.submit();
11668
11669         if(hiddens){ // remove dynamic params
11670             for(var i = 0, len = hiddens.length; i < len; i++){
11671                 form.removeChild(hiddens[i]);
11672             }
11673         }
11674     }
11675 });
11676 /*
11677  * Based on:
11678  * Ext JS Library 1.1.1
11679  * Copyright(c) 2006-2007, Ext JS, LLC.
11680  *
11681  * Originally Released Under LGPL - original licence link has changed is not relivant.
11682  *
11683  * Fork - LGPL
11684  * <script type="text/javascript">
11685  */
11686  
11687 /**
11688  * Global Ajax request class.
11689  * 
11690  * @class Roo.Ajax
11691  * @extends Roo.data.Connection
11692  * @static
11693  * 
11694  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11695  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11696  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11697  * @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)
11698  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11699  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11700  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11701  */
11702 Roo.Ajax = new Roo.data.Connection({
11703     // fix up the docs
11704     /**
11705      * @scope Roo.Ajax
11706      * @type {Boolear} 
11707      */
11708     autoAbort : false,
11709
11710     /**
11711      * Serialize the passed form into a url encoded string
11712      * @scope Roo.Ajax
11713      * @param {String/HTMLElement} form
11714      * @return {String}
11715      */
11716     serializeForm : function(form){
11717         return Roo.lib.Ajax.serializeForm(form);
11718     }
11719 });/*
11720  * Based on:
11721  * Ext JS Library 1.1.1
11722  * Copyright(c) 2006-2007, Ext JS, LLC.
11723  *
11724  * Originally Released Under LGPL - original licence link has changed is not relivant.
11725  *
11726  * Fork - LGPL
11727  * <script type="text/javascript">
11728  */
11729
11730  
11731 /**
11732  * @class Roo.UpdateManager
11733  * @extends Roo.util.Observable
11734  * Provides AJAX-style update for Element object.<br><br>
11735  * Usage:<br>
11736  * <pre><code>
11737  * // Get it from a Roo.Element object
11738  * var el = Roo.get("foo");
11739  * var mgr = el.getUpdateManager();
11740  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11741  * ...
11742  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11743  * <br>
11744  * // or directly (returns the same UpdateManager instance)
11745  * var mgr = new Roo.UpdateManager("myElementId");
11746  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11747  * mgr.on("update", myFcnNeedsToKnow);
11748  * <br>
11749    // short handed call directly from the element object
11750    Roo.get("foo").load({
11751         url: "bar.php",
11752         scripts:true,
11753         params: "for=bar",
11754         text: "Loading Foo..."
11755    });
11756  * </code></pre>
11757  * @constructor
11758  * Create new UpdateManager directly.
11759  * @param {String/HTMLElement/Roo.Element} el The element to update
11760  * @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).
11761  */
11762 Roo.UpdateManager = function(el, forceNew){
11763     el = Roo.get(el);
11764     if(!forceNew && el.updateManager){
11765         return el.updateManager;
11766     }
11767     /**
11768      * The Element object
11769      * @type Roo.Element
11770      */
11771     this.el = el;
11772     /**
11773      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11774      * @type String
11775      */
11776     this.defaultUrl = null;
11777
11778     this.addEvents({
11779         /**
11780          * @event beforeupdate
11781          * Fired before an update is made, return false from your handler and the update is cancelled.
11782          * @param {Roo.Element} el
11783          * @param {String/Object/Function} url
11784          * @param {String/Object} params
11785          */
11786         "beforeupdate": true,
11787         /**
11788          * @event update
11789          * Fired after successful update is made.
11790          * @param {Roo.Element} el
11791          * @param {Object} oResponseObject The response Object
11792          */
11793         "update": true,
11794         /**
11795          * @event failure
11796          * Fired on update failure.
11797          * @param {Roo.Element} el
11798          * @param {Object} oResponseObject The response Object
11799          */
11800         "failure": true
11801     });
11802     var d = Roo.UpdateManager.defaults;
11803     /**
11804      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11805      * @type String
11806      */
11807     this.sslBlankUrl = d.sslBlankUrl;
11808     /**
11809      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11810      * @type Boolean
11811      */
11812     this.disableCaching = d.disableCaching;
11813     /**
11814      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11815      * @type String
11816      */
11817     this.indicatorText = d.indicatorText;
11818     /**
11819      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11820      * @type String
11821      */
11822     this.showLoadIndicator = d.showLoadIndicator;
11823     /**
11824      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11825      * @type Number
11826      */
11827     this.timeout = d.timeout;
11828
11829     /**
11830      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11831      * @type Boolean
11832      */
11833     this.loadScripts = d.loadScripts;
11834
11835     /**
11836      * Transaction object of current executing transaction
11837      */
11838     this.transaction = null;
11839
11840     /**
11841      * @private
11842      */
11843     this.autoRefreshProcId = null;
11844     /**
11845      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11846      * @type Function
11847      */
11848     this.refreshDelegate = this.refresh.createDelegate(this);
11849     /**
11850      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11851      * @type Function
11852      */
11853     this.updateDelegate = this.update.createDelegate(this);
11854     /**
11855      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11856      * @type Function
11857      */
11858     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11859     /**
11860      * @private
11861      */
11862     this.successDelegate = this.processSuccess.createDelegate(this);
11863     /**
11864      * @private
11865      */
11866     this.failureDelegate = this.processFailure.createDelegate(this);
11867
11868     if(!this.renderer){
11869      /**
11870       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11871       */
11872     this.renderer = new Roo.UpdateManager.BasicRenderer();
11873     }
11874     
11875     Roo.UpdateManager.superclass.constructor.call(this);
11876 };
11877
11878 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11879     /**
11880      * Get the Element this UpdateManager is bound to
11881      * @return {Roo.Element} The element
11882      */
11883     getEl : function(){
11884         return this.el;
11885     },
11886     /**
11887      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11888      * @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:
11889 <pre><code>
11890 um.update({<br/>
11891     url: "your-url.php",<br/>
11892     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11893     callback: yourFunction,<br/>
11894     scope: yourObject, //(optional scope)  <br/>
11895     discardUrl: false, <br/>
11896     nocache: false,<br/>
11897     text: "Loading...",<br/>
11898     timeout: 30,<br/>
11899     scripts: false<br/>
11900 });
11901 </code></pre>
11902      * The only required property is url. The optional properties nocache, text and scripts
11903      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11904      * @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}
11905      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11906      * @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.
11907      */
11908     update : function(url, params, callback, discardUrl){
11909         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11910             var method = this.method,
11911                 cfg;
11912             if(typeof url == "object"){ // must be config object
11913                 cfg = url;
11914                 url = cfg.url;
11915                 params = params || cfg.params;
11916                 callback = callback || cfg.callback;
11917                 discardUrl = discardUrl || cfg.discardUrl;
11918                 if(callback && cfg.scope){
11919                     callback = callback.createDelegate(cfg.scope);
11920                 }
11921                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11922                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11923                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11924                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11925                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11926             }
11927             this.showLoading();
11928             if(!discardUrl){
11929                 this.defaultUrl = url;
11930             }
11931             if(typeof url == "function"){
11932                 url = url.call(this);
11933             }
11934
11935             method = method || (params ? "POST" : "GET");
11936             if(method == "GET"){
11937                 url = this.prepareUrl(url);
11938             }
11939
11940             var o = Roo.apply(cfg ||{}, {
11941                 url : url,
11942                 params: params,
11943                 success: this.successDelegate,
11944                 failure: this.failureDelegate,
11945                 callback: undefined,
11946                 timeout: (this.timeout*1000),
11947                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11948             });
11949             Roo.log("updated manager called with timeout of " + o.timeout);
11950             this.transaction = Roo.Ajax.request(o);
11951         }
11952     },
11953
11954     /**
11955      * 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.
11956      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11957      * @param {String/HTMLElement} form The form Id or form element
11958      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11959      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11960      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11961      */
11962     formUpdate : function(form, url, reset, callback){
11963         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11964             if(typeof url == "function"){
11965                 url = url.call(this);
11966             }
11967             form = Roo.getDom(form);
11968             this.transaction = Roo.Ajax.request({
11969                 form: form,
11970                 url:url,
11971                 success: this.successDelegate,
11972                 failure: this.failureDelegate,
11973                 timeout: (this.timeout*1000),
11974                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11975             });
11976             this.showLoading.defer(1, this);
11977         }
11978     },
11979
11980     /**
11981      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11982      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11983      */
11984     refresh : function(callback){
11985         if(this.defaultUrl == null){
11986             return;
11987         }
11988         this.update(this.defaultUrl, null, callback, true);
11989     },
11990
11991     /**
11992      * Set this element to auto refresh.
11993      * @param {Number} interval How often to update (in seconds).
11994      * @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)
11995      * @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}
11996      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11997      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11998      */
11999     startAutoRefresh : function(interval, url, params, callback, refreshNow){
12000         if(refreshNow){
12001             this.update(url || this.defaultUrl, params, callback, true);
12002         }
12003         if(this.autoRefreshProcId){
12004             clearInterval(this.autoRefreshProcId);
12005         }
12006         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
12007     },
12008
12009     /**
12010      * Stop auto refresh on this element.
12011      */
12012      stopAutoRefresh : function(){
12013         if(this.autoRefreshProcId){
12014             clearInterval(this.autoRefreshProcId);
12015             delete this.autoRefreshProcId;
12016         }
12017     },
12018
12019     isAutoRefreshing : function(){
12020        return this.autoRefreshProcId ? true : false;
12021     },
12022     /**
12023      * Called to update the element to "Loading" state. Override to perform custom action.
12024      */
12025     showLoading : function(){
12026         if(this.showLoadIndicator){
12027             this.el.update(this.indicatorText);
12028         }
12029     },
12030
12031     /**
12032      * Adds unique parameter to query string if disableCaching = true
12033      * @private
12034      */
12035     prepareUrl : function(url){
12036         if(this.disableCaching){
12037             var append = "_dc=" + (new Date().getTime());
12038             if(url.indexOf("?") !== -1){
12039                 url += "&" + append;
12040             }else{
12041                 url += "?" + append;
12042             }
12043         }
12044         return url;
12045     },
12046
12047     /**
12048      * @private
12049      */
12050     processSuccess : function(response){
12051         this.transaction = null;
12052         if(response.argument.form && response.argument.reset){
12053             try{ // put in try/catch since some older FF releases had problems with this
12054                 response.argument.form.reset();
12055             }catch(e){}
12056         }
12057         if(this.loadScripts){
12058             this.renderer.render(this.el, response, this,
12059                 this.updateComplete.createDelegate(this, [response]));
12060         }else{
12061             this.renderer.render(this.el, response, this);
12062             this.updateComplete(response);
12063         }
12064     },
12065
12066     updateComplete : function(response){
12067         this.fireEvent("update", this.el, response);
12068         if(typeof response.argument.callback == "function"){
12069             response.argument.callback(this.el, true, response);
12070         }
12071     },
12072
12073     /**
12074      * @private
12075      */
12076     processFailure : function(response){
12077         this.transaction = null;
12078         this.fireEvent("failure", this.el, response);
12079         if(typeof response.argument.callback == "function"){
12080             response.argument.callback(this.el, false, response);
12081         }
12082     },
12083
12084     /**
12085      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12086      * @param {Object} renderer The object implementing the render() method
12087      */
12088     setRenderer : function(renderer){
12089         this.renderer = renderer;
12090     },
12091
12092     getRenderer : function(){
12093        return this.renderer;
12094     },
12095
12096     /**
12097      * Set the defaultUrl used for updates
12098      * @param {String/Function} defaultUrl The url or a function to call to get the url
12099      */
12100     setDefaultUrl : function(defaultUrl){
12101         this.defaultUrl = defaultUrl;
12102     },
12103
12104     /**
12105      * Aborts the executing transaction
12106      */
12107     abort : function(){
12108         if(this.transaction){
12109             Roo.Ajax.abort(this.transaction);
12110         }
12111     },
12112
12113     /**
12114      * Returns true if an update is in progress
12115      * @return {Boolean}
12116      */
12117     isUpdating : function(){
12118         if(this.transaction){
12119             return Roo.Ajax.isLoading(this.transaction);
12120         }
12121         return false;
12122     }
12123 });
12124
12125 /**
12126  * @class Roo.UpdateManager.defaults
12127  * @static (not really - but it helps the doc tool)
12128  * The defaults collection enables customizing the default properties of UpdateManager
12129  */
12130    Roo.UpdateManager.defaults = {
12131        /**
12132          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12133          * @type Number
12134          */
12135          timeout : 30,
12136
12137          /**
12138          * True to process scripts by default (Defaults to false).
12139          * @type Boolean
12140          */
12141         loadScripts : false,
12142
12143         /**
12144         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12145         * @type String
12146         */
12147         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12148         /**
12149          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12150          * @type Boolean
12151          */
12152         disableCaching : false,
12153         /**
12154          * Whether to show indicatorText when loading (Defaults to true).
12155          * @type Boolean
12156          */
12157         showLoadIndicator : true,
12158         /**
12159          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12160          * @type String
12161          */
12162         indicatorText : '<div class="loading-indicator">Loading...</div>'
12163    };
12164
12165 /**
12166  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12167  *Usage:
12168  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12169  * @param {String/HTMLElement/Roo.Element} el The element to update
12170  * @param {String} url The url
12171  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12172  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12173  * @static
12174  * @deprecated
12175  * @member Roo.UpdateManager
12176  */
12177 Roo.UpdateManager.updateElement = function(el, url, params, options){
12178     var um = Roo.get(el, true).getUpdateManager();
12179     Roo.apply(um, options);
12180     um.update(url, params, options ? options.callback : null);
12181 };
12182 // alias for backwards compat
12183 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12184 /**
12185  * @class Roo.UpdateManager.BasicRenderer
12186  * Default Content renderer. Updates the elements innerHTML with the responseText.
12187  */
12188 Roo.UpdateManager.BasicRenderer = function(){};
12189
12190 Roo.UpdateManager.BasicRenderer.prototype = {
12191     /**
12192      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12193      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12194      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12195      * @param {Roo.Element} el The element being rendered
12196      * @param {Object} response The YUI Connect response object
12197      * @param {UpdateManager} updateManager The calling update manager
12198      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12199      */
12200      render : function(el, response, updateManager, callback){
12201         el.update(response.responseText, updateManager.loadScripts, callback);
12202     }
12203 };
12204 /*
12205  * Based on:
12206  * Roo JS
12207  * (c)) Alan Knowles
12208  * Licence : LGPL
12209  */
12210
12211
12212 /**
12213  * @class Roo.DomTemplate
12214  * @extends Roo.Template
12215  * An effort at a dom based template engine..
12216  *
12217  * Similar to XTemplate, except it uses dom parsing to create the template..
12218  *
12219  * Supported features:
12220  *
12221  *  Tags:
12222
12223 <pre><code>
12224       {a_variable} - output encoded.
12225       {a_variable.format:("Y-m-d")} - call a method on the variable
12226       {a_variable:raw} - unencoded output
12227       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12228       {a_variable:this.method_on_template(...)} - call a method on the template object.
12229  
12230 </code></pre>
12231  *  The tpl tag:
12232 <pre><code>
12233         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12234         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12235         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12236         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12237   
12238 </code></pre>
12239  *      
12240  */
12241 Roo.DomTemplate = function()
12242 {
12243      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12244      if (this.html) {
12245         this.compile();
12246      }
12247 };
12248
12249
12250 Roo.extend(Roo.DomTemplate, Roo.Template, {
12251     /**
12252      * id counter for sub templates.
12253      */
12254     id : 0,
12255     /**
12256      * flag to indicate if dom parser is inside a pre,
12257      * it will strip whitespace if not.
12258      */
12259     inPre : false,
12260     
12261     /**
12262      * The various sub templates
12263      */
12264     tpls : false,
12265     
12266     
12267     
12268     /**
12269      *
12270      * basic tag replacing syntax
12271      * WORD:WORD()
12272      *
12273      * // you can fake an object call by doing this
12274      *  x.t:(test,tesT) 
12275      * 
12276      */
12277     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12278     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12279     
12280     iterChild : function (node, method) {
12281         
12282         var oldPre = this.inPre;
12283         if (node.tagName == 'PRE') {
12284             this.inPre = true;
12285         }
12286         for( var i = 0; i < node.childNodes.length; i++) {
12287             method.call(this, node.childNodes[i]);
12288         }
12289         this.inPre = oldPre;
12290     },
12291     
12292     
12293     
12294     /**
12295      * compile the template
12296      *
12297      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12298      *
12299      */
12300     compile: function()
12301     {
12302         var s = this.html;
12303         
12304         // covert the html into DOM...
12305         var doc = false;
12306         var div =false;
12307         try {
12308             doc = document.implementation.createHTMLDocument("");
12309             doc.documentElement.innerHTML =   this.html  ;
12310             div = doc.documentElement;
12311         } catch (e) {
12312             // old IE... - nasty -- it causes all sorts of issues.. with
12313             // images getting pulled from server..
12314             div = document.createElement('div');
12315             div.innerHTML = this.html;
12316         }
12317         //doc.documentElement.innerHTML = htmlBody
12318          
12319         
12320         
12321         this.tpls = [];
12322         var _t = this;
12323         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12324         
12325         var tpls = this.tpls;
12326         
12327         // create a top level template from the snippet..
12328         
12329         //Roo.log(div.innerHTML);
12330         
12331         var tpl = {
12332             uid : 'master',
12333             id : this.id++,
12334             attr : false,
12335             value : false,
12336             body : div.innerHTML,
12337             
12338             forCall : false,
12339             execCall : false,
12340             dom : div,
12341             isTop : true
12342             
12343         };
12344         tpls.unshift(tpl);
12345         
12346         
12347         // compile them...
12348         this.tpls = [];
12349         Roo.each(tpls, function(tp){
12350             this.compileTpl(tp);
12351             this.tpls[tp.id] = tp;
12352         }, this);
12353         
12354         this.master = tpls[0];
12355         return this;
12356         
12357         
12358     },
12359     
12360     compileNode : function(node, istop) {
12361         // test for
12362         //Roo.log(node);
12363         
12364         
12365         // skip anything not a tag..
12366         if (node.nodeType != 1) {
12367             if (node.nodeType == 3 && !this.inPre) {
12368                 // reduce white space..
12369                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12370                 
12371             }
12372             return;
12373         }
12374         
12375         var tpl = {
12376             uid : false,
12377             id : false,
12378             attr : false,
12379             value : false,
12380             body : '',
12381             
12382             forCall : false,
12383             execCall : false,
12384             dom : false,
12385             isTop : istop
12386             
12387             
12388         };
12389         
12390         
12391         switch(true) {
12392             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12393             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12394             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12395             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12396             // no default..
12397         }
12398         
12399         
12400         if (!tpl.attr) {
12401             // just itterate children..
12402             this.iterChild(node,this.compileNode);
12403             return;
12404         }
12405         tpl.uid = this.id++;
12406         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12407         node.removeAttribute('roo-'+ tpl.attr);
12408         if (tpl.attr != 'name') {
12409             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12410             node.parentNode.replaceChild(placeholder,  node);
12411         } else {
12412             
12413             var placeholder =  document.createElement('span');
12414             placeholder.className = 'roo-tpl-' + tpl.value;
12415             node.parentNode.replaceChild(placeholder,  node);
12416         }
12417         
12418         // parent now sees '{domtplXXXX}
12419         this.iterChild(node,this.compileNode);
12420         
12421         // we should now have node body...
12422         var div = document.createElement('div');
12423         div.appendChild(node);
12424         tpl.dom = node;
12425         // this has the unfortunate side effect of converting tagged attributes
12426         // eg. href="{...}" into %7C...%7D
12427         // this has been fixed by searching for those combo's although it's a bit hacky..
12428         
12429         
12430         tpl.body = div.innerHTML;
12431         
12432         
12433          
12434         tpl.id = tpl.uid;
12435         switch(tpl.attr) {
12436             case 'for' :
12437                 switch (tpl.value) {
12438                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12439                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12440                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12441                 }
12442                 break;
12443             
12444             case 'exec':
12445                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12446                 break;
12447             
12448             case 'if':     
12449                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12450                 break;
12451             
12452             case 'name':
12453                 tpl.id  = tpl.value; // replace non characters???
12454                 break;
12455             
12456         }
12457         
12458         
12459         this.tpls.push(tpl);
12460         
12461         
12462         
12463     },
12464     
12465     
12466     
12467     
12468     /**
12469      * Compile a segment of the template into a 'sub-template'
12470      *
12471      * 
12472      * 
12473      *
12474      */
12475     compileTpl : function(tpl)
12476     {
12477         var fm = Roo.util.Format;
12478         var useF = this.disableFormats !== true;
12479         
12480         var sep = Roo.isGecko ? "+\n" : ",\n";
12481         
12482         var undef = function(str) {
12483             Roo.debug && Roo.log("Property not found :"  + str);
12484             return '';
12485         };
12486           
12487         //Roo.log(tpl.body);
12488         
12489         
12490         
12491         var fn = function(m, lbrace, name, format, args)
12492         {
12493             //Roo.log("ARGS");
12494             //Roo.log(arguments);
12495             args = args ? args.replace(/\\'/g,"'") : args;
12496             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12497             if (typeof(format) == 'undefined') {
12498                 format =  'htmlEncode'; 
12499             }
12500             if (format == 'raw' ) {
12501                 format = false;
12502             }
12503             
12504             if(name.substr(0, 6) == 'domtpl'){
12505                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12506             }
12507             
12508             // build an array of options to determine if value is undefined..
12509             
12510             // basically get 'xxxx.yyyy' then do
12511             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12512             //    (function () { Roo.log("Property not found"); return ''; })() :
12513             //    ......
12514             
12515             var udef_ar = [];
12516             var lookfor = '';
12517             Roo.each(name.split('.'), function(st) {
12518                 lookfor += (lookfor.length ? '.': '') + st;
12519                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12520             });
12521             
12522             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12523             
12524             
12525             if(format && useF){
12526                 
12527                 args = args ? ',' + args : "";
12528                  
12529                 if(format.substr(0, 5) != "this."){
12530                     format = "fm." + format + '(';
12531                 }else{
12532                     format = 'this.call("'+ format.substr(5) + '", ';
12533                     args = ", values";
12534                 }
12535                 
12536                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12537             }
12538              
12539             if (args && args.length) {
12540                 // called with xxyx.yuu:(test,test)
12541                 // change to ()
12542                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12543             }
12544             // raw.. - :raw modifier..
12545             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12546             
12547         };
12548         var body;
12549         // branched to use + in gecko and [].join() in others
12550         if(Roo.isGecko){
12551             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12552                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12553                     "';};};";
12554         }else{
12555             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12556             body.push(tpl.body.replace(/(\r\n|\n)/g,
12557                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12558             body.push("'].join('');};};");
12559             body = body.join('');
12560         }
12561         
12562         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12563        
12564         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12565         eval(body);
12566         
12567         return this;
12568     },
12569      
12570     /**
12571      * same as applyTemplate, except it's done to one of the subTemplates
12572      * when using named templates, you can do:
12573      *
12574      * var str = pl.applySubTemplate('your-name', values);
12575      *
12576      * 
12577      * @param {Number} id of the template
12578      * @param {Object} values to apply to template
12579      * @param {Object} parent (normaly the instance of this object)
12580      */
12581     applySubTemplate : function(id, values, parent)
12582     {
12583         
12584         
12585         var t = this.tpls[id];
12586         
12587         
12588         try { 
12589             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12590                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12591                 return '';
12592             }
12593         } catch(e) {
12594             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12595             Roo.log(values);
12596           
12597             return '';
12598         }
12599         try { 
12600             
12601             if(t.execCall && t.execCall.call(this, values, parent)){
12602                 return '';
12603             }
12604         } catch(e) {
12605             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12606             Roo.log(values);
12607             return '';
12608         }
12609         
12610         try {
12611             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12612             parent = t.target ? values : parent;
12613             if(t.forCall && vs instanceof Array){
12614                 var buf = [];
12615                 for(var i = 0, len = vs.length; i < len; i++){
12616                     try {
12617                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12618                     } catch (e) {
12619                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12620                         Roo.log(e.body);
12621                         //Roo.log(t.compiled);
12622                         Roo.log(vs[i]);
12623                     }   
12624                 }
12625                 return buf.join('');
12626             }
12627         } catch (e) {
12628             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12629             Roo.log(values);
12630             return '';
12631         }
12632         try {
12633             return t.compiled.call(this, vs, parent);
12634         } catch (e) {
12635             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12636             Roo.log(e.body);
12637             //Roo.log(t.compiled);
12638             Roo.log(values);
12639             return '';
12640         }
12641     },
12642
12643    
12644
12645     applyTemplate : function(values){
12646         return this.master.compiled.call(this, values, {});
12647         //var s = this.subs;
12648     },
12649
12650     apply : function(){
12651         return this.applyTemplate.apply(this, arguments);
12652     }
12653
12654  });
12655
12656 Roo.DomTemplate.from = function(el){
12657     el = Roo.getDom(el);
12658     return new Roo.Domtemplate(el.value || el.innerHTML);
12659 };/*
12660  * Based on:
12661  * Ext JS Library 1.1.1
12662  * Copyright(c) 2006-2007, Ext JS, LLC.
12663  *
12664  * Originally Released Under LGPL - original licence link has changed is not relivant.
12665  *
12666  * Fork - LGPL
12667  * <script type="text/javascript">
12668  */
12669
12670 /**
12671  * @class Roo.util.DelayedTask
12672  * Provides a convenient method of performing setTimeout where a new
12673  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12674  * You can use this class to buffer
12675  * the keypress events for a certain number of milliseconds, and perform only if they stop
12676  * for that amount of time.
12677  * @constructor The parameters to this constructor serve as defaults and are not required.
12678  * @param {Function} fn (optional) The default function to timeout
12679  * @param {Object} scope (optional) The default scope of that timeout
12680  * @param {Array} args (optional) The default Array of arguments
12681  */
12682 Roo.util.DelayedTask = function(fn, scope, args){
12683     var id = null, d, t;
12684
12685     var call = function(){
12686         var now = new Date().getTime();
12687         if(now - t >= d){
12688             clearInterval(id);
12689             id = null;
12690             fn.apply(scope, args || []);
12691         }
12692     };
12693     /**
12694      * Cancels any pending timeout and queues a new one
12695      * @param {Number} delay The milliseconds to delay
12696      * @param {Function} newFn (optional) Overrides function passed to constructor
12697      * @param {Object} newScope (optional) Overrides scope passed to constructor
12698      * @param {Array} newArgs (optional) Overrides args passed to constructor
12699      */
12700     this.delay = function(delay, newFn, newScope, newArgs){
12701         if(id && delay != d){
12702             this.cancel();
12703         }
12704         d = delay;
12705         t = new Date().getTime();
12706         fn = newFn || fn;
12707         scope = newScope || scope;
12708         args = newArgs || args;
12709         if(!id){
12710             id = setInterval(call, d);
12711         }
12712     };
12713
12714     /**
12715      * Cancel the last queued timeout
12716      */
12717     this.cancel = function(){
12718         if(id){
12719             clearInterval(id);
12720             id = null;
12721         }
12722     };
12723 };/*
12724  * Based on:
12725  * Ext JS Library 1.1.1
12726  * Copyright(c) 2006-2007, Ext JS, LLC.
12727  *
12728  * Originally Released Under LGPL - original licence link has changed is not relivant.
12729  *
12730  * Fork - LGPL
12731  * <script type="text/javascript">
12732  */
12733  
12734  
12735 Roo.util.TaskRunner = function(interval){
12736     interval = interval || 10;
12737     var tasks = [], removeQueue = [];
12738     var id = 0;
12739     var running = false;
12740
12741     var stopThread = function(){
12742         running = false;
12743         clearInterval(id);
12744         id = 0;
12745     };
12746
12747     var startThread = function(){
12748         if(!running){
12749             running = true;
12750             id = setInterval(runTasks, interval);
12751         }
12752     };
12753
12754     var removeTask = function(task){
12755         removeQueue.push(task);
12756         if(task.onStop){
12757             task.onStop();
12758         }
12759     };
12760
12761     var runTasks = function(){
12762         if(removeQueue.length > 0){
12763             for(var i = 0, len = removeQueue.length; i < len; i++){
12764                 tasks.remove(removeQueue[i]);
12765             }
12766             removeQueue = [];
12767             if(tasks.length < 1){
12768                 stopThread();
12769                 return;
12770             }
12771         }
12772         var now = new Date().getTime();
12773         for(var i = 0, len = tasks.length; i < len; ++i){
12774             var t = tasks[i];
12775             var itime = now - t.taskRunTime;
12776             if(t.interval <= itime){
12777                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12778                 t.taskRunTime = now;
12779                 if(rt === false || t.taskRunCount === t.repeat){
12780                     removeTask(t);
12781                     return;
12782                 }
12783             }
12784             if(t.duration && t.duration <= (now - t.taskStartTime)){
12785                 removeTask(t);
12786             }
12787         }
12788     };
12789
12790     /**
12791      * Queues a new task.
12792      * @param {Object} task
12793      */
12794     this.start = function(task){
12795         tasks.push(task);
12796         task.taskStartTime = new Date().getTime();
12797         task.taskRunTime = 0;
12798         task.taskRunCount = 0;
12799         startThread();
12800         return task;
12801     };
12802
12803     this.stop = function(task){
12804         removeTask(task);
12805         return task;
12806     };
12807
12808     this.stopAll = function(){
12809         stopThread();
12810         for(var i = 0, len = tasks.length; i < len; i++){
12811             if(tasks[i].onStop){
12812                 tasks[i].onStop();
12813             }
12814         }
12815         tasks = [];
12816         removeQueue = [];
12817     };
12818 };
12819
12820 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12821  * Based on:
12822  * Ext JS Library 1.1.1
12823  * Copyright(c) 2006-2007, Ext JS, LLC.
12824  *
12825  * Originally Released Under LGPL - original licence link has changed is not relivant.
12826  *
12827  * Fork - LGPL
12828  * <script type="text/javascript">
12829  */
12830
12831  
12832 /**
12833  * @class Roo.util.MixedCollection
12834  * @extends Roo.util.Observable
12835  * A Collection class that maintains both numeric indexes and keys and exposes events.
12836  * @constructor
12837  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12838  * collection (defaults to false)
12839  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12840  * and return the key value for that item.  This is used when available to look up the key on items that
12841  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12842  * equivalent to providing an implementation for the {@link #getKey} method.
12843  */
12844 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12845     this.items = [];
12846     this.map = {};
12847     this.keys = [];
12848     this.length = 0;
12849     this.addEvents({
12850         /**
12851          * @event clear
12852          * Fires when the collection is cleared.
12853          */
12854         "clear" : true,
12855         /**
12856          * @event add
12857          * Fires when an item is added to the collection.
12858          * @param {Number} index The index at which the item was added.
12859          * @param {Object} o The item added.
12860          * @param {String} key The key associated with the added item.
12861          */
12862         "add" : true,
12863         /**
12864          * @event replace
12865          * Fires when an item is replaced in the collection.
12866          * @param {String} key he key associated with the new added.
12867          * @param {Object} old The item being replaced.
12868          * @param {Object} new The new item.
12869          */
12870         "replace" : true,
12871         /**
12872          * @event remove
12873          * Fires when an item is removed from the collection.
12874          * @param {Object} o The item being removed.
12875          * @param {String} key (optional) The key associated with the removed item.
12876          */
12877         "remove" : true,
12878         "sort" : true
12879     });
12880     this.allowFunctions = allowFunctions === true;
12881     if(keyFn){
12882         this.getKey = keyFn;
12883     }
12884     Roo.util.MixedCollection.superclass.constructor.call(this);
12885 };
12886
12887 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12888     allowFunctions : false,
12889     
12890 /**
12891  * Adds an item to the collection.
12892  * @param {String} key The key to associate with the item
12893  * @param {Object} o The item to add.
12894  * @return {Object} The item added.
12895  */
12896     add : function(key, o){
12897         if(arguments.length == 1){
12898             o = arguments[0];
12899             key = this.getKey(o);
12900         }
12901         if(typeof key == "undefined" || key === null){
12902             this.length++;
12903             this.items.push(o);
12904             this.keys.push(null);
12905         }else{
12906             var old = this.map[key];
12907             if(old){
12908                 return this.replace(key, o);
12909             }
12910             this.length++;
12911             this.items.push(o);
12912             this.map[key] = o;
12913             this.keys.push(key);
12914         }
12915         this.fireEvent("add", this.length-1, o, key);
12916         return o;
12917     },
12918        
12919 /**
12920   * MixedCollection has a generic way to fetch keys if you implement getKey.
12921 <pre><code>
12922 // normal way
12923 var mc = new Roo.util.MixedCollection();
12924 mc.add(someEl.dom.id, someEl);
12925 mc.add(otherEl.dom.id, otherEl);
12926 //and so on
12927
12928 // using getKey
12929 var mc = new Roo.util.MixedCollection();
12930 mc.getKey = function(el){
12931    return el.dom.id;
12932 };
12933 mc.add(someEl);
12934 mc.add(otherEl);
12935
12936 // or via the constructor
12937 var mc = new Roo.util.MixedCollection(false, function(el){
12938    return el.dom.id;
12939 });
12940 mc.add(someEl);
12941 mc.add(otherEl);
12942 </code></pre>
12943  * @param o {Object} The item for which to find the key.
12944  * @return {Object} The key for the passed item.
12945  */
12946     getKey : function(o){
12947          return o.id; 
12948     },
12949    
12950 /**
12951  * Replaces an item in the collection.
12952  * @param {String} key The key associated with the item to replace, or the item to replace.
12953  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12954  * @return {Object}  The new item.
12955  */
12956     replace : function(key, o){
12957         if(arguments.length == 1){
12958             o = arguments[0];
12959             key = this.getKey(o);
12960         }
12961         var old = this.item(key);
12962         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12963              return this.add(key, o);
12964         }
12965         var index = this.indexOfKey(key);
12966         this.items[index] = o;
12967         this.map[key] = o;
12968         this.fireEvent("replace", key, old, o);
12969         return o;
12970     },
12971    
12972 /**
12973  * Adds all elements of an Array or an Object to the collection.
12974  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12975  * an Array of values, each of which are added to the collection.
12976  */
12977     addAll : function(objs){
12978         if(arguments.length > 1 || objs instanceof Array){
12979             var args = arguments.length > 1 ? arguments : objs;
12980             for(var i = 0, len = args.length; i < len; i++){
12981                 this.add(args[i]);
12982             }
12983         }else{
12984             for(var key in objs){
12985                 if(this.allowFunctions || typeof objs[key] != "function"){
12986                     this.add(key, objs[key]);
12987                 }
12988             }
12989         }
12990     },
12991    
12992 /**
12993  * Executes the specified function once for every item in the collection, passing each
12994  * item as the first and only parameter. returning false from the function will stop the iteration.
12995  * @param {Function} fn The function to execute for each item.
12996  * @param {Object} scope (optional) The scope in which to execute the function.
12997  */
12998     each : function(fn, scope){
12999         var items = [].concat(this.items); // each safe for removal
13000         for(var i = 0, len = items.length; i < len; i++){
13001             if(fn.call(scope || items[i], items[i], i, len) === false){
13002                 break;
13003             }
13004         }
13005     },
13006    
13007 /**
13008  * Executes the specified function once for every key in the collection, passing each
13009  * key, and its associated item as the first two parameters.
13010  * @param {Function} fn The function to execute for each item.
13011  * @param {Object} scope (optional) The scope in which to execute the function.
13012  */
13013     eachKey : function(fn, scope){
13014         for(var i = 0, len = this.keys.length; i < len; i++){
13015             fn.call(scope || window, this.keys[i], this.items[i], i, len);
13016         }
13017     },
13018    
13019 /**
13020  * Returns the first item in the collection which elicits a true return value from the
13021  * passed selection function.
13022  * @param {Function} fn The selection function to execute for each item.
13023  * @param {Object} scope (optional) The scope in which to execute the function.
13024  * @return {Object} The first item in the collection which returned true from the selection function.
13025  */
13026     find : function(fn, scope){
13027         for(var i = 0, len = this.items.length; i < len; i++){
13028             if(fn.call(scope || window, this.items[i], this.keys[i])){
13029                 return this.items[i];
13030             }
13031         }
13032         return null;
13033     },
13034    
13035 /**
13036  * Inserts an item at the specified index in the collection.
13037  * @param {Number} index The index to insert the item at.
13038  * @param {String} key The key to associate with the new item, or the item itself.
13039  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13040  * @return {Object} The item inserted.
13041  */
13042     insert : function(index, key, o){
13043         if(arguments.length == 2){
13044             o = arguments[1];
13045             key = this.getKey(o);
13046         }
13047         if(index >= this.length){
13048             return this.add(key, o);
13049         }
13050         this.length++;
13051         this.items.splice(index, 0, o);
13052         if(typeof key != "undefined" && key != null){
13053             this.map[key] = o;
13054         }
13055         this.keys.splice(index, 0, key);
13056         this.fireEvent("add", index, o, key);
13057         return o;
13058     },
13059    
13060 /**
13061  * Removed an item from the collection.
13062  * @param {Object} o The item to remove.
13063  * @return {Object} The item removed.
13064  */
13065     remove : function(o){
13066         return this.removeAt(this.indexOf(o));
13067     },
13068    
13069 /**
13070  * Remove an item from a specified index in the collection.
13071  * @param {Number} index The index within the collection of the item to remove.
13072  */
13073     removeAt : function(index){
13074         if(index < this.length && index >= 0){
13075             this.length--;
13076             var o = this.items[index];
13077             this.items.splice(index, 1);
13078             var key = this.keys[index];
13079             if(typeof key != "undefined"){
13080                 delete this.map[key];
13081             }
13082             this.keys.splice(index, 1);
13083             this.fireEvent("remove", o, key);
13084         }
13085     },
13086    
13087 /**
13088  * Removed an item associated with the passed key fom the collection.
13089  * @param {String} key The key of the item to remove.
13090  */
13091     removeKey : function(key){
13092         return this.removeAt(this.indexOfKey(key));
13093     },
13094    
13095 /**
13096  * Returns the number of items in the collection.
13097  * @return {Number} the number of items in the collection.
13098  */
13099     getCount : function(){
13100         return this.length; 
13101     },
13102    
13103 /**
13104  * Returns index within the collection of the passed Object.
13105  * @param {Object} o The item to find the index of.
13106  * @return {Number} index of the item.
13107  */
13108     indexOf : function(o){
13109         if(!this.items.indexOf){
13110             for(var i = 0, len = this.items.length; i < len; i++){
13111                 if(this.items[i] == o) return i;
13112             }
13113             return -1;
13114         }else{
13115             return this.items.indexOf(o);
13116         }
13117     },
13118    
13119 /**
13120  * Returns index within the collection of the passed key.
13121  * @param {String} key The key to find the index of.
13122  * @return {Number} index of the key.
13123  */
13124     indexOfKey : function(key){
13125         if(!this.keys.indexOf){
13126             for(var i = 0, len = this.keys.length; i < len; i++){
13127                 if(this.keys[i] == key) return i;
13128             }
13129             return -1;
13130         }else{
13131             return this.keys.indexOf(key);
13132         }
13133     },
13134    
13135 /**
13136  * Returns the item associated with the passed key OR index. Key has priority over index.
13137  * @param {String/Number} key The key or index of the item.
13138  * @return {Object} The item associated with the passed key.
13139  */
13140     item : function(key){
13141         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13142         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13143     },
13144     
13145 /**
13146  * Returns the item at the specified index.
13147  * @param {Number} index The index of the item.
13148  * @return {Object}
13149  */
13150     itemAt : function(index){
13151         return this.items[index];
13152     },
13153     
13154 /**
13155  * Returns the item associated with the passed key.
13156  * @param {String/Number} key The key of the item.
13157  * @return {Object} The item associated with the passed key.
13158  */
13159     key : function(key){
13160         return this.map[key];
13161     },
13162    
13163 /**
13164  * Returns true if the collection contains the passed Object as an item.
13165  * @param {Object} o  The Object to look for in the collection.
13166  * @return {Boolean} True if the collection contains the Object as an item.
13167  */
13168     contains : function(o){
13169         return this.indexOf(o) != -1;
13170     },
13171    
13172 /**
13173  * Returns true if the collection contains the passed Object as a key.
13174  * @param {String} key The key to look for in the collection.
13175  * @return {Boolean} True if the collection contains the Object as a key.
13176  */
13177     containsKey : function(key){
13178         return typeof this.map[key] != "undefined";
13179     },
13180    
13181 /**
13182  * Removes all items from the collection.
13183  */
13184     clear : function(){
13185         this.length = 0;
13186         this.items = [];
13187         this.keys = [];
13188         this.map = {};
13189         this.fireEvent("clear");
13190     },
13191    
13192 /**
13193  * Returns the first item in the collection.
13194  * @return {Object} the first item in the collection..
13195  */
13196     first : function(){
13197         return this.items[0]; 
13198     },
13199    
13200 /**
13201  * Returns the last item in the collection.
13202  * @return {Object} the last item in the collection..
13203  */
13204     last : function(){
13205         return this.items[this.length-1];   
13206     },
13207     
13208     _sort : function(property, dir, fn){
13209         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13210         fn = fn || function(a, b){
13211             return a-b;
13212         };
13213         var c = [], k = this.keys, items = this.items;
13214         for(var i = 0, len = items.length; i < len; i++){
13215             c[c.length] = {key: k[i], value: items[i], index: i};
13216         }
13217         c.sort(function(a, b){
13218             var v = fn(a[property], b[property]) * dsc;
13219             if(v == 0){
13220                 v = (a.index < b.index ? -1 : 1);
13221             }
13222             return v;
13223         });
13224         for(var i = 0, len = c.length; i < len; i++){
13225             items[i] = c[i].value;
13226             k[i] = c[i].key;
13227         }
13228         this.fireEvent("sort", this);
13229     },
13230     
13231     /**
13232      * Sorts this collection with the passed comparison function
13233      * @param {String} direction (optional) "ASC" or "DESC"
13234      * @param {Function} fn (optional) comparison function
13235      */
13236     sort : function(dir, fn){
13237         this._sort("value", dir, fn);
13238     },
13239     
13240     /**
13241      * Sorts this collection by keys
13242      * @param {String} direction (optional) "ASC" or "DESC"
13243      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13244      */
13245     keySort : function(dir, fn){
13246         this._sort("key", dir, fn || function(a, b){
13247             return String(a).toUpperCase()-String(b).toUpperCase();
13248         });
13249     },
13250     
13251     /**
13252      * Returns a range of items in this collection
13253      * @param {Number} startIndex (optional) defaults to 0
13254      * @param {Number} endIndex (optional) default to the last item
13255      * @return {Array} An array of items
13256      */
13257     getRange : function(start, end){
13258         var items = this.items;
13259         if(items.length < 1){
13260             return [];
13261         }
13262         start = start || 0;
13263         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13264         var r = [];
13265         if(start <= end){
13266             for(var i = start; i <= end; i++) {
13267                     r[r.length] = items[i];
13268             }
13269         }else{
13270             for(var i = start; i >= end; i--) {
13271                     r[r.length] = items[i];
13272             }
13273         }
13274         return r;
13275     },
13276         
13277     /**
13278      * Filter the <i>objects</i> in this collection by a specific property. 
13279      * Returns a new collection that has been filtered.
13280      * @param {String} property A property on your objects
13281      * @param {String/RegExp} value Either string that the property values 
13282      * should start with or a RegExp to test against the property
13283      * @return {MixedCollection} The new filtered collection
13284      */
13285     filter : function(property, value){
13286         if(!value.exec){ // not a regex
13287             value = String(value);
13288             if(value.length == 0){
13289                 return this.clone();
13290             }
13291             value = new RegExp("^" + Roo.escapeRe(value), "i");
13292         }
13293         return this.filterBy(function(o){
13294             return o && value.test(o[property]);
13295         });
13296         },
13297     
13298     /**
13299      * Filter by a function. * Returns a new collection that has been filtered.
13300      * The passed function will be called with each 
13301      * object in the collection. If the function returns true, the value is included 
13302      * otherwise it is filtered.
13303      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13304      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13305      * @return {MixedCollection} The new filtered collection
13306      */
13307     filterBy : function(fn, scope){
13308         var r = new Roo.util.MixedCollection();
13309         r.getKey = this.getKey;
13310         var k = this.keys, it = this.items;
13311         for(var i = 0, len = it.length; i < len; i++){
13312             if(fn.call(scope||this, it[i], k[i])){
13313                                 r.add(k[i], it[i]);
13314                         }
13315         }
13316         return r;
13317     },
13318     
13319     /**
13320      * Creates a duplicate of this collection
13321      * @return {MixedCollection}
13322      */
13323     clone : function(){
13324         var r = new Roo.util.MixedCollection();
13325         var k = this.keys, it = this.items;
13326         for(var i = 0, len = it.length; i < len; i++){
13327             r.add(k[i], it[i]);
13328         }
13329         r.getKey = this.getKey;
13330         return r;
13331     }
13332 });
13333 /**
13334  * Returns the item associated with the passed key or index.
13335  * @method
13336  * @param {String/Number} key The key or index of the item.
13337  * @return {Object} The item associated with the passed key.
13338  */
13339 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13340  * Based on:
13341  * Ext JS Library 1.1.1
13342  * Copyright(c) 2006-2007, Ext JS, LLC.
13343  *
13344  * Originally Released Under LGPL - original licence link has changed is not relivant.
13345  *
13346  * Fork - LGPL
13347  * <script type="text/javascript">
13348  */
13349 /**
13350  * @class Roo.util.JSON
13351  * Modified version of Douglas Crockford"s json.js that doesn"t
13352  * mess with the Object prototype 
13353  * http://www.json.org/js.html
13354  * @singleton
13355  */
13356 Roo.util.JSON = new (function(){
13357     var useHasOwn = {}.hasOwnProperty ? true : false;
13358     
13359     // crashes Safari in some instances
13360     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13361     
13362     var pad = function(n) {
13363         return n < 10 ? "0" + n : n;
13364     };
13365     
13366     var m = {
13367         "\b": '\\b',
13368         "\t": '\\t',
13369         "\n": '\\n',
13370         "\f": '\\f',
13371         "\r": '\\r',
13372         '"' : '\\"',
13373         "\\": '\\\\'
13374     };
13375
13376     var encodeString = function(s){
13377         if (/["\\\x00-\x1f]/.test(s)) {
13378             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13379                 var c = m[b];
13380                 if(c){
13381                     return c;
13382                 }
13383                 c = b.charCodeAt();
13384                 return "\\u00" +
13385                     Math.floor(c / 16).toString(16) +
13386                     (c % 16).toString(16);
13387             }) + '"';
13388         }
13389         return '"' + s + '"';
13390     };
13391     
13392     var encodeArray = function(o){
13393         var a = ["["], b, i, l = o.length, v;
13394             for (i = 0; i < l; i += 1) {
13395                 v = o[i];
13396                 switch (typeof v) {
13397                     case "undefined":
13398                     case "function":
13399                     case "unknown":
13400                         break;
13401                     default:
13402                         if (b) {
13403                             a.push(',');
13404                         }
13405                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13406                         b = true;
13407                 }
13408             }
13409             a.push("]");
13410             return a.join("");
13411     };
13412     
13413     var encodeDate = function(o){
13414         return '"' + o.getFullYear() + "-" +
13415                 pad(o.getMonth() + 1) + "-" +
13416                 pad(o.getDate()) + "T" +
13417                 pad(o.getHours()) + ":" +
13418                 pad(o.getMinutes()) + ":" +
13419                 pad(o.getSeconds()) + '"';
13420     };
13421     
13422     /**
13423      * Encodes an Object, Array or other value
13424      * @param {Mixed} o The variable to encode
13425      * @return {String} The JSON string
13426      */
13427     this.encode = function(o)
13428     {
13429         // should this be extended to fully wrap stringify..
13430         
13431         if(typeof o == "undefined" || o === null){
13432             return "null";
13433         }else if(o instanceof Array){
13434             return encodeArray(o);
13435         }else if(o instanceof Date){
13436             return encodeDate(o);
13437         }else if(typeof o == "string"){
13438             return encodeString(o);
13439         }else if(typeof o == "number"){
13440             return isFinite(o) ? String(o) : "null";
13441         }else if(typeof o == "boolean"){
13442             return String(o);
13443         }else {
13444             var a = ["{"], b, i, v;
13445             for (i in o) {
13446                 if(!useHasOwn || o.hasOwnProperty(i)) {
13447                     v = o[i];
13448                     switch (typeof v) {
13449                     case "undefined":
13450                     case "function":
13451                     case "unknown":
13452                         break;
13453                     default:
13454                         if(b){
13455                             a.push(',');
13456                         }
13457                         a.push(this.encode(i), ":",
13458                                 v === null ? "null" : this.encode(v));
13459                         b = true;
13460                     }
13461                 }
13462             }
13463             a.push("}");
13464             return a.join("");
13465         }
13466     };
13467     
13468     /**
13469      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13470      * @param {String} json The JSON string
13471      * @return {Object} The resulting object
13472      */
13473     this.decode = function(json){
13474         
13475         return  /** eval:var:json */ eval("(" + json + ')');
13476     };
13477 })();
13478 /** 
13479  * Shorthand for {@link Roo.util.JSON#encode}
13480  * @member Roo encode 
13481  * @method */
13482 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13483 /** 
13484  * Shorthand for {@link Roo.util.JSON#decode}
13485  * @member Roo decode 
13486  * @method */
13487 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13488 /*
13489  * Based on:
13490  * Ext JS Library 1.1.1
13491  * Copyright(c) 2006-2007, Ext JS, LLC.
13492  *
13493  * Originally Released Under LGPL - original licence link has changed is not relivant.
13494  *
13495  * Fork - LGPL
13496  * <script type="text/javascript">
13497  */
13498  
13499 /**
13500  * @class Roo.util.Format
13501  * Reusable data formatting functions
13502  * @singleton
13503  */
13504 Roo.util.Format = function(){
13505     var trimRe = /^\s+|\s+$/g;
13506     return {
13507         /**
13508          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13509          * @param {String} value The string to truncate
13510          * @param {Number} length The maximum length to allow before truncating
13511          * @return {String} The converted text
13512          */
13513         ellipsis : function(value, len){
13514             if(value && value.length > len){
13515                 return value.substr(0, len-3)+"...";
13516             }
13517             return value;
13518         },
13519
13520         /**
13521          * Checks a reference and converts it to empty string if it is undefined
13522          * @param {Mixed} value Reference to check
13523          * @return {Mixed} Empty string if converted, otherwise the original value
13524          */
13525         undef : function(value){
13526             return typeof value != "undefined" ? value : "";
13527         },
13528
13529         /**
13530          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13531          * @param {String} value The string to encode
13532          * @return {String} The encoded text
13533          */
13534         htmlEncode : function(value){
13535             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13536         },
13537
13538         /**
13539          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13540          * @param {String} value The string to decode
13541          * @return {String} The decoded text
13542          */
13543         htmlDecode : function(value){
13544             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13545         },
13546
13547         /**
13548          * Trims any whitespace from either side of a string
13549          * @param {String} value The text to trim
13550          * @return {String} The trimmed text
13551          */
13552         trim : function(value){
13553             return String(value).replace(trimRe, "");
13554         },
13555
13556         /**
13557          * Returns a substring from within an original string
13558          * @param {String} value The original text
13559          * @param {Number} start The start index of the substring
13560          * @param {Number} length The length of the substring
13561          * @return {String} The substring
13562          */
13563         substr : function(value, start, length){
13564             return String(value).substr(start, length);
13565         },
13566
13567         /**
13568          * Converts a string to all lower case letters
13569          * @param {String} value The text to convert
13570          * @return {String} The converted text
13571          */
13572         lowercase : function(value){
13573             return String(value).toLowerCase();
13574         },
13575
13576         /**
13577          * Converts a string to all upper case letters
13578          * @param {String} value The text to convert
13579          * @return {String} The converted text
13580          */
13581         uppercase : function(value){
13582             return String(value).toUpperCase();
13583         },
13584
13585         /**
13586          * Converts the first character only of a string to upper case
13587          * @param {String} value The text to convert
13588          * @return {String} The converted text
13589          */
13590         capitalize : function(value){
13591             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13592         },
13593
13594         // private
13595         call : function(value, fn){
13596             if(arguments.length > 2){
13597                 var args = Array.prototype.slice.call(arguments, 2);
13598                 args.unshift(value);
13599                  
13600                 return /** eval:var:value */  eval(fn).apply(window, args);
13601             }else{
13602                 /** eval:var:value */
13603                 return /** eval:var:value */ eval(fn).call(window, value);
13604             }
13605         },
13606
13607        
13608         /**
13609          * safer version of Math.toFixed..??/
13610          * @param {Number/String} value The numeric value to format
13611          * @param {Number/String} value Decimal places 
13612          * @return {String} The formatted currency string
13613          */
13614         toFixed : function(v, n)
13615         {
13616             // why not use to fixed - precision is buggered???
13617             if (!n) {
13618                 return Math.round(v-0);
13619             }
13620             var fact = Math.pow(10,n+1);
13621             v = (Math.round((v-0)*fact))/fact;
13622             var z = (''+fact).substring(2);
13623             if (v == Math.floor(v)) {
13624                 return Math.floor(v) + '.' + z;
13625             }
13626             
13627             // now just padd decimals..
13628             var ps = String(v).split('.');
13629             var fd = (ps[1] + z);
13630             var r = fd.substring(0,n); 
13631             var rm = fd.substring(n); 
13632             if (rm < 5) {
13633                 return ps[0] + '.' + r;
13634             }
13635             r*=1; // turn it into a number;
13636             r++;
13637             if (String(r).length != n) {
13638                 ps[0]*=1;
13639                 ps[0]++;
13640                 r = String(r).substring(1); // chop the end off.
13641             }
13642             
13643             return ps[0] + '.' + r;
13644              
13645         },
13646         
13647         /**
13648          * Format a number as US currency
13649          * @param {Number/String} value The numeric value to format
13650          * @return {String} The formatted currency string
13651          */
13652         usMoney : function(v){
13653             return '$' + Roo.util.Format.number(v);
13654         },
13655         
13656         /**
13657          * Format a number
13658          * eventually this should probably emulate php's number_format
13659          * @param {Number/String} value The numeric value to format
13660          * @param {Number} decimals number of decimal places
13661          * @return {String} The formatted currency string
13662          */
13663         number : function(v,decimals)
13664         {
13665             // multiply and round.
13666             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13667             var mul = Math.pow(10, decimals);
13668             var zero = String(mul).substring(1);
13669             v = (Math.round((v-0)*mul))/mul;
13670             
13671             // if it's '0' number.. then
13672             
13673             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13674             v = String(v);
13675             var ps = v.split('.');
13676             var whole = ps[0];
13677             
13678             
13679             var r = /(\d+)(\d{3})/;
13680             // add comma's
13681             while (r.test(whole)) {
13682                 whole = whole.replace(r, '$1' + ',' + '$2');
13683             }
13684             
13685             
13686             var sub = ps[1] ?
13687                     // has decimals..
13688                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13689                     // does not have decimals
13690                     (decimals ? ('.' + zero) : '');
13691             
13692             
13693             return whole + sub ;
13694         },
13695         
13696         /**
13697          * Parse a value into a formatted date using the specified format pattern.
13698          * @param {Mixed} value The value to format
13699          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13700          * @return {String} The formatted date string
13701          */
13702         date : function(v, format){
13703             if(!v){
13704                 return "";
13705             }
13706             if(!(v instanceof Date)){
13707                 v = new Date(Date.parse(v));
13708             }
13709             return v.dateFormat(format || Roo.util.Format.defaults.date);
13710         },
13711
13712         /**
13713          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13714          * @param {String} format Any valid date format string
13715          * @return {Function} The date formatting function
13716          */
13717         dateRenderer : function(format){
13718             return function(v){
13719                 return Roo.util.Format.date(v, format);  
13720             };
13721         },
13722
13723         // private
13724         stripTagsRE : /<\/?[^>]+>/gi,
13725         
13726         /**
13727          * Strips all HTML tags
13728          * @param {Mixed} value The text from which to strip tags
13729          * @return {String} The stripped text
13730          */
13731         stripTags : function(v){
13732             return !v ? v : String(v).replace(this.stripTagsRE, "");
13733         }
13734     };
13735 }();
13736 Roo.util.Format.defaults = {
13737     date : 'd/M/Y'
13738 };/*
13739  * Based on:
13740  * Ext JS Library 1.1.1
13741  * Copyright(c) 2006-2007, Ext JS, LLC.
13742  *
13743  * Originally Released Under LGPL - original licence link has changed is not relivant.
13744  *
13745  * Fork - LGPL
13746  * <script type="text/javascript">
13747  */
13748
13749
13750  
13751
13752 /**
13753  * @class Roo.MasterTemplate
13754  * @extends Roo.Template
13755  * Provides a template that can have child templates. The syntax is:
13756 <pre><code>
13757 var t = new Roo.MasterTemplate(
13758         '&lt;select name="{name}"&gt;',
13759                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13760         '&lt;/select&gt;'
13761 );
13762 t.add('options', {value: 'foo', text: 'bar'});
13763 // or you can add multiple child elements in one shot
13764 t.addAll('options', [
13765     {value: 'foo', text: 'bar'},
13766     {value: 'foo2', text: 'bar2'},
13767     {value: 'foo3', text: 'bar3'}
13768 ]);
13769 // then append, applying the master template values
13770 t.append('my-form', {name: 'my-select'});
13771 </code></pre>
13772 * A name attribute for the child template is not required if you have only one child
13773 * template or you want to refer to them by index.
13774  */
13775 Roo.MasterTemplate = function(){
13776     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13777     this.originalHtml = this.html;
13778     var st = {};
13779     var m, re = this.subTemplateRe;
13780     re.lastIndex = 0;
13781     var subIndex = 0;
13782     while(m = re.exec(this.html)){
13783         var name = m[1], content = m[2];
13784         st[subIndex] = {
13785             name: name,
13786             index: subIndex,
13787             buffer: [],
13788             tpl : new Roo.Template(content)
13789         };
13790         if(name){
13791             st[name] = st[subIndex];
13792         }
13793         st[subIndex].tpl.compile();
13794         st[subIndex].tpl.call = this.call.createDelegate(this);
13795         subIndex++;
13796     }
13797     this.subCount = subIndex;
13798     this.subs = st;
13799 };
13800 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13801     /**
13802     * The regular expression used to match sub templates
13803     * @type RegExp
13804     * @property
13805     */
13806     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13807
13808     /**
13809      * Applies the passed values to a child template.
13810      * @param {String/Number} name (optional) The name or index of the child template
13811      * @param {Array/Object} values The values to be applied to the template
13812      * @return {MasterTemplate} this
13813      */
13814      add : function(name, values){
13815         if(arguments.length == 1){
13816             values = arguments[0];
13817             name = 0;
13818         }
13819         var s = this.subs[name];
13820         s.buffer[s.buffer.length] = s.tpl.apply(values);
13821         return this;
13822     },
13823
13824     /**
13825      * Applies all the passed values to a child template.
13826      * @param {String/Number} name (optional) The name or index of the child template
13827      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13828      * @param {Boolean} reset (optional) True to reset the template first
13829      * @return {MasterTemplate} this
13830      */
13831     fill : function(name, values, reset){
13832         var a = arguments;
13833         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13834             values = a[0];
13835             name = 0;
13836             reset = a[1];
13837         }
13838         if(reset){
13839             this.reset();
13840         }
13841         for(var i = 0, len = values.length; i < len; i++){
13842             this.add(name, values[i]);
13843         }
13844         return this;
13845     },
13846
13847     /**
13848      * Resets the template for reuse
13849      * @return {MasterTemplate} this
13850      */
13851      reset : function(){
13852         var s = this.subs;
13853         for(var i = 0; i < this.subCount; i++){
13854             s[i].buffer = [];
13855         }
13856         return this;
13857     },
13858
13859     applyTemplate : function(values){
13860         var s = this.subs;
13861         var replaceIndex = -1;
13862         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13863             return s[++replaceIndex].buffer.join("");
13864         });
13865         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13866     },
13867
13868     apply : function(){
13869         return this.applyTemplate.apply(this, arguments);
13870     },
13871
13872     compile : function(){return this;}
13873 });
13874
13875 /**
13876  * Alias for fill().
13877  * @method
13878  */
13879 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13880  /**
13881  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13882  * var tpl = Roo.MasterTemplate.from('element-id');
13883  * @param {String/HTMLElement} el
13884  * @param {Object} config
13885  * @static
13886  */
13887 Roo.MasterTemplate.from = function(el, config){
13888     el = Roo.getDom(el);
13889     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13890 };/*
13891  * Based on:
13892  * Ext JS Library 1.1.1
13893  * Copyright(c) 2006-2007, Ext JS, LLC.
13894  *
13895  * Originally Released Under LGPL - original licence link has changed is not relivant.
13896  *
13897  * Fork - LGPL
13898  * <script type="text/javascript">
13899  */
13900
13901  
13902 /**
13903  * @class Roo.util.CSS
13904  * Utility class for manipulating CSS rules
13905  * @singleton
13906  */
13907 Roo.util.CSS = function(){
13908         var rules = null;
13909         var doc = document;
13910
13911     var camelRe = /(-[a-z])/gi;
13912     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13913
13914    return {
13915    /**
13916     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13917     * tag and appended to the HEAD of the document.
13918     * @param {String|Object} cssText The text containing the css rules
13919     * @param {String} id An id to add to the stylesheet for later removal
13920     * @return {StyleSheet}
13921     */
13922     createStyleSheet : function(cssText, id){
13923         var ss;
13924         var head = doc.getElementsByTagName("head")[0];
13925         var nrules = doc.createElement("style");
13926         nrules.setAttribute("type", "text/css");
13927         if(id){
13928             nrules.setAttribute("id", id);
13929         }
13930         if (typeof(cssText) != 'string') {
13931             // support object maps..
13932             // not sure if this a good idea.. 
13933             // perhaps it should be merged with the general css handling
13934             // and handle js style props.
13935             var cssTextNew = [];
13936             for(var n in cssText) {
13937                 var citems = [];
13938                 for(var k in cssText[n]) {
13939                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13940                 }
13941                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13942                 
13943             }
13944             cssText = cssTextNew.join("\n");
13945             
13946         }
13947        
13948        
13949        if(Roo.isIE){
13950            head.appendChild(nrules);
13951            ss = nrules.styleSheet;
13952            ss.cssText = cssText;
13953        }else{
13954            try{
13955                 nrules.appendChild(doc.createTextNode(cssText));
13956            }catch(e){
13957                nrules.cssText = cssText; 
13958            }
13959            head.appendChild(nrules);
13960            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13961        }
13962        this.cacheStyleSheet(ss);
13963        return ss;
13964    },
13965
13966    /**
13967     * Removes a style or link tag by id
13968     * @param {String} id The id of the tag
13969     */
13970    removeStyleSheet : function(id){
13971        var existing = doc.getElementById(id);
13972        if(existing){
13973            existing.parentNode.removeChild(existing);
13974        }
13975    },
13976
13977    /**
13978     * Dynamically swaps an existing stylesheet reference for a new one
13979     * @param {String} id The id of an existing link tag to remove
13980     * @param {String} url The href of the new stylesheet to include
13981     */
13982    swapStyleSheet : function(id, url){
13983        this.removeStyleSheet(id);
13984        var ss = doc.createElement("link");
13985        ss.setAttribute("rel", "stylesheet");
13986        ss.setAttribute("type", "text/css");
13987        ss.setAttribute("id", id);
13988        ss.setAttribute("href", url);
13989        doc.getElementsByTagName("head")[0].appendChild(ss);
13990    },
13991    
13992    /**
13993     * Refresh the rule cache if you have dynamically added stylesheets
13994     * @return {Object} An object (hash) of rules indexed by selector
13995     */
13996    refreshCache : function(){
13997        return this.getRules(true);
13998    },
13999
14000    // private
14001    cacheStyleSheet : function(stylesheet){
14002        if(!rules){
14003            rules = {};
14004        }
14005        try{// try catch for cross domain access issue
14006            var ssRules = stylesheet.cssRules || stylesheet.rules;
14007            for(var j = ssRules.length-1; j >= 0; --j){
14008                rules[ssRules[j].selectorText] = ssRules[j];
14009            }
14010        }catch(e){}
14011    },
14012    
14013    /**
14014     * Gets all css rules for the document
14015     * @param {Boolean} refreshCache true to refresh the internal cache
14016     * @return {Object} An object (hash) of rules indexed by selector
14017     */
14018    getRules : function(refreshCache){
14019                 if(rules == null || refreshCache){
14020                         rules = {};
14021                         var ds = doc.styleSheets;
14022                         for(var i =0, len = ds.length; i < len; i++){
14023                             try{
14024                         this.cacheStyleSheet(ds[i]);
14025                     }catch(e){} 
14026                 }
14027                 }
14028                 return rules;
14029         },
14030         
14031         /**
14032     * Gets an an individual CSS rule by selector(s)
14033     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14034     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14035     * @return {CSSRule} The CSS rule or null if one is not found
14036     */
14037    getRule : function(selector, refreshCache){
14038                 var rs = this.getRules(refreshCache);
14039                 if(!(selector instanceof Array)){
14040                     return rs[selector];
14041                 }
14042                 for(var i = 0; i < selector.length; i++){
14043                         if(rs[selector[i]]){
14044                                 return rs[selector[i]];
14045                         }
14046                 }
14047                 return null;
14048         },
14049         
14050         
14051         /**
14052     * Updates a rule property
14053     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14054     * @param {String} property The css property
14055     * @param {String} value The new value for the property
14056     * @return {Boolean} true If a rule was found and updated
14057     */
14058    updateRule : function(selector, property, value){
14059                 if(!(selector instanceof Array)){
14060                         var rule = this.getRule(selector);
14061                         if(rule){
14062                                 rule.style[property.replace(camelRe, camelFn)] = value;
14063                                 return true;
14064                         }
14065                 }else{
14066                         for(var i = 0; i < selector.length; i++){
14067                                 if(this.updateRule(selector[i], property, value)){
14068                                         return true;
14069                                 }
14070                         }
14071                 }
14072                 return false;
14073         }
14074    };   
14075 }();/*
14076  * Based on:
14077  * Ext JS Library 1.1.1
14078  * Copyright(c) 2006-2007, Ext JS, LLC.
14079  *
14080  * Originally Released Under LGPL - original licence link has changed is not relivant.
14081  *
14082  * Fork - LGPL
14083  * <script type="text/javascript">
14084  */
14085
14086  
14087
14088 /**
14089  * @class Roo.util.ClickRepeater
14090  * @extends Roo.util.Observable
14091  * 
14092  * A wrapper class which can be applied to any element. Fires a "click" event while the
14093  * mouse is pressed. The interval between firings may be specified in the config but
14094  * defaults to 10 milliseconds.
14095  * 
14096  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14097  * 
14098  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14099  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14100  * Similar to an autorepeat key delay.
14101  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14102  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14103  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14104  *           "interval" and "delay" are ignored. "immediate" is honored.
14105  * @cfg {Boolean} preventDefault True to prevent the default click event
14106  * @cfg {Boolean} stopDefault True to stop the default click event
14107  * 
14108  * @history
14109  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14110  *     2007-02-02 jvs Renamed to ClickRepeater
14111  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14112  *
14113  *  @constructor
14114  * @param {String/HTMLElement/Element} el The element to listen on
14115  * @param {Object} config
14116  **/
14117 Roo.util.ClickRepeater = function(el, config)
14118 {
14119     this.el = Roo.get(el);
14120     this.el.unselectable();
14121
14122     Roo.apply(this, config);
14123
14124     this.addEvents({
14125     /**
14126      * @event mousedown
14127      * Fires when the mouse button is depressed.
14128      * @param {Roo.util.ClickRepeater} this
14129      */
14130         "mousedown" : true,
14131     /**
14132      * @event click
14133      * Fires on a specified interval during the time the element is pressed.
14134      * @param {Roo.util.ClickRepeater} this
14135      */
14136         "click" : true,
14137     /**
14138      * @event mouseup
14139      * Fires when the mouse key is released.
14140      * @param {Roo.util.ClickRepeater} this
14141      */
14142         "mouseup" : true
14143     });
14144
14145     this.el.on("mousedown", this.handleMouseDown, this);
14146     if(this.preventDefault || this.stopDefault){
14147         this.el.on("click", function(e){
14148             if(this.preventDefault){
14149                 e.preventDefault();
14150             }
14151             if(this.stopDefault){
14152                 e.stopEvent();
14153             }
14154         }, this);
14155     }
14156
14157     // allow inline handler
14158     if(this.handler){
14159         this.on("click", this.handler,  this.scope || this);
14160     }
14161
14162     Roo.util.ClickRepeater.superclass.constructor.call(this);
14163 };
14164
14165 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14166     interval : 20,
14167     delay: 250,
14168     preventDefault : true,
14169     stopDefault : false,
14170     timer : 0,
14171
14172     // private
14173     handleMouseDown : function(){
14174         clearTimeout(this.timer);
14175         this.el.blur();
14176         if(this.pressClass){
14177             this.el.addClass(this.pressClass);
14178         }
14179         this.mousedownTime = new Date();
14180
14181         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14182         this.el.on("mouseout", this.handleMouseOut, this);
14183
14184         this.fireEvent("mousedown", this);
14185         this.fireEvent("click", this);
14186         
14187         this.timer = this.click.defer(this.delay || this.interval, this);
14188     },
14189
14190     // private
14191     click : function(){
14192         this.fireEvent("click", this);
14193         this.timer = this.click.defer(this.getInterval(), this);
14194     },
14195
14196     // private
14197     getInterval: function(){
14198         if(!this.accelerate){
14199             return this.interval;
14200         }
14201         var pressTime = this.mousedownTime.getElapsed();
14202         if(pressTime < 500){
14203             return 400;
14204         }else if(pressTime < 1700){
14205             return 320;
14206         }else if(pressTime < 2600){
14207             return 250;
14208         }else if(pressTime < 3500){
14209             return 180;
14210         }else if(pressTime < 4400){
14211             return 140;
14212         }else if(pressTime < 5300){
14213             return 80;
14214         }else if(pressTime < 6200){
14215             return 50;
14216         }else{
14217             return 10;
14218         }
14219     },
14220
14221     // private
14222     handleMouseOut : function(){
14223         clearTimeout(this.timer);
14224         if(this.pressClass){
14225             this.el.removeClass(this.pressClass);
14226         }
14227         this.el.on("mouseover", this.handleMouseReturn, this);
14228     },
14229
14230     // private
14231     handleMouseReturn : function(){
14232         this.el.un("mouseover", this.handleMouseReturn);
14233         if(this.pressClass){
14234             this.el.addClass(this.pressClass);
14235         }
14236         this.click();
14237     },
14238
14239     // private
14240     handleMouseUp : function(){
14241         clearTimeout(this.timer);
14242         this.el.un("mouseover", this.handleMouseReturn);
14243         this.el.un("mouseout", this.handleMouseOut);
14244         Roo.get(document).un("mouseup", this.handleMouseUp);
14245         this.el.removeClass(this.pressClass);
14246         this.fireEvent("mouseup", this);
14247     }
14248 });/*
14249  * Based on:
14250  * Ext JS Library 1.1.1
14251  * Copyright(c) 2006-2007, Ext JS, LLC.
14252  *
14253  * Originally Released Under LGPL - original licence link has changed is not relivant.
14254  *
14255  * Fork - LGPL
14256  * <script type="text/javascript">
14257  */
14258
14259  
14260 /**
14261  * @class Roo.KeyNav
14262  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14263  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14264  * way to implement custom navigation schemes for any UI component.</p>
14265  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14266  * pageUp, pageDown, del, home, end.  Usage:</p>
14267  <pre><code>
14268 var nav = new Roo.KeyNav("my-element", {
14269     "left" : function(e){
14270         this.moveLeft(e.ctrlKey);
14271     },
14272     "right" : function(e){
14273         this.moveRight(e.ctrlKey);
14274     },
14275     "enter" : function(e){
14276         this.save();
14277     },
14278     scope : this
14279 });
14280 </code></pre>
14281  * @constructor
14282  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14283  * @param {Object} config The config
14284  */
14285 Roo.KeyNav = function(el, config){
14286     this.el = Roo.get(el);
14287     Roo.apply(this, config);
14288     if(!this.disabled){
14289         this.disabled = true;
14290         this.enable();
14291     }
14292 };
14293
14294 Roo.KeyNav.prototype = {
14295     /**
14296      * @cfg {Boolean} disabled
14297      * True to disable this KeyNav instance (defaults to false)
14298      */
14299     disabled : false,
14300     /**
14301      * @cfg {String} defaultEventAction
14302      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14303      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14304      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14305      */
14306     defaultEventAction: "stopEvent",
14307     /**
14308      * @cfg {Boolean} forceKeyDown
14309      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14310      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14311      * handle keydown instead of keypress.
14312      */
14313     forceKeyDown : false,
14314
14315     // private
14316     prepareEvent : function(e){
14317         var k = e.getKey();
14318         var h = this.keyToHandler[k];
14319         //if(h && this[h]){
14320         //    e.stopPropagation();
14321         //}
14322         if(Roo.isSafari && h && k >= 37 && k <= 40){
14323             e.stopEvent();
14324         }
14325     },
14326
14327     // private
14328     relay : function(e){
14329         var k = e.getKey();
14330         var h = this.keyToHandler[k];
14331         if(h && this[h]){
14332             if(this.doRelay(e, this[h], h) !== true){
14333                 e[this.defaultEventAction]();
14334             }
14335         }
14336     },
14337
14338     // private
14339     doRelay : function(e, h, hname){
14340         return h.call(this.scope || this, e);
14341     },
14342
14343     // possible handlers
14344     enter : false,
14345     left : false,
14346     right : false,
14347     up : false,
14348     down : false,
14349     tab : false,
14350     esc : false,
14351     pageUp : false,
14352     pageDown : false,
14353     del : false,
14354     home : false,
14355     end : false,
14356
14357     // quick lookup hash
14358     keyToHandler : {
14359         37 : "left",
14360         39 : "right",
14361         38 : "up",
14362         40 : "down",
14363         33 : "pageUp",
14364         34 : "pageDown",
14365         46 : "del",
14366         36 : "home",
14367         35 : "end",
14368         13 : "enter",
14369         27 : "esc",
14370         9  : "tab"
14371     },
14372
14373         /**
14374          * Enable this KeyNav
14375          */
14376         enable: function(){
14377                 if(this.disabled){
14378             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14379             // the EventObject will normalize Safari automatically
14380             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14381                 this.el.on("keydown", this.relay,  this);
14382             }else{
14383                 this.el.on("keydown", this.prepareEvent,  this);
14384                 this.el.on("keypress", this.relay,  this);
14385             }
14386                     this.disabled = false;
14387                 }
14388         },
14389
14390         /**
14391          * Disable this KeyNav
14392          */
14393         disable: function(){
14394                 if(!this.disabled){
14395                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14396                 this.el.un("keydown", this.relay);
14397             }else{
14398                 this.el.un("keydown", this.prepareEvent);
14399                 this.el.un("keypress", this.relay);
14400             }
14401                     this.disabled = true;
14402                 }
14403         }
14404 };/*
14405  * Based on:
14406  * Ext JS Library 1.1.1
14407  * Copyright(c) 2006-2007, Ext JS, LLC.
14408  *
14409  * Originally Released Under LGPL - original licence link has changed is not relivant.
14410  *
14411  * Fork - LGPL
14412  * <script type="text/javascript">
14413  */
14414
14415  
14416 /**
14417  * @class Roo.KeyMap
14418  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14419  * The constructor accepts the same config object as defined by {@link #addBinding}.
14420  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14421  * combination it will call the function with this signature (if the match is a multi-key
14422  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14423  * A KeyMap can also handle a string representation of keys.<br />
14424  * Usage:
14425  <pre><code>
14426 // map one key by key code
14427 var map = new Roo.KeyMap("my-element", {
14428     key: 13, // or Roo.EventObject.ENTER
14429     fn: myHandler,
14430     scope: myObject
14431 });
14432
14433 // map multiple keys to one action by string
14434 var map = new Roo.KeyMap("my-element", {
14435     key: "a\r\n\t",
14436     fn: myHandler,
14437     scope: myObject
14438 });
14439
14440 // map multiple keys to multiple actions by strings and array of codes
14441 var map = new Roo.KeyMap("my-element", [
14442     {
14443         key: [10,13],
14444         fn: function(){ alert("Return was pressed"); }
14445     }, {
14446         key: "abc",
14447         fn: function(){ alert('a, b or c was pressed'); }
14448     }, {
14449         key: "\t",
14450         ctrl:true,
14451         shift:true,
14452         fn: function(){ alert('Control + shift + tab was pressed.'); }
14453     }
14454 ]);
14455 </code></pre>
14456  * <b>Note: A KeyMap starts enabled</b>
14457  * @constructor
14458  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14459  * @param {Object} config The config (see {@link #addBinding})
14460  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14461  */
14462 Roo.KeyMap = function(el, config, eventName){
14463     this.el  = Roo.get(el);
14464     this.eventName = eventName || "keydown";
14465     this.bindings = [];
14466     if(config){
14467         this.addBinding(config);
14468     }
14469     this.enable();
14470 };
14471
14472 Roo.KeyMap.prototype = {
14473     /**
14474      * True to stop the event from bubbling and prevent the default browser action if the
14475      * key was handled by the KeyMap (defaults to false)
14476      * @type Boolean
14477      */
14478     stopEvent : false,
14479
14480     /**
14481      * Add a new binding to this KeyMap. The following config object properties are supported:
14482      * <pre>
14483 Property    Type             Description
14484 ----------  ---------------  ----------------------------------------------------------------------
14485 key         String/Array     A single keycode or an array of keycodes to handle
14486 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14487 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14488 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14489 fn          Function         The function to call when KeyMap finds the expected key combination
14490 scope       Object           The scope of the callback function
14491 </pre>
14492      *
14493      * Usage:
14494      * <pre><code>
14495 // Create a KeyMap
14496 var map = new Roo.KeyMap(document, {
14497     key: Roo.EventObject.ENTER,
14498     fn: handleKey,
14499     scope: this
14500 });
14501
14502 //Add a new binding to the existing KeyMap later
14503 map.addBinding({
14504     key: 'abc',
14505     shift: true,
14506     fn: handleKey,
14507     scope: this
14508 });
14509 </code></pre>
14510      * @param {Object/Array} config A single KeyMap config or an array of configs
14511      */
14512         addBinding : function(config){
14513         if(config instanceof Array){
14514             for(var i = 0, len = config.length; i < len; i++){
14515                 this.addBinding(config[i]);
14516             }
14517             return;
14518         }
14519         var keyCode = config.key,
14520             shift = config.shift, 
14521             ctrl = config.ctrl, 
14522             alt = config.alt,
14523             fn = config.fn,
14524             scope = config.scope;
14525         if(typeof keyCode == "string"){
14526             var ks = [];
14527             var keyString = keyCode.toUpperCase();
14528             for(var j = 0, len = keyString.length; j < len; j++){
14529                 ks.push(keyString.charCodeAt(j));
14530             }
14531             keyCode = ks;
14532         }
14533         var keyArray = keyCode instanceof Array;
14534         var handler = function(e){
14535             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14536                 var k = e.getKey();
14537                 if(keyArray){
14538                     for(var i = 0, len = keyCode.length; i < len; i++){
14539                         if(keyCode[i] == k){
14540                           if(this.stopEvent){
14541                               e.stopEvent();
14542                           }
14543                           fn.call(scope || window, k, e);
14544                           return;
14545                         }
14546                     }
14547                 }else{
14548                     if(k == keyCode){
14549                         if(this.stopEvent){
14550                            e.stopEvent();
14551                         }
14552                         fn.call(scope || window, k, e);
14553                     }
14554                 }
14555             }
14556         };
14557         this.bindings.push(handler);  
14558         },
14559
14560     /**
14561      * Shorthand for adding a single key listener
14562      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14563      * following options:
14564      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14565      * @param {Function} fn The function to call
14566      * @param {Object} scope (optional) The scope of the function
14567      */
14568     on : function(key, fn, scope){
14569         var keyCode, shift, ctrl, alt;
14570         if(typeof key == "object" && !(key instanceof Array)){
14571             keyCode = key.key;
14572             shift = key.shift;
14573             ctrl = key.ctrl;
14574             alt = key.alt;
14575         }else{
14576             keyCode = key;
14577         }
14578         this.addBinding({
14579             key: keyCode,
14580             shift: shift,
14581             ctrl: ctrl,
14582             alt: alt,
14583             fn: fn,
14584             scope: scope
14585         })
14586     },
14587
14588     // private
14589     handleKeyDown : function(e){
14590             if(this.enabled){ //just in case
14591             var b = this.bindings;
14592             for(var i = 0, len = b.length; i < len; i++){
14593                 b[i].call(this, e);
14594             }
14595             }
14596         },
14597         
14598         /**
14599          * Returns true if this KeyMap is enabled
14600          * @return {Boolean} 
14601          */
14602         isEnabled : function(){
14603             return this.enabled;  
14604         },
14605         
14606         /**
14607          * Enables this KeyMap
14608          */
14609         enable: function(){
14610                 if(!this.enabled){
14611                     this.el.on(this.eventName, this.handleKeyDown, this);
14612                     this.enabled = true;
14613                 }
14614         },
14615
14616         /**
14617          * Disable this KeyMap
14618          */
14619         disable: function(){
14620                 if(this.enabled){
14621                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14622                     this.enabled = false;
14623                 }
14624         }
14625 };/*
14626  * Based on:
14627  * Ext JS Library 1.1.1
14628  * Copyright(c) 2006-2007, Ext JS, LLC.
14629  *
14630  * Originally Released Under LGPL - original licence link has changed is not relivant.
14631  *
14632  * Fork - LGPL
14633  * <script type="text/javascript">
14634  */
14635
14636  
14637 /**
14638  * @class Roo.util.TextMetrics
14639  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14640  * wide, in pixels, a given block of text will be.
14641  * @singleton
14642  */
14643 Roo.util.TextMetrics = function(){
14644     var shared;
14645     return {
14646         /**
14647          * Measures the size of the specified text
14648          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14649          * that can affect the size of the rendered text
14650          * @param {String} text The text to measure
14651          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14652          * in order to accurately measure the text height
14653          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14654          */
14655         measure : function(el, text, fixedWidth){
14656             if(!shared){
14657                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14658             }
14659             shared.bind(el);
14660             shared.setFixedWidth(fixedWidth || 'auto');
14661             return shared.getSize(text);
14662         },
14663
14664         /**
14665          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14666          * the overhead of multiple calls to initialize the style properties on each measurement.
14667          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14668          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14669          * in order to accurately measure the text height
14670          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14671          */
14672         createInstance : function(el, fixedWidth){
14673             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14674         }
14675     };
14676 }();
14677
14678  
14679
14680 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14681     var ml = new Roo.Element(document.createElement('div'));
14682     document.body.appendChild(ml.dom);
14683     ml.position('absolute');
14684     ml.setLeftTop(-1000, -1000);
14685     ml.hide();
14686
14687     if(fixedWidth){
14688         ml.setWidth(fixedWidth);
14689     }
14690      
14691     var instance = {
14692         /**
14693          * Returns the size of the specified text based on the internal element's style and width properties
14694          * @memberOf Roo.util.TextMetrics.Instance#
14695          * @param {String} text The text to measure
14696          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14697          */
14698         getSize : function(text){
14699             ml.update(text);
14700             var s = ml.getSize();
14701             ml.update('');
14702             return s;
14703         },
14704
14705         /**
14706          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14707          * that can affect the size of the rendered text
14708          * @memberOf Roo.util.TextMetrics.Instance#
14709          * @param {String/HTMLElement} el The element, dom node or id
14710          */
14711         bind : function(el){
14712             ml.setStyle(
14713                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14714             );
14715         },
14716
14717         /**
14718          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14719          * to set a fixed width in order to accurately measure the text height.
14720          * @memberOf Roo.util.TextMetrics.Instance#
14721          * @param {Number} width The width to set on the element
14722          */
14723         setFixedWidth : function(width){
14724             ml.setWidth(width);
14725         },
14726
14727         /**
14728          * Returns the measured width of the specified text
14729          * @memberOf Roo.util.TextMetrics.Instance#
14730          * @param {String} text The text to measure
14731          * @return {Number} width The width in pixels
14732          */
14733         getWidth : function(text){
14734             ml.dom.style.width = 'auto';
14735             return this.getSize(text).width;
14736         },
14737
14738         /**
14739          * Returns the measured height of the specified text.  For multiline text, be sure to call
14740          * {@link #setFixedWidth} if necessary.
14741          * @memberOf Roo.util.TextMetrics.Instance#
14742          * @param {String} text The text to measure
14743          * @return {Number} height The height in pixels
14744          */
14745         getHeight : function(text){
14746             return this.getSize(text).height;
14747         }
14748     };
14749
14750     instance.bind(bindTo);
14751
14752     return instance;
14753 };
14754
14755 // backwards compat
14756 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14757  * Based on:
14758  * Ext JS Library 1.1.1
14759  * Copyright(c) 2006-2007, Ext JS, LLC.
14760  *
14761  * Originally Released Under LGPL - original licence link has changed is not relivant.
14762  *
14763  * Fork - LGPL
14764  * <script type="text/javascript">
14765  */
14766
14767 /**
14768  * @class Roo.state.Provider
14769  * Abstract base class for state provider implementations. This class provides methods
14770  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14771  * Provider interface.
14772  */
14773 Roo.state.Provider = function(){
14774     /**
14775      * @event statechange
14776      * Fires when a state change occurs.
14777      * @param {Provider} this This state provider
14778      * @param {String} key The state key which was changed
14779      * @param {String} value The encoded value for the state
14780      */
14781     this.addEvents({
14782         "statechange": true
14783     });
14784     this.state = {};
14785     Roo.state.Provider.superclass.constructor.call(this);
14786 };
14787 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14788     /**
14789      * Returns the current value for a key
14790      * @param {String} name The key name
14791      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14792      * @return {Mixed} The state data
14793      */
14794     get : function(name, defaultValue){
14795         return typeof this.state[name] == "undefined" ?
14796             defaultValue : this.state[name];
14797     },
14798     
14799     /**
14800      * Clears a value from the state
14801      * @param {String} name The key name
14802      */
14803     clear : function(name){
14804         delete this.state[name];
14805         this.fireEvent("statechange", this, name, null);
14806     },
14807     
14808     /**
14809      * Sets the value for a key
14810      * @param {String} name The key name
14811      * @param {Mixed} value The value to set
14812      */
14813     set : function(name, value){
14814         this.state[name] = value;
14815         this.fireEvent("statechange", this, name, value);
14816     },
14817     
14818     /**
14819      * Decodes a string previously encoded with {@link #encodeValue}.
14820      * @param {String} value The value to decode
14821      * @return {Mixed} The decoded value
14822      */
14823     decodeValue : function(cookie){
14824         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14825         var matches = re.exec(unescape(cookie));
14826         if(!matches || !matches[1]) return; // non state cookie
14827         var type = matches[1];
14828         var v = matches[2];
14829         switch(type){
14830             case "n":
14831                 return parseFloat(v);
14832             case "d":
14833                 return new Date(Date.parse(v));
14834             case "b":
14835                 return (v == "1");
14836             case "a":
14837                 var all = [];
14838                 var values = v.split("^");
14839                 for(var i = 0, len = values.length; i < len; i++){
14840                     all.push(this.decodeValue(values[i]));
14841                 }
14842                 return all;
14843            case "o":
14844                 var all = {};
14845                 var values = v.split("^");
14846                 for(var i = 0, len = values.length; i < len; i++){
14847                     var kv = values[i].split("=");
14848                     all[kv[0]] = this.decodeValue(kv[1]);
14849                 }
14850                 return all;
14851            default:
14852                 return v;
14853         }
14854     },
14855     
14856     /**
14857      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14858      * @param {Mixed} value The value to encode
14859      * @return {String} The encoded value
14860      */
14861     encodeValue : function(v){
14862         var enc;
14863         if(typeof v == "number"){
14864             enc = "n:" + v;
14865         }else if(typeof v == "boolean"){
14866             enc = "b:" + (v ? "1" : "0");
14867         }else if(v instanceof Date){
14868             enc = "d:" + v.toGMTString();
14869         }else if(v instanceof Array){
14870             var flat = "";
14871             for(var i = 0, len = v.length; i < len; i++){
14872                 flat += this.encodeValue(v[i]);
14873                 if(i != len-1) flat += "^";
14874             }
14875             enc = "a:" + flat;
14876         }else if(typeof v == "object"){
14877             var flat = "";
14878             for(var key in v){
14879                 if(typeof v[key] != "function"){
14880                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14881                 }
14882             }
14883             enc = "o:" + flat.substring(0, flat.length-1);
14884         }else{
14885             enc = "s:" + v;
14886         }
14887         return escape(enc);        
14888     }
14889 });
14890
14891 /*
14892  * Based on:
14893  * Ext JS Library 1.1.1
14894  * Copyright(c) 2006-2007, Ext JS, LLC.
14895  *
14896  * Originally Released Under LGPL - original licence link has changed is not relivant.
14897  *
14898  * Fork - LGPL
14899  * <script type="text/javascript">
14900  */
14901 /**
14902  * @class Roo.state.Manager
14903  * This is the global state manager. By default all components that are "state aware" check this class
14904  * for state information if you don't pass them a custom state provider. In order for this class
14905  * to be useful, it must be initialized with a provider when your application initializes.
14906  <pre><code>
14907 // in your initialization function
14908 init : function(){
14909    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14910    ...
14911    // supposed you have a {@link Roo.BorderLayout}
14912    var layout = new Roo.BorderLayout(...);
14913    layout.restoreState();
14914    // or a {Roo.BasicDialog}
14915    var dialog = new Roo.BasicDialog(...);
14916    dialog.restoreState();
14917  </code></pre>
14918  * @singleton
14919  */
14920 Roo.state.Manager = function(){
14921     var provider = new Roo.state.Provider();
14922     
14923     return {
14924         /**
14925          * Configures the default state provider for your application
14926          * @param {Provider} stateProvider The state provider to set
14927          */
14928         setProvider : function(stateProvider){
14929             provider = stateProvider;
14930         },
14931         
14932         /**
14933          * Returns the current value for a key
14934          * @param {String} name The key name
14935          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14936          * @return {Mixed} The state data
14937          */
14938         get : function(key, defaultValue){
14939             return provider.get(key, defaultValue);
14940         },
14941         
14942         /**
14943          * Sets the value for a key
14944          * @param {String} name The key name
14945          * @param {Mixed} value The state data
14946          */
14947          set : function(key, value){
14948             provider.set(key, value);
14949         },
14950         
14951         /**
14952          * Clears a value from the state
14953          * @param {String} name The key name
14954          */
14955         clear : function(key){
14956             provider.clear(key);
14957         },
14958         
14959         /**
14960          * Gets the currently configured state provider
14961          * @return {Provider} The state provider
14962          */
14963         getProvider : function(){
14964             return provider;
14965         }
14966     };
14967 }();
14968 /*
14969  * Based on:
14970  * Ext JS Library 1.1.1
14971  * Copyright(c) 2006-2007, Ext JS, LLC.
14972  *
14973  * Originally Released Under LGPL - original licence link has changed is not relivant.
14974  *
14975  * Fork - LGPL
14976  * <script type="text/javascript">
14977  */
14978 /**
14979  * @class Roo.state.CookieProvider
14980  * @extends Roo.state.Provider
14981  * The default Provider implementation which saves state via cookies.
14982  * <br />Usage:
14983  <pre><code>
14984    var cp = new Roo.state.CookieProvider({
14985        path: "/cgi-bin/",
14986        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14987        domain: "roojs.com"
14988    })
14989    Roo.state.Manager.setProvider(cp);
14990  </code></pre>
14991  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14992  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14993  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14994  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14995  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14996  * domain the page is running on including the 'www' like 'www.roojs.com')
14997  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14998  * @constructor
14999  * Create a new CookieProvider
15000  * @param {Object} config The configuration object
15001  */
15002 Roo.state.CookieProvider = function(config){
15003     Roo.state.CookieProvider.superclass.constructor.call(this);
15004     this.path = "/";
15005     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
15006     this.domain = null;
15007     this.secure = false;
15008     Roo.apply(this, config);
15009     this.state = this.readCookies();
15010 };
15011
15012 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
15013     // private
15014     set : function(name, value){
15015         if(typeof value == "undefined" || value === null){
15016             this.clear(name);
15017             return;
15018         }
15019         this.setCookie(name, value);
15020         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15021     },
15022
15023     // private
15024     clear : function(name){
15025         this.clearCookie(name);
15026         Roo.state.CookieProvider.superclass.clear.call(this, name);
15027     },
15028
15029     // private
15030     readCookies : function(){
15031         var cookies = {};
15032         var c = document.cookie + ";";
15033         var re = /\s?(.*?)=(.*?);/g;
15034         var matches;
15035         while((matches = re.exec(c)) != null){
15036             var name = matches[1];
15037             var value = matches[2];
15038             if(name && name.substring(0,3) == "ys-"){
15039                 cookies[name.substr(3)] = this.decodeValue(value);
15040             }
15041         }
15042         return cookies;
15043     },
15044
15045     // private
15046     setCookie : function(name, value){
15047         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15048            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15049            ((this.path == null) ? "" : ("; path=" + this.path)) +
15050            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15051            ((this.secure == true) ? "; secure" : "");
15052     },
15053
15054     // private
15055     clearCookie : function(name){
15056         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15057            ((this.path == null) ? "" : ("; path=" + this.path)) +
15058            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15059            ((this.secure == true) ? "; secure" : "");
15060     }
15061 });/*
15062  * Based on:
15063  * Ext JS Library 1.1.1
15064  * Copyright(c) 2006-2007, Ext JS, LLC.
15065  *
15066  * Originally Released Under LGPL - original licence link has changed is not relivant.
15067  *
15068  * Fork - LGPL
15069  * <script type="text/javascript">
15070  */
15071  
15072
15073 /**
15074  * @class Roo.ComponentMgr
15075  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15076  * @singleton
15077  */
15078 Roo.ComponentMgr = function(){
15079     var all = new Roo.util.MixedCollection();
15080
15081     return {
15082         /**
15083          * Registers a component.
15084          * @param {Roo.Component} c The component
15085          */
15086         register : function(c){
15087             all.add(c);
15088         },
15089
15090         /**
15091          * Unregisters a component.
15092          * @param {Roo.Component} c The component
15093          */
15094         unregister : function(c){
15095             all.remove(c);
15096         },
15097
15098         /**
15099          * Returns a component by id
15100          * @param {String} id The component id
15101          */
15102         get : function(id){
15103             return all.get(id);
15104         },
15105
15106         /**
15107          * Registers a function that will be called when a specified component is added to ComponentMgr
15108          * @param {String} id The component id
15109          * @param {Funtction} fn The callback function
15110          * @param {Object} scope The scope of the callback
15111          */
15112         onAvailable : function(id, fn, scope){
15113             all.on("add", function(index, o){
15114                 if(o.id == id){
15115                     fn.call(scope || o, o);
15116                     all.un("add", fn, scope);
15117                 }
15118             });
15119         }
15120     };
15121 }();/*
15122  * Based on:
15123  * Ext JS Library 1.1.1
15124  * Copyright(c) 2006-2007, Ext JS, LLC.
15125  *
15126  * Originally Released Under LGPL - original licence link has changed is not relivant.
15127  *
15128  * Fork - LGPL
15129  * <script type="text/javascript">
15130  */
15131  
15132 /**
15133  * @class Roo.Component
15134  * @extends Roo.util.Observable
15135  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15136  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15137  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15138  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15139  * All visual components (widgets) that require rendering into a layout should subclass Component.
15140  * @constructor
15141  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15142  * 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
15143  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15144  */
15145 Roo.Component = function(config){
15146     config = config || {};
15147     if(config.tagName || config.dom || typeof config == "string"){ // element object
15148         config = {el: config, id: config.id || config};
15149     }
15150     this.initialConfig = config;
15151
15152     Roo.apply(this, config);
15153     this.addEvents({
15154         /**
15155          * @event disable
15156          * Fires after the component is disabled.
15157              * @param {Roo.Component} this
15158              */
15159         disable : true,
15160         /**
15161          * @event enable
15162          * Fires after the component is enabled.
15163              * @param {Roo.Component} this
15164              */
15165         enable : true,
15166         /**
15167          * @event beforeshow
15168          * Fires before the component is shown.  Return false to stop the show.
15169              * @param {Roo.Component} this
15170              */
15171         beforeshow : true,
15172         /**
15173          * @event show
15174          * Fires after the component is shown.
15175              * @param {Roo.Component} this
15176              */
15177         show : true,
15178         /**
15179          * @event beforehide
15180          * Fires before the component is hidden. Return false to stop the hide.
15181              * @param {Roo.Component} this
15182              */
15183         beforehide : true,
15184         /**
15185          * @event hide
15186          * Fires after the component is hidden.
15187              * @param {Roo.Component} this
15188              */
15189         hide : true,
15190         /**
15191          * @event beforerender
15192          * Fires before the component is rendered. Return false to stop the render.
15193              * @param {Roo.Component} this
15194              */
15195         beforerender : true,
15196         /**
15197          * @event render
15198          * Fires after the component is rendered.
15199              * @param {Roo.Component} this
15200              */
15201         render : true,
15202         /**
15203          * @event beforedestroy
15204          * Fires before the component is destroyed. Return false to stop the destroy.
15205              * @param {Roo.Component} this
15206              */
15207         beforedestroy : true,
15208         /**
15209          * @event destroy
15210          * Fires after the component is destroyed.
15211              * @param {Roo.Component} this
15212              */
15213         destroy : true
15214     });
15215     if(!this.id){
15216         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15217     }
15218     Roo.ComponentMgr.register(this);
15219     Roo.Component.superclass.constructor.call(this);
15220     this.initComponent();
15221     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15222         this.render(this.renderTo);
15223         delete this.renderTo;
15224     }
15225 };
15226
15227 /** @private */
15228 Roo.Component.AUTO_ID = 1000;
15229
15230 Roo.extend(Roo.Component, Roo.util.Observable, {
15231     /**
15232      * @scope Roo.Component.prototype
15233      * @type {Boolean}
15234      * true if this component is hidden. Read-only.
15235      */
15236     hidden : false,
15237     /**
15238      * @type {Boolean}
15239      * true if this component is disabled. Read-only.
15240      */
15241     disabled : false,
15242     /**
15243      * @type {Boolean}
15244      * true if this component has been rendered. Read-only.
15245      */
15246     rendered : false,
15247     
15248     /** @cfg {String} disableClass
15249      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15250      */
15251     disabledClass : "x-item-disabled",
15252         /** @cfg {Boolean} allowDomMove
15253          * Whether the component can move the Dom node when rendering (defaults to true).
15254          */
15255     allowDomMove : true,
15256     /** @cfg {String} hideMode (display|visibility)
15257      * How this component should hidden. Supported values are
15258      * "visibility" (css visibility), "offsets" (negative offset position) and
15259      * "display" (css display) - defaults to "display".
15260      */
15261     hideMode: 'display',
15262
15263     /** @private */
15264     ctype : "Roo.Component",
15265
15266     /**
15267      * @cfg {String} actionMode 
15268      * which property holds the element that used for  hide() / show() / disable() / enable()
15269      * default is 'el' 
15270      */
15271     actionMode : "el",
15272
15273     /** @private */
15274     getActionEl : function(){
15275         return this[this.actionMode];
15276     },
15277
15278     initComponent : Roo.emptyFn,
15279     /**
15280      * If this is a lazy rendering component, render it to its container element.
15281      * @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.
15282      */
15283     render : function(container, position){
15284         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15285             if(!container && this.el){
15286                 this.el = Roo.get(this.el);
15287                 container = this.el.dom.parentNode;
15288                 this.allowDomMove = false;
15289             }
15290             this.container = Roo.get(container);
15291             this.rendered = true;
15292             if(position !== undefined){
15293                 if(typeof position == 'number'){
15294                     position = this.container.dom.childNodes[position];
15295                 }else{
15296                     position = Roo.getDom(position);
15297                 }
15298             }
15299             this.onRender(this.container, position || null);
15300             if(this.cls){
15301                 this.el.addClass(this.cls);
15302                 delete this.cls;
15303             }
15304             if(this.style){
15305                 this.el.applyStyles(this.style);
15306                 delete this.style;
15307             }
15308             this.fireEvent("render", this);
15309             this.afterRender(this.container);
15310             if(this.hidden){
15311                 this.hide();
15312             }
15313             if(this.disabled){
15314                 this.disable();
15315             }
15316         }
15317         return this;
15318     },
15319
15320     /** @private */
15321     // default function is not really useful
15322     onRender : function(ct, position){
15323         if(this.el){
15324             this.el = Roo.get(this.el);
15325             if(this.allowDomMove !== false){
15326                 ct.dom.insertBefore(this.el.dom, position);
15327             }
15328         }
15329     },
15330
15331     /** @private */
15332     getAutoCreate : function(){
15333         var cfg = typeof this.autoCreate == "object" ?
15334                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15335         if(this.id && !cfg.id){
15336             cfg.id = this.id;
15337         }
15338         return cfg;
15339     },
15340
15341     /** @private */
15342     afterRender : Roo.emptyFn,
15343
15344     /**
15345      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15346      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15347      */
15348     destroy : function(){
15349         if(this.fireEvent("beforedestroy", this) !== false){
15350             this.purgeListeners();
15351             this.beforeDestroy();
15352             if(this.rendered){
15353                 this.el.removeAllListeners();
15354                 this.el.remove();
15355                 if(this.actionMode == "container"){
15356                     this.container.remove();
15357                 }
15358             }
15359             this.onDestroy();
15360             Roo.ComponentMgr.unregister(this);
15361             this.fireEvent("destroy", this);
15362         }
15363     },
15364
15365         /** @private */
15366     beforeDestroy : function(){
15367
15368     },
15369
15370         /** @private */
15371         onDestroy : function(){
15372
15373     },
15374
15375     /**
15376      * Returns the underlying {@link Roo.Element}.
15377      * @return {Roo.Element} The element
15378      */
15379     getEl : function(){
15380         return this.el;
15381     },
15382
15383     /**
15384      * Returns the id of this component.
15385      * @return {String}
15386      */
15387     getId : function(){
15388         return this.id;
15389     },
15390
15391     /**
15392      * Try to focus this component.
15393      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15394      * @return {Roo.Component} this
15395      */
15396     focus : function(selectText){
15397         if(this.rendered){
15398             this.el.focus();
15399             if(selectText === true){
15400                 this.el.dom.select();
15401             }
15402         }
15403         return this;
15404     },
15405
15406     /** @private */
15407     blur : function(){
15408         if(this.rendered){
15409             this.el.blur();
15410         }
15411         return this;
15412     },
15413
15414     /**
15415      * Disable this component.
15416      * @return {Roo.Component} this
15417      */
15418     disable : function(){
15419         if(this.rendered){
15420             this.onDisable();
15421         }
15422         this.disabled = true;
15423         this.fireEvent("disable", this);
15424         return this;
15425     },
15426
15427         // private
15428     onDisable : function(){
15429         this.getActionEl().addClass(this.disabledClass);
15430         this.el.dom.disabled = true;
15431     },
15432
15433     /**
15434      * Enable this component.
15435      * @return {Roo.Component} this
15436      */
15437     enable : function(){
15438         if(this.rendered){
15439             this.onEnable();
15440         }
15441         this.disabled = false;
15442         this.fireEvent("enable", this);
15443         return this;
15444     },
15445
15446         // private
15447     onEnable : function(){
15448         this.getActionEl().removeClass(this.disabledClass);
15449         this.el.dom.disabled = false;
15450     },
15451
15452     /**
15453      * Convenience function for setting disabled/enabled by boolean.
15454      * @param {Boolean} disabled
15455      */
15456     setDisabled : function(disabled){
15457         this[disabled ? "disable" : "enable"]();
15458     },
15459
15460     /**
15461      * Show this component.
15462      * @return {Roo.Component} this
15463      */
15464     show: function(){
15465         if(this.fireEvent("beforeshow", this) !== false){
15466             this.hidden = false;
15467             if(this.rendered){
15468                 this.onShow();
15469             }
15470             this.fireEvent("show", this);
15471         }
15472         return this;
15473     },
15474
15475     // private
15476     onShow : function(){
15477         var ae = this.getActionEl();
15478         if(this.hideMode == 'visibility'){
15479             ae.dom.style.visibility = "visible";
15480         }else if(this.hideMode == 'offsets'){
15481             ae.removeClass('x-hidden');
15482         }else{
15483             ae.dom.style.display = "";
15484         }
15485     },
15486
15487     /**
15488      * Hide this component.
15489      * @return {Roo.Component} this
15490      */
15491     hide: function(){
15492         if(this.fireEvent("beforehide", this) !== false){
15493             this.hidden = true;
15494             if(this.rendered){
15495                 this.onHide();
15496             }
15497             this.fireEvent("hide", this);
15498         }
15499         return this;
15500     },
15501
15502     // private
15503     onHide : function(){
15504         var ae = this.getActionEl();
15505         if(this.hideMode == 'visibility'){
15506             ae.dom.style.visibility = "hidden";
15507         }else if(this.hideMode == 'offsets'){
15508             ae.addClass('x-hidden');
15509         }else{
15510             ae.dom.style.display = "none";
15511         }
15512     },
15513
15514     /**
15515      * Convenience function to hide or show this component by boolean.
15516      * @param {Boolean} visible True to show, false to hide
15517      * @return {Roo.Component} this
15518      */
15519     setVisible: function(visible){
15520         if(visible) {
15521             this.show();
15522         }else{
15523             this.hide();
15524         }
15525         return this;
15526     },
15527
15528     /**
15529      * Returns true if this component is visible.
15530      */
15531     isVisible : function(){
15532         return this.getActionEl().isVisible();
15533     },
15534
15535     cloneConfig : function(overrides){
15536         overrides = overrides || {};
15537         var id = overrides.id || Roo.id();
15538         var cfg = Roo.applyIf(overrides, this.initialConfig);
15539         cfg.id = id; // prevent dup id
15540         return new this.constructor(cfg);
15541     }
15542 });/*
15543  * Based on:
15544  * Ext JS Library 1.1.1
15545  * Copyright(c) 2006-2007, Ext JS, LLC.
15546  *
15547  * Originally Released Under LGPL - original licence link has changed is not relivant.
15548  *
15549  * Fork - LGPL
15550  * <script type="text/javascript">
15551  */
15552
15553 /**
15554  * @class Roo.BoxComponent
15555  * @extends Roo.Component
15556  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15557  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15558  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15559  * layout containers.
15560  * @constructor
15561  * @param {Roo.Element/String/Object} config The configuration options.
15562  */
15563 Roo.BoxComponent = function(config){
15564     Roo.Component.call(this, config);
15565     this.addEvents({
15566         /**
15567          * @event resize
15568          * Fires after the component is resized.
15569              * @param {Roo.Component} this
15570              * @param {Number} adjWidth The box-adjusted width that was set
15571              * @param {Number} adjHeight The box-adjusted height that was set
15572              * @param {Number} rawWidth The width that was originally specified
15573              * @param {Number} rawHeight The height that was originally specified
15574              */
15575         resize : true,
15576         /**
15577          * @event move
15578          * Fires after the component is moved.
15579              * @param {Roo.Component} this
15580              * @param {Number} x The new x position
15581              * @param {Number} y The new y position
15582              */
15583         move : true
15584     });
15585 };
15586
15587 Roo.extend(Roo.BoxComponent, Roo.Component, {
15588     // private, set in afterRender to signify that the component has been rendered
15589     boxReady : false,
15590     // private, used to defer height settings to subclasses
15591     deferHeight: false,
15592     /** @cfg {Number} width
15593      * width (optional) size of component
15594      */
15595      /** @cfg {Number} height
15596      * height (optional) size of component
15597      */
15598      
15599     /**
15600      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15601      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15602      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15603      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15604      * @return {Roo.BoxComponent} this
15605      */
15606     setSize : function(w, h){
15607         // support for standard size objects
15608         if(typeof w == 'object'){
15609             h = w.height;
15610             w = w.width;
15611         }
15612         // not rendered
15613         if(!this.boxReady){
15614             this.width = w;
15615             this.height = h;
15616             return this;
15617         }
15618
15619         // prevent recalcs when not needed
15620         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15621             return this;
15622         }
15623         this.lastSize = {width: w, height: h};
15624
15625         var adj = this.adjustSize(w, h);
15626         var aw = adj.width, ah = adj.height;
15627         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15628             var rz = this.getResizeEl();
15629             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15630                 rz.setSize(aw, ah);
15631             }else if(!this.deferHeight && ah !== undefined){
15632                 rz.setHeight(ah);
15633             }else if(aw !== undefined){
15634                 rz.setWidth(aw);
15635             }
15636             this.onResize(aw, ah, w, h);
15637             this.fireEvent('resize', this, aw, ah, w, h);
15638         }
15639         return this;
15640     },
15641
15642     /**
15643      * Gets the current size of the component's underlying element.
15644      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15645      */
15646     getSize : function(){
15647         return this.el.getSize();
15648     },
15649
15650     /**
15651      * Gets the current XY position of the component's underlying element.
15652      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15653      * @return {Array} The XY position of the element (e.g., [100, 200])
15654      */
15655     getPosition : function(local){
15656         if(local === true){
15657             return [this.el.getLeft(true), this.el.getTop(true)];
15658         }
15659         return this.xy || this.el.getXY();
15660     },
15661
15662     /**
15663      * Gets the current box measurements of the component's underlying element.
15664      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15665      * @returns {Object} box An object in the format {x, y, width, height}
15666      */
15667     getBox : function(local){
15668         var s = this.el.getSize();
15669         if(local){
15670             s.x = this.el.getLeft(true);
15671             s.y = this.el.getTop(true);
15672         }else{
15673             var xy = this.xy || this.el.getXY();
15674             s.x = xy[0];
15675             s.y = xy[1];
15676         }
15677         return s;
15678     },
15679
15680     /**
15681      * Sets the current box measurements of the component's underlying element.
15682      * @param {Object} box An object in the format {x, y, width, height}
15683      * @returns {Roo.BoxComponent} this
15684      */
15685     updateBox : function(box){
15686         this.setSize(box.width, box.height);
15687         this.setPagePosition(box.x, box.y);
15688         return this;
15689     },
15690
15691     // protected
15692     getResizeEl : function(){
15693         return this.resizeEl || this.el;
15694     },
15695
15696     // protected
15697     getPositionEl : function(){
15698         return this.positionEl || this.el;
15699     },
15700
15701     /**
15702      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15703      * This method fires the move event.
15704      * @param {Number} left The new left
15705      * @param {Number} top The new top
15706      * @returns {Roo.BoxComponent} this
15707      */
15708     setPosition : function(x, y){
15709         this.x = x;
15710         this.y = y;
15711         if(!this.boxReady){
15712             return this;
15713         }
15714         var adj = this.adjustPosition(x, y);
15715         var ax = adj.x, ay = adj.y;
15716
15717         var el = this.getPositionEl();
15718         if(ax !== undefined || ay !== undefined){
15719             if(ax !== undefined && ay !== undefined){
15720                 el.setLeftTop(ax, ay);
15721             }else if(ax !== undefined){
15722                 el.setLeft(ax);
15723             }else if(ay !== undefined){
15724                 el.setTop(ay);
15725             }
15726             this.onPosition(ax, ay);
15727             this.fireEvent('move', this, ax, ay);
15728         }
15729         return this;
15730     },
15731
15732     /**
15733      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15734      * This method fires the move event.
15735      * @param {Number} x The new x position
15736      * @param {Number} y The new y position
15737      * @returns {Roo.BoxComponent} this
15738      */
15739     setPagePosition : function(x, y){
15740         this.pageX = x;
15741         this.pageY = y;
15742         if(!this.boxReady){
15743             return;
15744         }
15745         if(x === undefined || y === undefined){ // cannot translate undefined points
15746             return;
15747         }
15748         var p = this.el.translatePoints(x, y);
15749         this.setPosition(p.left, p.top);
15750         return this;
15751     },
15752
15753     // private
15754     onRender : function(ct, position){
15755         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15756         if(this.resizeEl){
15757             this.resizeEl = Roo.get(this.resizeEl);
15758         }
15759         if(this.positionEl){
15760             this.positionEl = Roo.get(this.positionEl);
15761         }
15762     },
15763
15764     // private
15765     afterRender : function(){
15766         Roo.BoxComponent.superclass.afterRender.call(this);
15767         this.boxReady = true;
15768         this.setSize(this.width, this.height);
15769         if(this.x || this.y){
15770             this.setPosition(this.x, this.y);
15771         }
15772         if(this.pageX || this.pageY){
15773             this.setPagePosition(this.pageX, this.pageY);
15774         }
15775     },
15776
15777     /**
15778      * Force the component's size to recalculate based on the underlying element's current height and width.
15779      * @returns {Roo.BoxComponent} this
15780      */
15781     syncSize : function(){
15782         delete this.lastSize;
15783         this.setSize(this.el.getWidth(), this.el.getHeight());
15784         return this;
15785     },
15786
15787     /**
15788      * Called after the component is resized, this method is empty by default but can be implemented by any
15789      * subclass that needs to perform custom logic after a resize occurs.
15790      * @param {Number} adjWidth The box-adjusted width that was set
15791      * @param {Number} adjHeight The box-adjusted height that was set
15792      * @param {Number} rawWidth The width that was originally specified
15793      * @param {Number} rawHeight The height that was originally specified
15794      */
15795     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15796
15797     },
15798
15799     /**
15800      * Called after the component is moved, this method is empty by default but can be implemented by any
15801      * subclass that needs to perform custom logic after a move occurs.
15802      * @param {Number} x The new x position
15803      * @param {Number} y The new y position
15804      */
15805     onPosition : function(x, y){
15806
15807     },
15808
15809     // private
15810     adjustSize : function(w, h){
15811         if(this.autoWidth){
15812             w = 'auto';
15813         }
15814         if(this.autoHeight){
15815             h = 'auto';
15816         }
15817         return {width : w, height: h};
15818     },
15819
15820     // private
15821     adjustPosition : function(x, y){
15822         return {x : x, y: y};
15823     }
15824 });/*
15825  * Original code for Roojs - LGPL
15826  * <script type="text/javascript">
15827  */
15828  
15829 /**
15830  * @class Roo.XComponent
15831  * A delayed Element creator...
15832  * Or a way to group chunks of interface together.
15833  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15834  *  used in conjunction with XComponent.build() it will create an instance of each element,
15835  *  then call addxtype() to build the User interface.
15836  * 
15837  * Mypart.xyx = new Roo.XComponent({
15838
15839     parent : 'Mypart.xyz', // empty == document.element.!!
15840     order : '001',
15841     name : 'xxxx'
15842     region : 'xxxx'
15843     disabled : function() {} 
15844      
15845     tree : function() { // return an tree of xtype declared components
15846         var MODULE = this;
15847         return 
15848         {
15849             xtype : 'NestedLayoutPanel',
15850             // technicall
15851         }
15852      ]
15853  *})
15854  *
15855  *
15856  * It can be used to build a big heiracy, with parent etc.
15857  * or you can just use this to render a single compoent to a dom element
15858  * MYPART.render(Roo.Element | String(id) | dom_element )
15859  *
15860  *
15861  * Usage patterns.
15862  *
15863  * Classic Roo
15864  *
15865  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15866  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15867  *
15868  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15869  *
15870  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15871  * - if mulitple topModules exist, the last one is defined as the top module.
15872  *
15873  * Embeded Roo
15874  * 
15875  * When the top level or multiple modules are to embedded into a existing HTML page,
15876  * the parent element can container '#id' of the element where the module will be drawn.
15877  *
15878  * Bootstrap Roo
15879  *
15880  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15881  * it relies more on a include mechanism, where sub modules are included into an outer page.
15882  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15883  * 
15884  * Bootstrap Roo Included elements
15885  *
15886  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15887  * hence confusing the component builder as it thinks there are multiple top level elements. 
15888  *
15889  * 
15890  * 
15891  * @extends Roo.util.Observable
15892  * @constructor
15893  * @param cfg {Object} configuration of component
15894  * 
15895  */
15896 Roo.XComponent = function(cfg) {
15897     Roo.apply(this, cfg);
15898     this.addEvents({ 
15899         /**
15900              * @event built
15901              * Fires when this the componnt is built
15902              * @param {Roo.XComponent} c the component
15903              */
15904         'built' : true
15905         
15906     });
15907     this.region = this.region || 'center'; // default..
15908     Roo.XComponent.register(this);
15909     this.modules = false;
15910     this.el = false; // where the layout goes..
15911     
15912     
15913 }
15914 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15915     /**
15916      * @property el
15917      * The created element (with Roo.factory())
15918      * @type {Roo.Layout}
15919      */
15920     el  : false,
15921     
15922     /**
15923      * @property el
15924      * for BC  - use el in new code
15925      * @type {Roo.Layout}
15926      */
15927     panel : false,
15928     
15929     /**
15930      * @property layout
15931      * for BC  - use el in new code
15932      * @type {Roo.Layout}
15933      */
15934     layout : false,
15935     
15936      /**
15937      * @cfg {Function|boolean} disabled
15938      * If this module is disabled by some rule, return true from the funtion
15939      */
15940     disabled : false,
15941     
15942     /**
15943      * @cfg {String} parent 
15944      * Name of parent element which it get xtype added to..
15945      */
15946     parent: false,
15947     
15948     /**
15949      * @cfg {String} order
15950      * Used to set the order in which elements are created (usefull for multiple tabs)
15951      */
15952     
15953     order : false,
15954     /**
15955      * @cfg {String} name
15956      * String to display while loading.
15957      */
15958     name : false,
15959     /**
15960      * @cfg {String} region
15961      * Region to render component to (defaults to center)
15962      */
15963     region : 'center',
15964     
15965     /**
15966      * @cfg {Array} items
15967      * A single item array - the first element is the root of the tree..
15968      * It's done this way to stay compatible with the Xtype system...
15969      */
15970     items : false,
15971     
15972     /**
15973      * @property _tree
15974      * The method that retuns the tree of parts that make up this compoennt 
15975      * @type {function}
15976      */
15977     _tree  : false,
15978     
15979      /**
15980      * render
15981      * render element to dom or tree
15982      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15983      */
15984     
15985     render : function(el)
15986     {
15987         
15988         el = el || false;
15989         var hp = this.parent ? 1 : 0;
15990         Roo.debug &&  Roo.log(this);
15991         
15992         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15993             // if parent is a '#.....' string, then let's use that..
15994             var ename = this.parent.substr(1);
15995             this.parent = false;
15996             Roo.debug && Roo.log(ename);
15997             switch (ename) {
15998                 case 'bootstrap-body' :
15999                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
16000                         this.parent = { el :  new  Roo.bootstrap.Body() };
16001                         Roo.debug && Roo.log("setting el to doc body");
16002                          
16003                     } else {
16004                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
16005                     }
16006                     break;
16007                 case 'bootstrap':
16008                     this.parent = { el : true};
16009                     // fall through
16010                 default:
16011                     el = Roo.get(ename);
16012                     break;
16013             }
16014                 
16015             
16016             if (!el && !this.parent) {
16017                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
16018                 return;
16019             }
16020         }
16021         Roo.debug && Roo.log("EL:");
16022         Roo.debug && Roo.log(el);
16023         Roo.debug && Roo.log("this.parent.el:");
16024         Roo.debug && Roo.log(this.parent.el);
16025         
16026         var tree = this._tree ? this._tree() : this.tree();
16027
16028         // altertive root elements ??? - we need a better way to indicate these.
16029         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16030                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16031         
16032         if (!this.parent && is_alt) {
16033             //el = Roo.get(document.body);
16034             this.parent = { el : true };
16035         }
16036             
16037             
16038         
16039         if (!this.parent) {
16040             
16041             Roo.debug && Roo.log("no parent - creating one");
16042             
16043             el = el ? Roo.get(el) : false;      
16044             
16045             // it's a top level one..
16046             this.parent =  {
16047                 el : new Roo.BorderLayout(el || document.body, {
16048                 
16049                      center: {
16050                          titlebar: false,
16051                          autoScroll:false,
16052                          closeOnTab: true,
16053                          tabPosition: 'top',
16054                           //resizeTabs: true,
16055                          alwaysShowTabs: el && hp? false :  true,
16056                          hideTabs: el || !hp ? true :  false,
16057                          minTabWidth: 140
16058                      }
16059                  })
16060             }
16061         }
16062         
16063         if (!this.parent.el) {
16064                 // probably an old style ctor, which has been disabled.
16065                 return;
16066
16067         }
16068                 // The 'tree' method is  '_tree now' 
16069             
16070         tree.region = tree.region || this.region;
16071         
16072         if (this.parent.el === true) {
16073             // bootstrap... - body..
16074             this.parent.el = Roo.factory(tree);
16075         }
16076         
16077         this.el = this.parent.el.addxtype(tree);
16078         this.fireEvent('built', this);
16079         
16080         this.panel = this.el;
16081         this.layout = this.panel.layout;
16082         this.parentLayout = this.parent.layout  || false;  
16083          
16084     }
16085     
16086 });
16087
16088 Roo.apply(Roo.XComponent, {
16089     /**
16090      * @property  hideProgress
16091      * true to disable the building progress bar.. usefull on single page renders.
16092      * @type Boolean
16093      */
16094     hideProgress : false,
16095     /**
16096      * @property  buildCompleted
16097      * True when the builder has completed building the interface.
16098      * @type Boolean
16099      */
16100     buildCompleted : false,
16101      
16102     /**
16103      * @property  topModule
16104      * the upper most module - uses document.element as it's constructor.
16105      * @type Object
16106      */
16107      
16108     topModule  : false,
16109       
16110     /**
16111      * @property  modules
16112      * array of modules to be created by registration system.
16113      * @type {Array} of Roo.XComponent
16114      */
16115     
16116     modules : [],
16117     /**
16118      * @property  elmodules
16119      * array of modules to be created by which use #ID 
16120      * @type {Array} of Roo.XComponent
16121      */
16122      
16123     elmodules : [],
16124
16125      /**
16126      * @property  build_from_html
16127      * Build elements from html - used by bootstrap HTML stuff 
16128      *    - this is cleared after build is completed
16129      * @type {boolean} true  (default false)
16130      */
16131      
16132     build_from_html : false,
16133
16134     /**
16135      * Register components to be built later.
16136      *
16137      * This solves the following issues
16138      * - Building is not done on page load, but after an authentication process has occured.
16139      * - Interface elements are registered on page load
16140      * - Parent Interface elements may not be loaded before child, so this handles that..
16141      * 
16142      *
16143      * example:
16144      * 
16145      * MyApp.register({
16146           order : '000001',
16147           module : 'Pman.Tab.projectMgr',
16148           region : 'center',
16149           parent : 'Pman.layout',
16150           disabled : false,  // or use a function..
16151         })
16152      
16153      * * @param {Object} details about module
16154      */
16155     register : function(obj) {
16156                 
16157         Roo.XComponent.event.fireEvent('register', obj);
16158         switch(typeof(obj.disabled) ) {
16159                 
16160             case 'undefined':
16161                 break;
16162             
16163             case 'function':
16164                 if ( obj.disabled() ) {
16165                         return;
16166                 }
16167                 break;
16168             
16169             default:
16170                 if (obj.disabled) {
16171                         return;
16172                 }
16173                 break;
16174         }
16175                 
16176         this.modules.push(obj);
16177          
16178     },
16179     /**
16180      * convert a string to an object..
16181      * eg. 'AAA.BBB' -> finds AAA.BBB
16182
16183      */
16184     
16185     toObject : function(str)
16186     {
16187         if (!str || typeof(str) == 'object') {
16188             return str;
16189         }
16190         if (str.substring(0,1) == '#') {
16191             return str;
16192         }
16193
16194         var ar = str.split('.');
16195         var rt, o;
16196         rt = ar.shift();
16197             /** eval:var:o */
16198         try {
16199             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16200         } catch (e) {
16201             throw "Module not found : " + str;
16202         }
16203         
16204         if (o === false) {
16205             throw "Module not found : " + str;
16206         }
16207         Roo.each(ar, function(e) {
16208             if (typeof(o[e]) == 'undefined') {
16209                 throw "Module not found : " + str;
16210             }
16211             o = o[e];
16212         });
16213         
16214         return o;
16215         
16216     },
16217     
16218     
16219     /**
16220      * move modules into their correct place in the tree..
16221      * 
16222      */
16223     preBuild : function ()
16224     {
16225         var _t = this;
16226         Roo.each(this.modules , function (obj)
16227         {
16228             Roo.XComponent.event.fireEvent('beforebuild', obj);
16229             
16230             var opar = obj.parent;
16231             try { 
16232                 obj.parent = this.toObject(opar);
16233             } catch(e) {
16234                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16235                 return;
16236             }
16237             
16238             if (!obj.parent) {
16239                 Roo.debug && Roo.log("GOT top level module");
16240                 Roo.debug && Roo.log(obj);
16241                 obj.modules = new Roo.util.MixedCollection(false, 
16242                     function(o) { return o.order + '' }
16243                 );
16244                 this.topModule = obj;
16245                 return;
16246             }
16247                         // parent is a string (usually a dom element name..)
16248             if (typeof(obj.parent) == 'string') {
16249                 this.elmodules.push(obj);
16250                 return;
16251             }
16252             if (obj.parent.constructor != Roo.XComponent) {
16253                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16254             }
16255             if (!obj.parent.modules) {
16256                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16257                     function(o) { return o.order + '' }
16258                 );
16259             }
16260             if (obj.parent.disabled) {
16261                 obj.disabled = true;
16262             }
16263             obj.parent.modules.add(obj);
16264         }, this);
16265     },
16266     
16267      /**
16268      * make a list of modules to build.
16269      * @return {Array} list of modules. 
16270      */ 
16271     
16272     buildOrder : function()
16273     {
16274         var _this = this;
16275         var cmp = function(a,b) {   
16276             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16277         };
16278         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16279             throw "No top level modules to build";
16280         }
16281         
16282         // make a flat list in order of modules to build.
16283         var mods = this.topModule ? [ this.topModule ] : [];
16284                 
16285         
16286         // elmodules (is a list of DOM based modules )
16287         Roo.each(this.elmodules, function(e) {
16288             mods.push(e);
16289             if (!this.topModule &&
16290                 typeof(e.parent) == 'string' &&
16291                 e.parent.substring(0,1) == '#' &&
16292                 Roo.get(e.parent.substr(1))
16293                ) {
16294                 
16295                 _this.topModule = e;
16296             }
16297             
16298         });
16299
16300         
16301         // add modules to their parents..
16302         var addMod = function(m) {
16303             Roo.debug && Roo.log("build Order: add: " + m.name);
16304                 
16305             mods.push(m);
16306             if (m.modules && !m.disabled) {
16307                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16308                 m.modules.keySort('ASC',  cmp );
16309                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16310     
16311                 m.modules.each(addMod);
16312             } else {
16313                 Roo.debug && Roo.log("build Order: no child modules");
16314             }
16315             // not sure if this is used any more..
16316             if (m.finalize) {
16317                 m.finalize.name = m.name + " (clean up) ";
16318                 mods.push(m.finalize);
16319             }
16320             
16321         }
16322         if (this.topModule && this.topModule.modules) { 
16323             this.topModule.modules.keySort('ASC',  cmp );
16324             this.topModule.modules.each(addMod);
16325         } 
16326         return mods;
16327     },
16328     
16329      /**
16330      * Build the registered modules.
16331      * @param {Object} parent element.
16332      * @param {Function} optional method to call after module has been added.
16333      * 
16334      */ 
16335    
16336     build : function(opts) 
16337     {
16338         
16339         if (typeof(opts) != 'undefined') {
16340             Roo.apply(this,opts);
16341         }
16342         
16343         this.preBuild();
16344         var mods = this.buildOrder();
16345       
16346         //this.allmods = mods;
16347         //Roo.debug && Roo.log(mods);
16348         //return;
16349         if (!mods.length) { // should not happen
16350             throw "NO modules!!!";
16351         }
16352         
16353         
16354         var msg = "Building Interface...";
16355         // flash it up as modal - so we store the mask!?
16356         if (!this.hideProgress && Roo.MessageBox) {
16357             Roo.MessageBox.show({ title: 'loading' });
16358             Roo.MessageBox.show({
16359                title: "Please wait...",
16360                msg: msg,
16361                width:450,
16362                progress:true,
16363                closable:false,
16364                modal: false
16365               
16366             });
16367         }
16368         var total = mods.length;
16369         
16370         var _this = this;
16371         var progressRun = function() {
16372             if (!mods.length) {
16373                 Roo.debug && Roo.log('hide?');
16374                 if (!this.hideProgress && Roo.MessageBox) {
16375                     Roo.MessageBox.hide();
16376                 }
16377                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16378                 
16379                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16380                 
16381                 // THE END...
16382                 return false;   
16383             }
16384             
16385             var m = mods.shift();
16386             
16387             
16388             Roo.debug && Roo.log(m);
16389             // not sure if this is supported any more.. - modules that are are just function
16390             if (typeof(m) == 'function') { 
16391                 m.call(this);
16392                 return progressRun.defer(10, _this);
16393             } 
16394             
16395             
16396             msg = "Building Interface " + (total  - mods.length) + 
16397                     " of " + total + 
16398                     (m.name ? (' - ' + m.name) : '');
16399                         Roo.debug && Roo.log(msg);
16400             if (!this.hideProgress &&  Roo.MessageBox) { 
16401                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16402             }
16403             
16404          
16405             // is the module disabled?
16406             var disabled = (typeof(m.disabled) == 'function') ?
16407                 m.disabled.call(m.module.disabled) : m.disabled;    
16408             
16409             
16410             if (disabled) {
16411                 return progressRun(); // we do not update the display!
16412             }
16413             
16414             // now build 
16415             
16416                         
16417                         
16418             m.render();
16419             // it's 10 on top level, and 1 on others??? why...
16420             return progressRun.defer(10, _this);
16421              
16422         }
16423         progressRun.defer(1, _this);
16424      
16425         
16426         
16427     },
16428         
16429         
16430         /**
16431          * Event Object.
16432          *
16433          *
16434          */
16435         event: false, 
16436     /**
16437          * wrapper for event.on - aliased later..  
16438          * Typically use to register a event handler for register:
16439          *
16440          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16441          *
16442          */
16443     on : false
16444    
16445     
16446     
16447 });
16448
16449 Roo.XComponent.event = new Roo.util.Observable({
16450                 events : { 
16451                         /**
16452                          * @event register
16453                          * Fires when an Component is registered,
16454                          * set the disable property on the Component to stop registration.
16455                          * @param {Roo.XComponent} c the component being registerd.
16456                          * 
16457                          */
16458                         'register' : true,
16459             /**
16460                          * @event beforebuild
16461                          * Fires before each Component is built
16462                          * can be used to apply permissions.
16463                          * @param {Roo.XComponent} c the component being registerd.
16464                          * 
16465                          */
16466                         'beforebuild' : true,
16467                         /**
16468                          * @event buildcomplete
16469                          * Fires on the top level element when all elements have been built
16470                          * @param {Roo.XComponent} the top level component.
16471                          */
16472                         'buildcomplete' : true
16473                         
16474                 }
16475 });
16476
16477 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16478