Roo/bootstrap/UploadCropbox.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 el[attr] = o[attr];
4244             }
4245         }
4246         Roo.DomHelper.applyStyles(el, o.style);
4247         var cn = o.children || o.cn;
4248         if(cn){
4249             //http://bugs.kde.org/show_bug.cgi?id=71506
4250              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4251                 for(var i = 0, len = cn.length; i < len; i++) {
4252                     createDom(cn[i], el);
4253                 }
4254             }else{
4255                 createDom(cn, el);
4256             }
4257         }
4258         if(o.html){
4259             el.innerHTML = o.html;
4260         }
4261         if(parentNode){
4262            parentNode.appendChild(el);
4263         }
4264         return el;
4265     };
4266
4267     var ieTable = function(depth, s, h, e){
4268         tempTableEl.innerHTML = [s, h, e].join('');
4269         var i = -1, el = tempTableEl;
4270         while(++i < depth){
4271             el = el.firstChild;
4272         }
4273         return el;
4274     };
4275
4276     // kill repeat to save bytes
4277     var ts = '<table>',
4278         te = '</table>',
4279         tbs = ts+'<tbody>',
4280         tbe = '</tbody>'+te,
4281         trs = tbs + '<tr>',
4282         tre = '</tr>'+tbe;
4283
4284     /**
4285      * @ignore
4286      * Nasty code for IE's broken table implementation
4287      */
4288     var insertIntoTable = function(tag, where, el, html){
4289         if(!tempTableEl){
4290             tempTableEl = document.createElement('div');
4291         }
4292         var node;
4293         var before = null;
4294         if(tag == 'td'){
4295             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4296                 return;
4297             }
4298             if(where == 'beforebegin'){
4299                 before = el;
4300                 el = el.parentNode;
4301             } else{
4302                 before = el.nextSibling;
4303                 el = el.parentNode;
4304             }
4305             node = ieTable(4, trs, html, tre);
4306         }
4307         else if(tag == 'tr'){
4308             if(where == 'beforebegin'){
4309                 before = el;
4310                 el = el.parentNode;
4311                 node = ieTable(3, tbs, html, tbe);
4312             } else if(where == 'afterend'){
4313                 before = el.nextSibling;
4314                 el = el.parentNode;
4315                 node = ieTable(3, tbs, html, tbe);
4316             } else{ // INTO a TR
4317                 if(where == 'afterbegin'){
4318                     before = el.firstChild;
4319                 }
4320                 node = ieTable(4, trs, html, tre);
4321             }
4322         } else if(tag == 'tbody'){
4323             if(where == 'beforebegin'){
4324                 before = el;
4325                 el = el.parentNode;
4326                 node = ieTable(2, ts, html, te);
4327             } else if(where == 'afterend'){
4328                 before = el.nextSibling;
4329                 el = el.parentNode;
4330                 node = ieTable(2, ts, html, te);
4331             } else{
4332                 if(where == 'afterbegin'){
4333                     before = el.firstChild;
4334                 }
4335                 node = ieTable(3, tbs, html, tbe);
4336             }
4337         } else{ // TABLE
4338             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4339                 return;
4340             }
4341             if(where == 'afterbegin'){
4342                 before = el.firstChild;
4343             }
4344             node = ieTable(2, ts, html, te);
4345         }
4346         el.insertBefore(node, before);
4347         return node;
4348     };
4349
4350     return {
4351     /** True to force the use of DOM instead of html fragments @type Boolean */
4352     useDom : false,
4353
4354     /**
4355      * Returns the markup for the passed Element(s) config
4356      * @param {Object} o The Dom object spec (and children)
4357      * @return {String}
4358      */
4359     markup : function(o){
4360         return createHtml(o);
4361     },
4362
4363     /**
4364      * Applies a style specification to an element
4365      * @param {String/HTMLElement} el The element to apply styles to
4366      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4367      * a function which returns such a specification.
4368      */
4369     applyStyles : function(el, styles){
4370         if(styles){
4371            el = Roo.fly(el);
4372            if(typeof styles == "string"){
4373                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4374                var matches;
4375                while ((matches = re.exec(styles)) != null){
4376                    el.setStyle(matches[1], matches[2]);
4377                }
4378            }else if (typeof styles == "object"){
4379                for (var style in styles){
4380                   el.setStyle(style, styles[style]);
4381                }
4382            }else if (typeof styles == "function"){
4383                 Roo.DomHelper.applyStyles(el, styles.call());
4384            }
4385         }
4386     },
4387
4388     /**
4389      * Inserts an HTML fragment into the Dom
4390      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4391      * @param {HTMLElement} el The context element
4392      * @param {String} html The HTML fragmenet
4393      * @return {HTMLElement} The new node
4394      */
4395     insertHtml : function(where, el, html){
4396         where = where.toLowerCase();
4397         if(el.insertAdjacentHTML){
4398             if(tableRe.test(el.tagName)){
4399                 var rs;
4400                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4401                     return rs;
4402                 }
4403             }
4404             switch(where){
4405                 case "beforebegin":
4406                     el.insertAdjacentHTML('BeforeBegin', html);
4407                     return el.previousSibling;
4408                 case "afterbegin":
4409                     el.insertAdjacentHTML('AfterBegin', html);
4410                     return el.firstChild;
4411                 case "beforeend":
4412                     el.insertAdjacentHTML('BeforeEnd', html);
4413                     return el.lastChild;
4414                 case "afterend":
4415                     el.insertAdjacentHTML('AfterEnd', html);
4416                     return el.nextSibling;
4417             }
4418             throw 'Illegal insertion point -> "' + where + '"';
4419         }
4420         var range = el.ownerDocument.createRange();
4421         var frag;
4422         switch(where){
4423              case "beforebegin":
4424                 range.setStartBefore(el);
4425                 frag = range.createContextualFragment(html);
4426                 el.parentNode.insertBefore(frag, el);
4427                 return el.previousSibling;
4428              case "afterbegin":
4429                 if(el.firstChild){
4430                     range.setStartBefore(el.firstChild);
4431                     frag = range.createContextualFragment(html);
4432                     el.insertBefore(frag, el.firstChild);
4433                     return el.firstChild;
4434                 }else{
4435                     el.innerHTML = html;
4436                     return el.firstChild;
4437                 }
4438             case "beforeend":
4439                 if(el.lastChild){
4440                     range.setStartAfter(el.lastChild);
4441                     frag = range.createContextualFragment(html);
4442                     el.appendChild(frag);
4443                     return el.lastChild;
4444                 }else{
4445                     el.innerHTML = html;
4446                     return el.lastChild;
4447                 }
4448             case "afterend":
4449                 range.setStartAfter(el);
4450                 frag = range.createContextualFragment(html);
4451                 el.parentNode.insertBefore(frag, el.nextSibling);
4452                 return el.nextSibling;
4453             }
4454             throw 'Illegal insertion point -> "' + where + '"';
4455     },
4456
4457     /**
4458      * Creates new Dom element(s) and inserts them before el
4459      * @param {String/HTMLElement/Element} el The context element
4460      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4461      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4462      * @return {HTMLElement/Roo.Element} The new node
4463      */
4464     insertBefore : function(el, o, returnElement){
4465         return this.doInsert(el, o, returnElement, "beforeBegin");
4466     },
4467
4468     /**
4469      * Creates new Dom element(s) and inserts them after el
4470      * @param {String/HTMLElement/Element} el The context element
4471      * @param {Object} o The Dom object spec (and children)
4472      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4473      * @return {HTMLElement/Roo.Element} The new node
4474      */
4475     insertAfter : function(el, o, returnElement){
4476         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4477     },
4478
4479     /**
4480      * Creates new Dom element(s) and inserts them as the first child of el
4481      * @param {String/HTMLElement/Element} el The context element
4482      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4483      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4484      * @return {HTMLElement/Roo.Element} The new node
4485      */
4486     insertFirst : function(el, o, returnElement){
4487         return this.doInsert(el, o, returnElement, "afterBegin");
4488     },
4489
4490     // private
4491     doInsert : function(el, o, returnElement, pos, sibling){
4492         el = Roo.getDom(el);
4493         var newNode;
4494         if(this.useDom || o.ns){
4495             newNode = createDom(o, null);
4496             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4497         }else{
4498             var html = createHtml(o);
4499             newNode = this.insertHtml(pos, el, html);
4500         }
4501         return returnElement ? Roo.get(newNode, true) : newNode;
4502     },
4503
4504     /**
4505      * Creates new Dom element(s) and appends them to el
4506      * @param {String/HTMLElement/Element} el The context element
4507      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4508      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4509      * @return {HTMLElement/Roo.Element} The new node
4510      */
4511     append : function(el, o, returnElement){
4512         el = Roo.getDom(el);
4513         var newNode;
4514         if(this.useDom || o.ns){
4515             newNode = createDom(o, null);
4516             el.appendChild(newNode);
4517         }else{
4518             var html = createHtml(o);
4519             newNode = this.insertHtml("beforeEnd", el, html);
4520         }
4521         return returnElement ? Roo.get(newNode, true) : newNode;
4522     },
4523
4524     /**
4525      * Creates new Dom element(s) and overwrites the contents of el with them
4526      * @param {String/HTMLElement/Element} el The context element
4527      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4528      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4529      * @return {HTMLElement/Roo.Element} The new node
4530      */
4531     overwrite : function(el, o, returnElement){
4532         el = Roo.getDom(el);
4533         if (o.ns) {
4534           
4535             while (el.childNodes.length) {
4536                 el.removeChild(el.firstChild);
4537             }
4538             createDom(o, el);
4539         } else {
4540             el.innerHTML = createHtml(o);   
4541         }
4542         
4543         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4544     },
4545
4546     /**
4547      * Creates a new Roo.DomHelper.Template from the Dom object spec
4548      * @param {Object} o The Dom object spec (and children)
4549      * @return {Roo.DomHelper.Template} The new template
4550      */
4551     createTemplate : function(o){
4552         var html = createHtml(o);
4553         return new Roo.Template(html);
4554     }
4555     };
4556 }();
4557 /*
4558  * Based on:
4559  * Ext JS Library 1.1.1
4560  * Copyright(c) 2006-2007, Ext JS, LLC.
4561  *
4562  * Originally Released Under LGPL - original licence link has changed is not relivant.
4563  *
4564  * Fork - LGPL
4565  * <script type="text/javascript">
4566  */
4567  
4568 /**
4569 * @class Roo.Template
4570 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4571 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4572 * Usage:
4573 <pre><code>
4574 var t = new Roo.Template({
4575     html :  '&lt;div name="{id}"&gt;' + 
4576         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4577         '&lt;/div&gt;',
4578     myformat: function (value, allValues) {
4579         return 'XX' + value;
4580     }
4581 });
4582 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4583 </code></pre>
4584 * For more information see this blog post with examples:
4585 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4586      - Create Elements using DOM, HTML fragments and Templates</a>. 
4587 * @constructor
4588 * @param {Object} cfg - Configuration object.
4589 */
4590 Roo.Template = function(cfg){
4591     // BC!
4592     if(cfg instanceof Array){
4593         cfg = cfg.join("");
4594     }else if(arguments.length > 1){
4595         cfg = Array.prototype.join.call(arguments, "");
4596     }
4597     
4598     
4599     if (typeof(cfg) == 'object') {
4600         Roo.apply(this,cfg)
4601     } else {
4602         // bc
4603         this.html = cfg;
4604     }
4605     if (this.url) {
4606         this.load();
4607     }
4608     
4609 };
4610 Roo.Template.prototype = {
4611     
4612     /**
4613      * @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..
4614      *                    it should be fixed so that template is observable...
4615      */
4616     url : false,
4617     /**
4618      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4619      */
4620     html : '',
4621     /**
4622      * Returns an HTML fragment of this template with the specified values applied.
4623      * @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'})
4624      * @return {String} The HTML fragment
4625      */
4626     applyTemplate : function(values){
4627         try {
4628            
4629             if(this.compiled){
4630                 return this.compiled(values);
4631             }
4632             var useF = this.disableFormats !== true;
4633             var fm = Roo.util.Format, tpl = this;
4634             var fn = function(m, name, format, args){
4635                 if(format && useF){
4636                     if(format.substr(0, 5) == "this."){
4637                         return tpl.call(format.substr(5), values[name], values);
4638                     }else{
4639                         if(args){
4640                             // quoted values are required for strings in compiled templates, 
4641                             // but for non compiled we need to strip them
4642                             // quoted reversed for jsmin
4643                             var re = /^\s*['"](.*)["']\s*$/;
4644                             args = args.split(',');
4645                             for(var i = 0, len = args.length; i < len; i++){
4646                                 args[i] = args[i].replace(re, "$1");
4647                             }
4648                             args = [values[name]].concat(args);
4649                         }else{
4650                             args = [values[name]];
4651                         }
4652                         return fm[format].apply(fm, args);
4653                     }
4654                 }else{
4655                     return values[name] !== undefined ? values[name] : "";
4656                 }
4657             };
4658             return this.html.replace(this.re, fn);
4659         } catch (e) {
4660             Roo.log(e);
4661             throw e;
4662         }
4663          
4664     },
4665     
4666     loading : false,
4667       
4668     load : function ()
4669     {
4670          
4671         if (this.loading) {
4672             return;
4673         }
4674         var _t = this;
4675         
4676         this.loading = true;
4677         this.compiled = false;
4678         
4679         var cx = new Roo.data.Connection();
4680         cx.request({
4681             url : this.url,
4682             method : 'GET',
4683             success : function (response) {
4684                 _t.loading = false;
4685                 _t.html = response.responseText;
4686                 _t.url = false;
4687                 _t.compile();
4688              },
4689             failure : function(response) {
4690                 Roo.log("Template failed to load from " + _t.url);
4691                 _t.loading = false;
4692             }
4693         });
4694     },
4695
4696     /**
4697      * Sets the HTML used as the template and optionally compiles it.
4698      * @param {String} html
4699      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4700      * @return {Roo.Template} this
4701      */
4702     set : function(html, compile){
4703         this.html = html;
4704         this.compiled = null;
4705         if(compile){
4706             this.compile();
4707         }
4708         return this;
4709     },
4710     
4711     /**
4712      * True to disable format functions (defaults to false)
4713      * @type Boolean
4714      */
4715     disableFormats : false,
4716     
4717     /**
4718     * The regular expression used to match template variables 
4719     * @type RegExp
4720     * @property 
4721     */
4722     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4723     
4724     /**
4725      * Compiles the template into an internal function, eliminating the RegEx overhead.
4726      * @return {Roo.Template} this
4727      */
4728     compile : function(){
4729         var fm = Roo.util.Format;
4730         var useF = this.disableFormats !== true;
4731         var sep = Roo.isGecko ? "+" : ",";
4732         var fn = function(m, name, format, args){
4733             if(format && useF){
4734                 args = args ? ',' + args : "";
4735                 if(format.substr(0, 5) != "this."){
4736                     format = "fm." + format + '(';
4737                 }else{
4738                     format = 'this.call("'+ format.substr(5) + '", ';
4739                     args = ", values";
4740                 }
4741             }else{
4742                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4743             }
4744             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4745         };
4746         var body;
4747         // branched to use + in gecko and [].join() in others
4748         if(Roo.isGecko){
4749             body = "this.compiled = function(values){ return '" +
4750                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4751                     "';};";
4752         }else{
4753             body = ["this.compiled = function(values){ return ['"];
4754             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4755             body.push("'].join('');};");
4756             body = body.join('');
4757         }
4758         /**
4759          * eval:var:values
4760          * eval:var:fm
4761          */
4762         eval(body);
4763         return this;
4764     },
4765     
4766     // private function used to call members
4767     call : function(fnName, value, allValues){
4768         return this[fnName](value, allValues);
4769     },
4770     
4771     /**
4772      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4773      * @param {String/HTMLElement/Roo.Element} el The context element
4774      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4775      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4776      * @return {HTMLElement/Roo.Element} The new node or Element
4777      */
4778     insertFirst: function(el, values, returnElement){
4779         return this.doInsert('afterBegin', el, values, returnElement);
4780     },
4781
4782     /**
4783      * Applies the supplied values to the template and inserts the new node(s) before el.
4784      * @param {String/HTMLElement/Roo.Element} el The context element
4785      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4786      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4787      * @return {HTMLElement/Roo.Element} The new node or Element
4788      */
4789     insertBefore: function(el, values, returnElement){
4790         return this.doInsert('beforeBegin', el, values, returnElement);
4791     },
4792
4793     /**
4794      * Applies the supplied values to the template and inserts the new node(s) after el.
4795      * @param {String/HTMLElement/Roo.Element} el The context element
4796      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4797      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4798      * @return {HTMLElement/Roo.Element} The new node or Element
4799      */
4800     insertAfter : function(el, values, returnElement){
4801         return this.doInsert('afterEnd', el, values, returnElement);
4802     },
4803     
4804     /**
4805      * Applies the supplied values to the template and appends the new node(s) to el.
4806      * @param {String/HTMLElement/Roo.Element} el The context element
4807      * @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'})
4808      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4809      * @return {HTMLElement/Roo.Element} The new node or Element
4810      */
4811     append : function(el, values, returnElement){
4812         return this.doInsert('beforeEnd', el, values, returnElement);
4813     },
4814
4815     doInsert : function(where, el, values, returnEl){
4816         el = Roo.getDom(el);
4817         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4818         return returnEl ? Roo.get(newNode, true) : newNode;
4819     },
4820
4821     /**
4822      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4823      * @param {String/HTMLElement/Roo.Element} el The context element
4824      * @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'})
4825      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4826      * @return {HTMLElement/Roo.Element} The new node or Element
4827      */
4828     overwrite : function(el, values, returnElement){
4829         el = Roo.getDom(el);
4830         el.innerHTML = this.applyTemplate(values);
4831         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4832     }
4833 };
4834 /**
4835  * Alias for {@link #applyTemplate}
4836  * @method
4837  */
4838 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4839
4840 // backwards compat
4841 Roo.DomHelper.Template = Roo.Template;
4842
4843 /**
4844  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4845  * @param {String/HTMLElement} el A DOM element or its id
4846  * @returns {Roo.Template} The created template
4847  * @static
4848  */
4849 Roo.Template.from = function(el){
4850     el = Roo.getDom(el);
4851     return new Roo.Template(el.value || el.innerHTML);
4852 };/*
4853  * Based on:
4854  * Ext JS Library 1.1.1
4855  * Copyright(c) 2006-2007, Ext JS, LLC.
4856  *
4857  * Originally Released Under LGPL - original licence link has changed is not relivant.
4858  *
4859  * Fork - LGPL
4860  * <script type="text/javascript">
4861  */
4862  
4863
4864 /*
4865  * This is code is also distributed under MIT license for use
4866  * with jQuery and prototype JavaScript libraries.
4867  */
4868 /**
4869  * @class Roo.DomQuery
4870 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).
4871 <p>
4872 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>
4873
4874 <p>
4875 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.
4876 </p>
4877 <h4>Element Selectors:</h4>
4878 <ul class="list">
4879     <li> <b>*</b> any element</li>
4880     <li> <b>E</b> an element with the tag E</li>
4881     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4882     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4883     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4884     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4885 </ul>
4886 <h4>Attribute Selectors:</h4>
4887 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4888 <ul class="list">
4889     <li> <b>E[foo]</b> has an attribute "foo"</li>
4890     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4891     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4892     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4893     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4894     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4895     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4896 </ul>
4897 <h4>Pseudo Classes:</h4>
4898 <ul class="list">
4899     <li> <b>E:first-child</b> E is the first child of its parent</li>
4900     <li> <b>E:last-child</b> E is the last child of its parent</li>
4901     <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>
4902     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4903     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4904     <li> <b>E:only-child</b> E is the only child of its parent</li>
4905     <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>
4906     <li> <b>E:first</b> the first E in the resultset</li>
4907     <li> <b>E:last</b> the last E in the resultset</li>
4908     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4909     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4910     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4911     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4912     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4913     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4914     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4915     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4916     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4917 </ul>
4918 <h4>CSS Value Selectors:</h4>
4919 <ul class="list">
4920     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4921     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4922     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4923     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4924     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4925     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4926 </ul>
4927  * @singleton
4928  */
4929 Roo.DomQuery = function(){
4930     var cache = {}, simpleCache = {}, valueCache = {};
4931     var nonSpace = /\S/;
4932     var trimRe = /^\s+|\s+$/g;
4933     var tplRe = /\{(\d+)\}/g;
4934     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4935     var tagTokenRe = /^(#)?([\w-\*]+)/;
4936     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4937
4938     function child(p, index){
4939         var i = 0;
4940         var n = p.firstChild;
4941         while(n){
4942             if(n.nodeType == 1){
4943                if(++i == index){
4944                    return n;
4945                }
4946             }
4947             n = n.nextSibling;
4948         }
4949         return null;
4950     };
4951
4952     function next(n){
4953         while((n = n.nextSibling) && n.nodeType != 1);
4954         return n;
4955     };
4956
4957     function prev(n){
4958         while((n = n.previousSibling) && n.nodeType != 1);
4959         return n;
4960     };
4961
4962     function children(d){
4963         var n = d.firstChild, ni = -1;
4964             while(n){
4965                 var nx = n.nextSibling;
4966                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4967                     d.removeChild(n);
4968                 }else{
4969                     n.nodeIndex = ++ni;
4970                 }
4971                 n = nx;
4972             }
4973             return this;
4974         };
4975
4976     function byClassName(c, a, v){
4977         if(!v){
4978             return c;
4979         }
4980         var r = [], ri = -1, cn;
4981         for(var i = 0, ci; ci = c[i]; i++){
4982             if((' '+ci.className+' ').indexOf(v) != -1){
4983                 r[++ri] = ci;
4984             }
4985         }
4986         return r;
4987     };
4988
4989     function attrValue(n, attr){
4990         if(!n.tagName && typeof n.length != "undefined"){
4991             n = n[0];
4992         }
4993         if(!n){
4994             return null;
4995         }
4996         if(attr == "for"){
4997             return n.htmlFor;
4998         }
4999         if(attr == "class" || attr == "className"){
5000             return n.className;
5001         }
5002         return n.getAttribute(attr) || n[attr];
5003
5004     };
5005
5006     function getNodes(ns, mode, tagName){
5007         var result = [], ri = -1, cs;
5008         if(!ns){
5009             return result;
5010         }
5011         tagName = tagName || "*";
5012         if(typeof ns.getElementsByTagName != "undefined"){
5013             ns = [ns];
5014         }
5015         if(!mode){
5016             for(var i = 0, ni; ni = ns[i]; i++){
5017                 cs = ni.getElementsByTagName(tagName);
5018                 for(var j = 0, ci; ci = cs[j]; j++){
5019                     result[++ri] = ci;
5020                 }
5021             }
5022         }else if(mode == "/" || mode == ">"){
5023             var utag = tagName.toUpperCase();
5024             for(var i = 0, ni, cn; ni = ns[i]; i++){
5025                 cn = ni.children || ni.childNodes;
5026                 for(var j = 0, cj; cj = cn[j]; j++){
5027                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5028                         result[++ri] = cj;
5029                     }
5030                 }
5031             }
5032         }else if(mode == "+"){
5033             var utag = tagName.toUpperCase();
5034             for(var i = 0, n; n = ns[i]; i++){
5035                 while((n = n.nextSibling) && n.nodeType != 1);
5036                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5037                     result[++ri] = n;
5038                 }
5039             }
5040         }else if(mode == "~"){
5041             for(var i = 0, n; n = ns[i]; i++){
5042                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5043                 if(n){
5044                     result[++ri] = n;
5045                 }
5046             }
5047         }
5048         return result;
5049     };
5050
5051     function concat(a, b){
5052         if(b.slice){
5053             return a.concat(b);
5054         }
5055         for(var i = 0, l = b.length; i < l; i++){
5056             a[a.length] = b[i];
5057         }
5058         return a;
5059     }
5060
5061     function byTag(cs, tagName){
5062         if(cs.tagName || cs == document){
5063             cs = [cs];
5064         }
5065         if(!tagName){
5066             return cs;
5067         }
5068         var r = [], ri = -1;
5069         tagName = tagName.toLowerCase();
5070         for(var i = 0, ci; ci = cs[i]; i++){
5071             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5072                 r[++ri] = ci;
5073             }
5074         }
5075         return r;
5076     };
5077
5078     function byId(cs, attr, id){
5079         if(cs.tagName || cs == document){
5080             cs = [cs];
5081         }
5082         if(!id){
5083             return cs;
5084         }
5085         var r = [], ri = -1;
5086         for(var i = 0,ci; ci = cs[i]; i++){
5087             if(ci && ci.id == id){
5088                 r[++ri] = ci;
5089                 return r;
5090             }
5091         }
5092         return r;
5093     };
5094
5095     function byAttribute(cs, attr, value, op, custom){
5096         var r = [], ri = -1, st = custom=="{";
5097         var f = Roo.DomQuery.operators[op];
5098         for(var i = 0, ci; ci = cs[i]; i++){
5099             var a;
5100             if(st){
5101                 a = Roo.DomQuery.getStyle(ci, attr);
5102             }
5103             else if(attr == "class" || attr == "className"){
5104                 a = ci.className;
5105             }else if(attr == "for"){
5106                 a = ci.htmlFor;
5107             }else if(attr == "href"){
5108                 a = ci.getAttribute("href", 2);
5109             }else{
5110                 a = ci.getAttribute(attr);
5111             }
5112             if((f && f(a, value)) || (!f && a)){
5113                 r[++ri] = ci;
5114             }
5115         }
5116         return r;
5117     };
5118
5119     function byPseudo(cs, name, value){
5120         return Roo.DomQuery.pseudos[name](cs, value);
5121     };
5122
5123     // This is for IE MSXML which does not support expandos.
5124     // IE runs the same speed using setAttribute, however FF slows way down
5125     // and Safari completely fails so they need to continue to use expandos.
5126     var isIE = window.ActiveXObject ? true : false;
5127
5128     // this eval is stop the compressor from
5129     // renaming the variable to something shorter
5130     
5131     /** eval:var:batch */
5132     var batch = 30803; 
5133
5134     var key = 30803;
5135
5136     function nodupIEXml(cs){
5137         var d = ++key;
5138         cs[0].setAttribute("_nodup", d);
5139         var r = [cs[0]];
5140         for(var i = 1, len = cs.length; i < len; i++){
5141             var c = cs[i];
5142             if(!c.getAttribute("_nodup") != d){
5143                 c.setAttribute("_nodup", d);
5144                 r[r.length] = c;
5145             }
5146         }
5147         for(var i = 0, len = cs.length; i < len; i++){
5148             cs[i].removeAttribute("_nodup");
5149         }
5150         return r;
5151     }
5152
5153     function nodup(cs){
5154         if(!cs){
5155             return [];
5156         }
5157         var len = cs.length, c, i, r = cs, cj, ri = -1;
5158         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5159             return cs;
5160         }
5161         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5162             return nodupIEXml(cs);
5163         }
5164         var d = ++key;
5165         cs[0]._nodup = d;
5166         for(i = 1; c = cs[i]; i++){
5167             if(c._nodup != d){
5168                 c._nodup = d;
5169             }else{
5170                 r = [];
5171                 for(var j = 0; j < i; j++){
5172                     r[++ri] = cs[j];
5173                 }
5174                 for(j = i+1; cj = cs[j]; j++){
5175                     if(cj._nodup != d){
5176                         cj._nodup = d;
5177                         r[++ri] = cj;
5178                     }
5179                 }
5180                 return r;
5181             }
5182         }
5183         return r;
5184     }
5185
5186     function quickDiffIEXml(c1, c2){
5187         var d = ++key;
5188         for(var i = 0, len = c1.length; i < len; i++){
5189             c1[i].setAttribute("_qdiff", d);
5190         }
5191         var r = [];
5192         for(var i = 0, len = c2.length; i < len; i++){
5193             if(c2[i].getAttribute("_qdiff") != d){
5194                 r[r.length] = c2[i];
5195             }
5196         }
5197         for(var i = 0, len = c1.length; i < len; i++){
5198            c1[i].removeAttribute("_qdiff");
5199         }
5200         return r;
5201     }
5202
5203     function quickDiff(c1, c2){
5204         var len1 = c1.length;
5205         if(!len1){
5206             return c2;
5207         }
5208         if(isIE && c1[0].selectSingleNode){
5209             return quickDiffIEXml(c1, c2);
5210         }
5211         var d = ++key;
5212         for(var i = 0; i < len1; i++){
5213             c1[i]._qdiff = d;
5214         }
5215         var r = [];
5216         for(var i = 0, len = c2.length; i < len; i++){
5217             if(c2[i]._qdiff != d){
5218                 r[r.length] = c2[i];
5219             }
5220         }
5221         return r;
5222     }
5223
5224     function quickId(ns, mode, root, id){
5225         if(ns == root){
5226            var d = root.ownerDocument || root;
5227            return d.getElementById(id);
5228         }
5229         ns = getNodes(ns, mode, "*");
5230         return byId(ns, null, id);
5231     }
5232
5233     return {
5234         getStyle : function(el, name){
5235             return Roo.fly(el).getStyle(name);
5236         },
5237         /**
5238          * Compiles a selector/xpath query into a reusable function. The returned function
5239          * takes one parameter "root" (optional), which is the context node from where the query should start.
5240          * @param {String} selector The selector/xpath query
5241          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5242          * @return {Function}
5243          */
5244         compile : function(path, type){
5245             type = type || "select";
5246             
5247             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5248             var q = path, mode, lq;
5249             var tk = Roo.DomQuery.matchers;
5250             var tklen = tk.length;
5251             var mm;
5252
5253             // accept leading mode switch
5254             var lmode = q.match(modeRe);
5255             if(lmode && lmode[1]){
5256                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5257                 q = q.replace(lmode[1], "");
5258             }
5259             // strip leading slashes
5260             while(path.substr(0, 1)=="/"){
5261                 path = path.substr(1);
5262             }
5263
5264             while(q && lq != q){
5265                 lq = q;
5266                 var tm = q.match(tagTokenRe);
5267                 if(type == "select"){
5268                     if(tm){
5269                         if(tm[1] == "#"){
5270                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5271                         }else{
5272                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5273                         }
5274                         q = q.replace(tm[0], "");
5275                     }else if(q.substr(0, 1) != '@'){
5276                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5277                     }
5278                 }else{
5279                     if(tm){
5280                         if(tm[1] == "#"){
5281                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5282                         }else{
5283                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5284                         }
5285                         q = q.replace(tm[0], "");
5286                     }
5287                 }
5288                 while(!(mm = q.match(modeRe))){
5289                     var matched = false;
5290                     for(var j = 0; j < tklen; j++){
5291                         var t = tk[j];
5292                         var m = q.match(t.re);
5293                         if(m){
5294                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5295                                                     return m[i];
5296                                                 });
5297                             q = q.replace(m[0], "");
5298                             matched = true;
5299                             break;
5300                         }
5301                     }
5302                     // prevent infinite loop on bad selector
5303                     if(!matched){
5304                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5305                     }
5306                 }
5307                 if(mm[1]){
5308                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5309                     q = q.replace(mm[1], "");
5310                 }
5311             }
5312             fn[fn.length] = "return nodup(n);\n}";
5313             
5314              /** 
5315               * list of variables that need from compression as they are used by eval.
5316              *  eval:var:batch 
5317              *  eval:var:nodup
5318              *  eval:var:byTag
5319              *  eval:var:ById
5320              *  eval:var:getNodes
5321              *  eval:var:quickId
5322              *  eval:var:mode
5323              *  eval:var:root
5324              *  eval:var:n
5325              *  eval:var:byClassName
5326              *  eval:var:byPseudo
5327              *  eval:var:byAttribute
5328              *  eval:var:attrValue
5329              * 
5330              **/ 
5331             eval(fn.join(""));
5332             return f;
5333         },
5334
5335         /**
5336          * Selects a group of elements.
5337          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5338          * @param {Node} root (optional) The start of the query (defaults to document).
5339          * @return {Array}
5340          */
5341         select : function(path, root, type){
5342             if(!root || root == document){
5343                 root = document;
5344             }
5345             if(typeof root == "string"){
5346                 root = document.getElementById(root);
5347             }
5348             var paths = path.split(",");
5349             var results = [];
5350             for(var i = 0, len = paths.length; i < len; i++){
5351                 var p = paths[i].replace(trimRe, "");
5352                 if(!cache[p]){
5353                     cache[p] = Roo.DomQuery.compile(p);
5354                     if(!cache[p]){
5355                         throw p + " is not a valid selector";
5356                     }
5357                 }
5358                 var result = cache[p](root);
5359                 if(result && result != document){
5360                     results = results.concat(result);
5361                 }
5362             }
5363             if(paths.length > 1){
5364                 return nodup(results);
5365             }
5366             return results;
5367         },
5368
5369         /**
5370          * Selects a single element.
5371          * @param {String} selector The selector/xpath query
5372          * @param {Node} root (optional) The start of the query (defaults to document).
5373          * @return {Element}
5374          */
5375         selectNode : function(path, root){
5376             return Roo.DomQuery.select(path, root)[0];
5377         },
5378
5379         /**
5380          * Selects the value of a node, optionally replacing null with the defaultValue.
5381          * @param {String} selector The selector/xpath query
5382          * @param {Node} root (optional) The start of the query (defaults to document).
5383          * @param {String} defaultValue
5384          */
5385         selectValue : function(path, root, defaultValue){
5386             path = path.replace(trimRe, "");
5387             if(!valueCache[path]){
5388                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5389             }
5390             var n = valueCache[path](root);
5391             n = n[0] ? n[0] : n;
5392             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5393             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5394         },
5395
5396         /**
5397          * Selects the value of a node, parsing integers and floats.
5398          * @param {String} selector The selector/xpath query
5399          * @param {Node} root (optional) The start of the query (defaults to document).
5400          * @param {Number} defaultValue
5401          * @return {Number}
5402          */
5403         selectNumber : function(path, root, defaultValue){
5404             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5405             return parseFloat(v);
5406         },
5407
5408         /**
5409          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5410          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5411          * @param {String} selector The simple selector to test
5412          * @return {Boolean}
5413          */
5414         is : function(el, ss){
5415             if(typeof el == "string"){
5416                 el = document.getElementById(el);
5417             }
5418             var isArray = (el instanceof Array);
5419             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5420             return isArray ? (result.length == el.length) : (result.length > 0);
5421         },
5422
5423         /**
5424          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5425          * @param {Array} el An array of elements to filter
5426          * @param {String} selector The simple selector to test
5427          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5428          * the selector instead of the ones that match
5429          * @return {Array}
5430          */
5431         filter : function(els, ss, nonMatches){
5432             ss = ss.replace(trimRe, "");
5433             if(!simpleCache[ss]){
5434                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5435             }
5436             var result = simpleCache[ss](els);
5437             return nonMatches ? quickDiff(result, els) : result;
5438         },
5439
5440         /**
5441          * Collection of matching regular expressions and code snippets.
5442          */
5443         matchers : [{
5444                 re: /^\.([\w-]+)/,
5445                 select: 'n = byClassName(n, null, " {1} ");'
5446             }, {
5447                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5448                 select: 'n = byPseudo(n, "{1}", "{2}");'
5449             },{
5450                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5451                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5452             }, {
5453                 re: /^#([\w-]+)/,
5454                 select: 'n = byId(n, null, "{1}");'
5455             },{
5456                 re: /^@([\w-]+)/,
5457                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5458             }
5459         ],
5460
5461         /**
5462          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5463          * 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;.
5464          */
5465         operators : {
5466             "=" : function(a, v){
5467                 return a == v;
5468             },
5469             "!=" : function(a, v){
5470                 return a != v;
5471             },
5472             "^=" : function(a, v){
5473                 return a && a.substr(0, v.length) == v;
5474             },
5475             "$=" : function(a, v){
5476                 return a && a.substr(a.length-v.length) == v;
5477             },
5478             "*=" : function(a, v){
5479                 return a && a.indexOf(v) !== -1;
5480             },
5481             "%=" : function(a, v){
5482                 return (a % v) == 0;
5483             },
5484             "|=" : function(a, v){
5485                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5486             },
5487             "~=" : function(a, v){
5488                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5489             }
5490         },
5491
5492         /**
5493          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5494          * and the argument (if any) supplied in the selector.
5495          */
5496         pseudos : {
5497             "first-child" : function(c){
5498                 var r = [], ri = -1, n;
5499                 for(var i = 0, ci; ci = n = c[i]; i++){
5500                     while((n = n.previousSibling) && n.nodeType != 1);
5501                     if(!n){
5502                         r[++ri] = ci;
5503                     }
5504                 }
5505                 return r;
5506             },
5507
5508             "last-child" : function(c){
5509                 var r = [], ri = -1, n;
5510                 for(var i = 0, ci; ci = n = c[i]; i++){
5511                     while((n = n.nextSibling) && n.nodeType != 1);
5512                     if(!n){
5513                         r[++ri] = ci;
5514                     }
5515                 }
5516                 return r;
5517             },
5518
5519             "nth-child" : function(c, a) {
5520                 var r = [], ri = -1;
5521                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5522                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5523                 for(var i = 0, n; n = c[i]; i++){
5524                     var pn = n.parentNode;
5525                     if (batch != pn._batch) {
5526                         var j = 0;
5527                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5528                             if(cn.nodeType == 1){
5529                                cn.nodeIndex = ++j;
5530                             }
5531                         }
5532                         pn._batch = batch;
5533                     }
5534                     if (f == 1) {
5535                         if (l == 0 || n.nodeIndex == l){
5536                             r[++ri] = n;
5537                         }
5538                     } else if ((n.nodeIndex + l) % f == 0){
5539                         r[++ri] = n;
5540                     }
5541                 }
5542
5543                 return r;
5544             },
5545
5546             "only-child" : function(c){
5547                 var r = [], ri = -1;;
5548                 for(var i = 0, ci; ci = c[i]; i++){
5549                     if(!prev(ci) && !next(ci)){
5550                         r[++ri] = ci;
5551                     }
5552                 }
5553                 return r;
5554             },
5555
5556             "empty" : function(c){
5557                 var r = [], ri = -1;
5558                 for(var i = 0, ci; ci = c[i]; i++){
5559                     var cns = ci.childNodes, j = 0, cn, empty = true;
5560                     while(cn = cns[j]){
5561                         ++j;
5562                         if(cn.nodeType == 1 || cn.nodeType == 3){
5563                             empty = false;
5564                             break;
5565                         }
5566                     }
5567                     if(empty){
5568                         r[++ri] = ci;
5569                     }
5570                 }
5571                 return r;
5572             },
5573
5574             "contains" : function(c, v){
5575                 var r = [], ri = -1;
5576                 for(var i = 0, ci; ci = c[i]; i++){
5577                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5578                         r[++ri] = ci;
5579                     }
5580                 }
5581                 return r;
5582             },
5583
5584             "nodeValue" : function(c, v){
5585                 var r = [], ri = -1;
5586                 for(var i = 0, ci; ci = c[i]; i++){
5587                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5588                         r[++ri] = ci;
5589                     }
5590                 }
5591                 return r;
5592             },
5593
5594             "checked" : function(c){
5595                 var r = [], ri = -1;
5596                 for(var i = 0, ci; ci = c[i]; i++){
5597                     if(ci.checked == true){
5598                         r[++ri] = ci;
5599                     }
5600                 }
5601                 return r;
5602             },
5603
5604             "not" : function(c, ss){
5605                 return Roo.DomQuery.filter(c, ss, true);
5606             },
5607
5608             "odd" : function(c){
5609                 return this["nth-child"](c, "odd");
5610             },
5611
5612             "even" : function(c){
5613                 return this["nth-child"](c, "even");
5614             },
5615
5616             "nth" : function(c, a){
5617                 return c[a-1] || [];
5618             },
5619
5620             "first" : function(c){
5621                 return c[0] || [];
5622             },
5623
5624             "last" : function(c){
5625                 return c[c.length-1] || [];
5626             },
5627
5628             "has" : function(c, ss){
5629                 var s = Roo.DomQuery.select;
5630                 var r = [], ri = -1;
5631                 for(var i = 0, ci; ci = c[i]; i++){
5632                     if(s(ss, ci).length > 0){
5633                         r[++ri] = ci;
5634                     }
5635                 }
5636                 return r;
5637             },
5638
5639             "next" : function(c, ss){
5640                 var is = Roo.DomQuery.is;
5641                 var r = [], ri = -1;
5642                 for(var i = 0, ci; ci = c[i]; i++){
5643                     var n = next(ci);
5644                     if(n && is(n, ss)){
5645                         r[++ri] = ci;
5646                     }
5647                 }
5648                 return r;
5649             },
5650
5651             "prev" : function(c, ss){
5652                 var is = Roo.DomQuery.is;
5653                 var r = [], ri = -1;
5654                 for(var i = 0, ci; ci = c[i]; i++){
5655                     var n = prev(ci);
5656                     if(n && is(n, ss)){
5657                         r[++ri] = ci;
5658                     }
5659                 }
5660                 return r;
5661             }
5662         }
5663     };
5664 }();
5665
5666 /**
5667  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5668  * @param {String} path The selector/xpath query
5669  * @param {Node} root (optional) The start of the query (defaults to document).
5670  * @return {Array}
5671  * @member Roo
5672  * @method query
5673  */
5674 Roo.query = Roo.DomQuery.select;
5675 /*
5676  * Based on:
5677  * Ext JS Library 1.1.1
5678  * Copyright(c) 2006-2007, Ext JS, LLC.
5679  *
5680  * Originally Released Under LGPL - original licence link has changed is not relivant.
5681  *
5682  * Fork - LGPL
5683  * <script type="text/javascript">
5684  */
5685
5686 /**
5687  * @class Roo.util.Observable
5688  * Base class that provides a common interface for publishing events. Subclasses are expected to
5689  * to have a property "events" with all the events defined.<br>
5690  * For example:
5691  * <pre><code>
5692  Employee = function(name){
5693     this.name = name;
5694     this.addEvents({
5695         "fired" : true,
5696         "quit" : true
5697     });
5698  }
5699  Roo.extend(Employee, Roo.util.Observable);
5700 </code></pre>
5701  * @param {Object} config properties to use (incuding events / listeners)
5702  */
5703
5704 Roo.util.Observable = function(cfg){
5705     
5706     cfg = cfg|| {};
5707     this.addEvents(cfg.events || {});
5708     if (cfg.events) {
5709         delete cfg.events; // make sure
5710     }
5711      
5712     Roo.apply(this, cfg);
5713     
5714     if(this.listeners){
5715         this.on(this.listeners);
5716         delete this.listeners;
5717     }
5718 };
5719 Roo.util.Observable.prototype = {
5720     /** 
5721  * @cfg {Object} listeners  list of events and functions to call for this object, 
5722  * For example :
5723  * <pre><code>
5724     listeners :  { 
5725        'click' : function(e) {
5726            ..... 
5727         } ,
5728         .... 
5729     } 
5730   </code></pre>
5731  */
5732     
5733     
5734     /**
5735      * Fires the specified event with the passed parameters (minus the event name).
5736      * @param {String} eventName
5737      * @param {Object...} args Variable number of parameters are passed to handlers
5738      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5739      */
5740     fireEvent : function(){
5741         var ce = this.events[arguments[0].toLowerCase()];
5742         if(typeof ce == "object"){
5743             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5744         }else{
5745             return true;
5746         }
5747     },
5748
5749     // private
5750     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5751
5752     /**
5753      * Appends an event handler to this component
5754      * @param {String}   eventName The type of event to listen for
5755      * @param {Function} handler The method the event invokes
5756      * @param {Object}   scope (optional) The scope in which to execute the handler
5757      * function. The handler function's "this" context.
5758      * @param {Object}   options (optional) An object containing handler configuration
5759      * properties. This may contain any of the following properties:<ul>
5760      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5761      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5762      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5763      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5764      * by the specified number of milliseconds. If the event fires again within that time, the original
5765      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5766      * </ul><br>
5767      * <p>
5768      * <b>Combining Options</b><br>
5769      * Using the options argument, it is possible to combine different types of listeners:<br>
5770      * <br>
5771      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5772                 <pre><code>
5773                 el.on('click', this.onClick, this, {
5774                         single: true,
5775                 delay: 100,
5776                 forumId: 4
5777                 });
5778                 </code></pre>
5779      * <p>
5780      * <b>Attaching multiple handlers in 1 call</b><br>
5781      * The method also allows for a single argument to be passed which is a config object containing properties
5782      * which specify multiple handlers.
5783      * <pre><code>
5784                 el.on({
5785                         'click': {
5786                         fn: this.onClick,
5787                         scope: this,
5788                         delay: 100
5789                 }, 
5790                 'mouseover': {
5791                         fn: this.onMouseOver,
5792                         scope: this
5793                 },
5794                 'mouseout': {
5795                         fn: this.onMouseOut,
5796                         scope: this
5797                 }
5798                 });
5799                 </code></pre>
5800      * <p>
5801      * Or a shorthand syntax which passes the same scope object to all handlers:
5802         <pre><code>
5803                 el.on({
5804                         'click': this.onClick,
5805                 'mouseover': this.onMouseOver,
5806                 'mouseout': this.onMouseOut,
5807                 scope: this
5808                 });
5809                 </code></pre>
5810      */
5811     addListener : function(eventName, fn, scope, o){
5812         if(typeof eventName == "object"){
5813             o = eventName;
5814             for(var e in o){
5815                 if(this.filterOptRe.test(e)){
5816                     continue;
5817                 }
5818                 if(typeof o[e] == "function"){
5819                     // shared options
5820                     this.addListener(e, o[e], o.scope,  o);
5821                 }else{
5822                     // individual options
5823                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5824                 }
5825             }
5826             return;
5827         }
5828         o = (!o || typeof o == "boolean") ? {} : o;
5829         eventName = eventName.toLowerCase();
5830         var ce = this.events[eventName] || true;
5831         if(typeof ce == "boolean"){
5832             ce = new Roo.util.Event(this, eventName);
5833             this.events[eventName] = ce;
5834         }
5835         ce.addListener(fn, scope, o);
5836     },
5837
5838     /**
5839      * Removes a listener
5840      * @param {String}   eventName     The type of event to listen for
5841      * @param {Function} handler        The handler to remove
5842      * @param {Object}   scope  (optional) The scope (this object) for the handler
5843      */
5844     removeListener : function(eventName, fn, scope){
5845         var ce = this.events[eventName.toLowerCase()];
5846         if(typeof ce == "object"){
5847             ce.removeListener(fn, scope);
5848         }
5849     },
5850
5851     /**
5852      * Removes all listeners for this object
5853      */
5854     purgeListeners : function(){
5855         for(var evt in this.events){
5856             if(typeof this.events[evt] == "object"){
5857                  this.events[evt].clearListeners();
5858             }
5859         }
5860     },
5861
5862     relayEvents : function(o, events){
5863         var createHandler = function(ename){
5864             return function(){
5865                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5866             };
5867         };
5868         for(var i = 0, len = events.length; i < len; i++){
5869             var ename = events[i];
5870             if(!this.events[ename]){ this.events[ename] = true; };
5871             o.on(ename, createHandler(ename), this);
5872         }
5873     },
5874
5875     /**
5876      * Used to define events on this Observable
5877      * @param {Object} object The object with the events defined
5878      */
5879     addEvents : function(o){
5880         if(!this.events){
5881             this.events = {};
5882         }
5883         Roo.applyIf(this.events, o);
5884     },
5885
5886     /**
5887      * Checks to see if this object has any listeners for a specified event
5888      * @param {String} eventName The name of the event to check for
5889      * @return {Boolean} True if the event is being listened for, else false
5890      */
5891     hasListener : function(eventName){
5892         var e = this.events[eventName];
5893         return typeof e == "object" && e.listeners.length > 0;
5894     }
5895 };
5896 /**
5897  * Appends an event handler to this element (shorthand for addListener)
5898  * @param {String}   eventName     The type of event to listen for
5899  * @param {Function} handler        The method the event invokes
5900  * @param {Object}   scope (optional) The scope in which to execute the handler
5901  * function. The handler function's "this" context.
5902  * @param {Object}   options  (optional)
5903  * @method
5904  */
5905 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5906 /**
5907  * Removes a listener (shorthand for removeListener)
5908  * @param {String}   eventName     The type of event to listen for
5909  * @param {Function} handler        The handler to remove
5910  * @param {Object}   scope  (optional) The scope (this object) for the handler
5911  * @method
5912  */
5913 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5914
5915 /**
5916  * Starts capture on the specified Observable. All events will be passed
5917  * to the supplied function with the event name + standard signature of the event
5918  * <b>before</b> the event is fired. If the supplied function returns false,
5919  * the event will not fire.
5920  * @param {Observable} o The Observable to capture
5921  * @param {Function} fn The function to call
5922  * @param {Object} scope (optional) The scope (this object) for the fn
5923  * @static
5924  */
5925 Roo.util.Observable.capture = function(o, fn, scope){
5926     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5927 };
5928
5929 /**
5930  * Removes <b>all</b> added captures from the Observable.
5931  * @param {Observable} o The Observable to release
5932  * @static
5933  */
5934 Roo.util.Observable.releaseCapture = function(o){
5935     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5936 };
5937
5938 (function(){
5939
5940     var createBuffered = function(h, o, scope){
5941         var task = new Roo.util.DelayedTask();
5942         return function(){
5943             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5944         };
5945     };
5946
5947     var createSingle = function(h, e, fn, scope){
5948         return function(){
5949             e.removeListener(fn, scope);
5950             return h.apply(scope, arguments);
5951         };
5952     };
5953
5954     var createDelayed = function(h, o, scope){
5955         return function(){
5956             var args = Array.prototype.slice.call(arguments, 0);
5957             setTimeout(function(){
5958                 h.apply(scope, args);
5959             }, o.delay || 10);
5960         };
5961     };
5962
5963     Roo.util.Event = function(obj, name){
5964         this.name = name;
5965         this.obj = obj;
5966         this.listeners = [];
5967     };
5968
5969     Roo.util.Event.prototype = {
5970         addListener : function(fn, scope, options){
5971             var o = options || {};
5972             scope = scope || this.obj;
5973             if(!this.isListening(fn, scope)){
5974                 var l = {fn: fn, scope: scope, options: o};
5975                 var h = fn;
5976                 if(o.delay){
5977                     h = createDelayed(h, o, scope);
5978                 }
5979                 if(o.single){
5980                     h = createSingle(h, this, fn, scope);
5981                 }
5982                 if(o.buffer){
5983                     h = createBuffered(h, o, scope);
5984                 }
5985                 l.fireFn = h;
5986                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5987                     this.listeners.push(l);
5988                 }else{
5989                     this.listeners = this.listeners.slice(0);
5990                     this.listeners.push(l);
5991                 }
5992             }
5993         },
5994
5995         findListener : function(fn, scope){
5996             scope = scope || this.obj;
5997             var ls = this.listeners;
5998             for(var i = 0, len = ls.length; i < len; i++){
5999                 var l = ls[i];
6000                 if(l.fn == fn && l.scope == scope){
6001                     return i;
6002                 }
6003             }
6004             return -1;
6005         },
6006
6007         isListening : function(fn, scope){
6008             return this.findListener(fn, scope) != -1;
6009         },
6010
6011         removeListener : function(fn, scope){
6012             var index;
6013             if((index = this.findListener(fn, scope)) != -1){
6014                 if(!this.firing){
6015                     this.listeners.splice(index, 1);
6016                 }else{
6017                     this.listeners = this.listeners.slice(0);
6018                     this.listeners.splice(index, 1);
6019                 }
6020                 return true;
6021             }
6022             return false;
6023         },
6024
6025         clearListeners : function(){
6026             this.listeners = [];
6027         },
6028
6029         fire : function(){
6030             var ls = this.listeners, scope, len = ls.length;
6031             if(len > 0){
6032                 this.firing = true;
6033                 var args = Array.prototype.slice.call(arguments, 0);
6034                 for(var i = 0; i < len; i++){
6035                     var l = ls[i];
6036                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6037                         this.firing = false;
6038                         return false;
6039                     }
6040                 }
6041                 this.firing = false;
6042             }
6043             return true;
6044         }
6045     };
6046 })();/*
6047  * Based on:
6048  * Ext JS Library 1.1.1
6049  * Copyright(c) 2006-2007, Ext JS, LLC.
6050  *
6051  * Originally Released Under LGPL - original licence link has changed is not relivant.
6052  *
6053  * Fork - LGPL
6054  * <script type="text/javascript">
6055  */
6056
6057 /**
6058  * @class Roo.EventManager
6059  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6060  * several useful events directly.
6061  * See {@link Roo.EventObject} for more details on normalized event objects.
6062  * @singleton
6063  */
6064 Roo.EventManager = function(){
6065     var docReadyEvent, docReadyProcId, docReadyState = false;
6066     var resizeEvent, resizeTask, textEvent, textSize;
6067     var E = Roo.lib.Event;
6068     var D = Roo.lib.Dom;
6069
6070     
6071     
6072
6073     var fireDocReady = function(){
6074         if(!docReadyState){
6075             docReadyState = true;
6076             Roo.isReady = true;
6077             if(docReadyProcId){
6078                 clearInterval(docReadyProcId);
6079             }
6080             if(Roo.isGecko || Roo.isOpera) {
6081                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6082             }
6083             if(Roo.isIE){
6084                 var defer = document.getElementById("ie-deferred-loader");
6085                 if(defer){
6086                     defer.onreadystatechange = null;
6087                     defer.parentNode.removeChild(defer);
6088                 }
6089             }
6090             if(docReadyEvent){
6091                 docReadyEvent.fire();
6092                 docReadyEvent.clearListeners();
6093             }
6094         }
6095     };
6096     
6097     var initDocReady = function(){
6098         docReadyEvent = new Roo.util.Event();
6099         if(Roo.isGecko || Roo.isOpera) {
6100             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6101         }else if(Roo.isIE){
6102             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6103             var defer = document.getElementById("ie-deferred-loader");
6104             defer.onreadystatechange = function(){
6105                 if(this.readyState == "complete"){
6106                     fireDocReady();
6107                 }
6108             };
6109         }else if(Roo.isSafari){ 
6110             docReadyProcId = setInterval(function(){
6111                 var rs = document.readyState;
6112                 if(rs == "complete") {
6113                     fireDocReady();     
6114                  }
6115             }, 10);
6116         }
6117         // no matter what, make sure it fires on load
6118         E.on(window, "load", fireDocReady);
6119     };
6120
6121     var createBuffered = function(h, o){
6122         var task = new Roo.util.DelayedTask(h);
6123         return function(e){
6124             // create new event object impl so new events don't wipe out properties
6125             e = new Roo.EventObjectImpl(e);
6126             task.delay(o.buffer, h, null, [e]);
6127         };
6128     };
6129
6130     var createSingle = function(h, el, ename, fn){
6131         return function(e){
6132             Roo.EventManager.removeListener(el, ename, fn);
6133             h(e);
6134         };
6135     };
6136
6137     var createDelayed = function(h, o){
6138         return function(e){
6139             // create new event object impl so new events don't wipe out properties
6140             e = new Roo.EventObjectImpl(e);
6141             setTimeout(function(){
6142                 h(e);
6143             }, o.delay || 10);
6144         };
6145     };
6146     var transitionEndVal = false;
6147     
6148     var transitionEnd = function()
6149     {
6150         if (transitionEndVal) {
6151             return transitionEndVal;
6152         }
6153         var el = document.createElement('div');
6154
6155         var transEndEventNames = {
6156             WebkitTransition : 'webkitTransitionEnd',
6157             MozTransition    : 'transitionend',
6158             OTransition      : 'oTransitionEnd otransitionend',
6159             transition       : 'transitionend'
6160         };
6161     
6162         for (var name in transEndEventNames) {
6163             if (el.style[name] !== undefined) {
6164                 transitionEndVal = transEndEventNames[name];
6165                 return  transitionEndVal ;
6166             }
6167         }
6168     }
6169     
6170
6171     var listen = function(element, ename, opt, fn, scope){
6172         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6173         fn = fn || o.fn; scope = scope || o.scope;
6174         var el = Roo.getDom(element);
6175         
6176         
6177         if(!el){
6178             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6179         }
6180         
6181         if (ename == 'transitionend') {
6182             ename = transitionEnd();
6183         }
6184         var h = function(e){
6185             e = Roo.EventObject.setEvent(e);
6186             var t;
6187             if(o.delegate){
6188                 t = e.getTarget(o.delegate, el);
6189                 if(!t){
6190                     return;
6191                 }
6192             }else{
6193                 t = e.target;
6194             }
6195             if(o.stopEvent === true){
6196                 e.stopEvent();
6197             }
6198             if(o.preventDefault === true){
6199                e.preventDefault();
6200             }
6201             if(o.stopPropagation === true){
6202                 e.stopPropagation();
6203             }
6204
6205             if(o.normalized === false){
6206                 e = e.browserEvent;
6207             }
6208
6209             fn.call(scope || el, e, t, o);
6210         };
6211         if(o.delay){
6212             h = createDelayed(h, o);
6213         }
6214         if(o.single){
6215             h = createSingle(h, el, ename, fn);
6216         }
6217         if(o.buffer){
6218             h = createBuffered(h, o);
6219         }
6220         fn._handlers = fn._handlers || [];
6221         
6222         
6223         fn._handlers.push([Roo.id(el), ename, h]);
6224         
6225         
6226          
6227         E.on(el, ename, h);
6228         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6229             el.addEventListener("DOMMouseScroll", h, false);
6230             E.on(window, 'unload', function(){
6231                 el.removeEventListener("DOMMouseScroll", h, false);
6232             });
6233         }
6234         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6235             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6236         }
6237         return h;
6238     };
6239
6240     var stopListening = function(el, ename, fn){
6241         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6242         if(hds){
6243             for(var i = 0, len = hds.length; i < len; i++){
6244                 var h = hds[i];
6245                 if(h[0] == id && h[1] == ename){
6246                     hd = h[2];
6247                     hds.splice(i, 1);
6248                     break;
6249                 }
6250             }
6251         }
6252         E.un(el, ename, hd);
6253         el = Roo.getDom(el);
6254         if(ename == "mousewheel" && el.addEventListener){
6255             el.removeEventListener("DOMMouseScroll", hd, false);
6256         }
6257         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6258             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6259         }
6260     };
6261
6262     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6263     
6264     var pub = {
6265         
6266         
6267         /** 
6268          * Fix for doc tools
6269          * @scope Roo.EventManager
6270          */
6271         
6272         
6273         /** 
6274          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6275          * object with a Roo.EventObject
6276          * @param {Function} fn        The method the event invokes
6277          * @param {Object}   scope    An object that becomes the scope of the handler
6278          * @param {boolean}  override If true, the obj passed in becomes
6279          *                             the execution scope of the listener
6280          * @return {Function} The wrapped function
6281          * @deprecated
6282          */
6283         wrap : function(fn, scope, override){
6284             return function(e){
6285                 Roo.EventObject.setEvent(e);
6286                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6287             };
6288         },
6289         
6290         /**
6291      * Appends an event handler to an element (shorthand for addListener)
6292      * @param {String/HTMLElement}   element        The html element or id to assign the
6293      * @param {String}   eventName The type of event to listen for
6294      * @param {Function} handler The method the event invokes
6295      * @param {Object}   scope (optional) The scope in which to execute the handler
6296      * function. The handler function's "this" context.
6297      * @param {Object}   options (optional) An object containing handler configuration
6298      * properties. This may contain any of the following properties:<ul>
6299      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6300      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6301      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6302      * <li>preventDefault {Boolean} True to prevent the default action</li>
6303      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6304      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6305      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6306      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6307      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6308      * by the specified number of milliseconds. If the event fires again within that time, the original
6309      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6310      * </ul><br>
6311      * <p>
6312      * <b>Combining Options</b><br>
6313      * Using the options argument, it is possible to combine different types of listeners:<br>
6314      * <br>
6315      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6316      * Code:<pre><code>
6317 el.on('click', this.onClick, this, {
6318     single: true,
6319     delay: 100,
6320     stopEvent : true,
6321     forumId: 4
6322 });</code></pre>
6323      * <p>
6324      * <b>Attaching multiple handlers in 1 call</b><br>
6325       * The method also allows for a single argument to be passed which is a config object containing properties
6326      * which specify multiple handlers.
6327      * <p>
6328      * Code:<pre><code>
6329 el.on({
6330     'click' : {
6331         fn: this.onClick
6332         scope: this,
6333         delay: 100
6334     },
6335     'mouseover' : {
6336         fn: this.onMouseOver
6337         scope: this
6338     },
6339     'mouseout' : {
6340         fn: this.onMouseOut
6341         scope: this
6342     }
6343 });</code></pre>
6344      * <p>
6345      * Or a shorthand syntax:<br>
6346      * Code:<pre><code>
6347 el.on({
6348     'click' : this.onClick,
6349     'mouseover' : this.onMouseOver,
6350     'mouseout' : this.onMouseOut
6351     scope: this
6352 });</code></pre>
6353      */
6354         addListener : function(element, eventName, fn, scope, options){
6355             if(typeof eventName == "object"){
6356                 var o = eventName;
6357                 for(var e in o){
6358                     if(propRe.test(e)){
6359                         continue;
6360                     }
6361                     if(typeof o[e] == "function"){
6362                         // shared options
6363                         listen(element, e, o, o[e], o.scope);
6364                     }else{
6365                         // individual options
6366                         listen(element, e, o[e]);
6367                     }
6368                 }
6369                 return;
6370             }
6371             return listen(element, eventName, options, fn, scope);
6372         },
6373         
6374         /**
6375          * Removes an event handler
6376          *
6377          * @param {String/HTMLElement}   element        The id or html element to remove the 
6378          *                             event from
6379          * @param {String}   eventName     The type of event
6380          * @param {Function} fn
6381          * @return {Boolean} True if a listener was actually removed
6382          */
6383         removeListener : function(element, eventName, fn){
6384             return stopListening(element, eventName, fn);
6385         },
6386         
6387         /**
6388          * Fires when the document is ready (before onload and before images are loaded). Can be 
6389          * accessed shorthanded Roo.onReady().
6390          * @param {Function} fn        The method the event invokes
6391          * @param {Object}   scope    An  object that becomes the scope of the handler
6392          * @param {boolean}  options
6393          */
6394         onDocumentReady : function(fn, scope, options){
6395             if(docReadyState){ // if it already fired
6396                 docReadyEvent.addListener(fn, scope, options);
6397                 docReadyEvent.fire();
6398                 docReadyEvent.clearListeners();
6399                 return;
6400             }
6401             if(!docReadyEvent){
6402                 initDocReady();
6403             }
6404             docReadyEvent.addListener(fn, scope, options);
6405         },
6406         
6407         /**
6408          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6409          * @param {Function} fn        The method the event invokes
6410          * @param {Object}   scope    An object that becomes the scope of the handler
6411          * @param {boolean}  options
6412          */
6413         onWindowResize : function(fn, scope, options){
6414             if(!resizeEvent){
6415                 resizeEvent = new Roo.util.Event();
6416                 resizeTask = new Roo.util.DelayedTask(function(){
6417                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6418                 });
6419                 E.on(window, "resize", function(){
6420                     if(Roo.isIE){
6421                         resizeTask.delay(50);
6422                     }else{
6423                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6424                     }
6425                 });
6426             }
6427             resizeEvent.addListener(fn, scope, options);
6428         },
6429
6430         /**
6431          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6432          * @param {Function} fn        The method the event invokes
6433          * @param {Object}   scope    An object that becomes the scope of the handler
6434          * @param {boolean}  options
6435          */
6436         onTextResize : function(fn, scope, options){
6437             if(!textEvent){
6438                 textEvent = new Roo.util.Event();
6439                 var textEl = new Roo.Element(document.createElement('div'));
6440                 textEl.dom.className = 'x-text-resize';
6441                 textEl.dom.innerHTML = 'X';
6442                 textEl.appendTo(document.body);
6443                 textSize = textEl.dom.offsetHeight;
6444                 setInterval(function(){
6445                     if(textEl.dom.offsetHeight != textSize){
6446                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6447                     }
6448                 }, this.textResizeInterval);
6449             }
6450             textEvent.addListener(fn, scope, options);
6451         },
6452
6453         /**
6454          * Removes the passed window resize listener.
6455          * @param {Function} fn        The method the event invokes
6456          * @param {Object}   scope    The scope of handler
6457          */
6458         removeResizeListener : function(fn, scope){
6459             if(resizeEvent){
6460                 resizeEvent.removeListener(fn, scope);
6461             }
6462         },
6463
6464         // private
6465         fireResize : function(){
6466             if(resizeEvent){
6467                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6468             }   
6469         },
6470         /**
6471          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6472          */
6473         ieDeferSrc : false,
6474         /**
6475          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6476          */
6477         textResizeInterval : 50
6478     };
6479     
6480     /**
6481      * Fix for doc tools
6482      * @scopeAlias pub=Roo.EventManager
6483      */
6484     
6485      /**
6486      * Appends an event handler to an element (shorthand for addListener)
6487      * @param {String/HTMLElement}   element        The html element or id to assign the
6488      * @param {String}   eventName The type of event to listen for
6489      * @param {Function} handler The method the event invokes
6490      * @param {Object}   scope (optional) The scope in which to execute the handler
6491      * function. The handler function's "this" context.
6492      * @param {Object}   options (optional) An object containing handler configuration
6493      * properties. This may contain any of the following properties:<ul>
6494      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6495      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6496      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6497      * <li>preventDefault {Boolean} True to prevent the default action</li>
6498      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6499      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6500      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6501      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6502      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6503      * by the specified number of milliseconds. If the event fires again within that time, the original
6504      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6505      * </ul><br>
6506      * <p>
6507      * <b>Combining Options</b><br>
6508      * Using the options argument, it is possible to combine different types of listeners:<br>
6509      * <br>
6510      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6511      * Code:<pre><code>
6512 el.on('click', this.onClick, this, {
6513     single: true,
6514     delay: 100,
6515     stopEvent : true,
6516     forumId: 4
6517 });</code></pre>
6518      * <p>
6519      * <b>Attaching multiple handlers in 1 call</b><br>
6520       * The method also allows for a single argument to be passed which is a config object containing properties
6521      * which specify multiple handlers.
6522      * <p>
6523      * Code:<pre><code>
6524 el.on({
6525     'click' : {
6526         fn: this.onClick
6527         scope: this,
6528         delay: 100
6529     },
6530     'mouseover' : {
6531         fn: this.onMouseOver
6532         scope: this
6533     },
6534     'mouseout' : {
6535         fn: this.onMouseOut
6536         scope: this
6537     }
6538 });</code></pre>
6539      * <p>
6540      * Or a shorthand syntax:<br>
6541      * Code:<pre><code>
6542 el.on({
6543     'click' : this.onClick,
6544     'mouseover' : this.onMouseOver,
6545     'mouseout' : this.onMouseOut
6546     scope: this
6547 });</code></pre>
6548      */
6549     pub.on = pub.addListener;
6550     pub.un = pub.removeListener;
6551
6552     pub.stoppedMouseDownEvent = new Roo.util.Event();
6553     return pub;
6554 }();
6555 /**
6556   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6557   * @param {Function} fn        The method the event invokes
6558   * @param {Object}   scope    An  object that becomes the scope of the handler
6559   * @param {boolean}  override If true, the obj passed in becomes
6560   *                             the execution scope of the listener
6561   * @member Roo
6562   * @method onReady
6563  */
6564 Roo.onReady = Roo.EventManager.onDocumentReady;
6565
6566 Roo.onReady(function(){
6567     var bd = Roo.get(document.body);
6568     if(!bd){ return; }
6569
6570     var cls = [
6571             Roo.isIE ? "roo-ie"
6572             : Roo.isGecko ? "roo-gecko"
6573             : Roo.isOpera ? "roo-opera"
6574             : Roo.isSafari ? "roo-safari" : ""];
6575
6576     if(Roo.isMac){
6577         cls.push("roo-mac");
6578     }
6579     if(Roo.isLinux){
6580         cls.push("roo-linux");
6581     }
6582     if(Roo.isIOS){
6583         cls.push("roo-ios");
6584     }
6585     if(Roo.isBorderBox){
6586         cls.push('roo-border-box');
6587     }
6588     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6589         var p = bd.dom.parentNode;
6590         if(p){
6591             p.className += ' roo-strict';
6592         }
6593     }
6594     bd.addClass(cls.join(' '));
6595 });
6596
6597 /**
6598  * @class Roo.EventObject
6599  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6600  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6601  * Example:
6602  * <pre><code>
6603  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6604     e.preventDefault();
6605     var target = e.getTarget();
6606     ...
6607  }
6608  var myDiv = Roo.get("myDiv");
6609  myDiv.on("click", handleClick);
6610  //or
6611  Roo.EventManager.on("myDiv", 'click', handleClick);
6612  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6613  </code></pre>
6614  * @singleton
6615  */
6616 Roo.EventObject = function(){
6617     
6618     var E = Roo.lib.Event;
6619     
6620     // safari keypress events for special keys return bad keycodes
6621     var safariKeys = {
6622         63234 : 37, // left
6623         63235 : 39, // right
6624         63232 : 38, // up
6625         63233 : 40, // down
6626         63276 : 33, // page up
6627         63277 : 34, // page down
6628         63272 : 46, // delete
6629         63273 : 36, // home
6630         63275 : 35  // end
6631     };
6632
6633     // normalize button clicks
6634     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6635                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6636
6637     Roo.EventObjectImpl = function(e){
6638         if(e){
6639             this.setEvent(e.browserEvent || e);
6640         }
6641     };
6642     Roo.EventObjectImpl.prototype = {
6643         /**
6644          * Used to fix doc tools.
6645          * @scope Roo.EventObject.prototype
6646          */
6647             
6648
6649         
6650         
6651         /** The normal browser event */
6652         browserEvent : null,
6653         /** The button pressed in a mouse event */
6654         button : -1,
6655         /** True if the shift key was down during the event */
6656         shiftKey : false,
6657         /** True if the control key was down during the event */
6658         ctrlKey : false,
6659         /** True if the alt key was down during the event */
6660         altKey : false,
6661
6662         /** Key constant 
6663         * @type Number */
6664         BACKSPACE : 8,
6665         /** Key constant 
6666         * @type Number */
6667         TAB : 9,
6668         /** Key constant 
6669         * @type Number */
6670         RETURN : 13,
6671         /** Key constant 
6672         * @type Number */
6673         ENTER : 13,
6674         /** Key constant 
6675         * @type Number */
6676         SHIFT : 16,
6677         /** Key constant 
6678         * @type Number */
6679         CONTROL : 17,
6680         /** Key constant 
6681         * @type Number */
6682         ESC : 27,
6683         /** Key constant 
6684         * @type Number */
6685         SPACE : 32,
6686         /** Key constant 
6687         * @type Number */
6688         PAGEUP : 33,
6689         /** Key constant 
6690         * @type Number */
6691         PAGEDOWN : 34,
6692         /** Key constant 
6693         * @type Number */
6694         END : 35,
6695         /** Key constant 
6696         * @type Number */
6697         HOME : 36,
6698         /** Key constant 
6699         * @type Number */
6700         LEFT : 37,
6701         /** Key constant 
6702         * @type Number */
6703         UP : 38,
6704         /** Key constant 
6705         * @type Number */
6706         RIGHT : 39,
6707         /** Key constant 
6708         * @type Number */
6709         DOWN : 40,
6710         /** Key constant 
6711         * @type Number */
6712         DELETE : 46,
6713         /** Key constant 
6714         * @type Number */
6715         F5 : 116,
6716
6717            /** @private */
6718         setEvent : function(e){
6719             if(e == this || (e && e.browserEvent)){ // already wrapped
6720                 return e;
6721             }
6722             this.browserEvent = e;
6723             if(e){
6724                 // normalize buttons
6725                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6726                 if(e.type == 'click' && this.button == -1){
6727                     this.button = 0;
6728                 }
6729                 this.type = e.type;
6730                 this.shiftKey = e.shiftKey;
6731                 // mac metaKey behaves like ctrlKey
6732                 this.ctrlKey = e.ctrlKey || e.metaKey;
6733                 this.altKey = e.altKey;
6734                 // in getKey these will be normalized for the mac
6735                 this.keyCode = e.keyCode;
6736                 // keyup warnings on firefox.
6737                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6738                 // cache the target for the delayed and or buffered events
6739                 this.target = E.getTarget(e);
6740                 // same for XY
6741                 this.xy = E.getXY(e);
6742             }else{
6743                 this.button = -1;
6744                 this.shiftKey = false;
6745                 this.ctrlKey = false;
6746                 this.altKey = false;
6747                 this.keyCode = 0;
6748                 this.charCode =0;
6749                 this.target = null;
6750                 this.xy = [0, 0];
6751             }
6752             return this;
6753         },
6754
6755         /**
6756          * Stop the event (preventDefault and stopPropagation)
6757          */
6758         stopEvent : function(){
6759             if(this.browserEvent){
6760                 if(this.browserEvent.type == 'mousedown'){
6761                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6762                 }
6763                 E.stopEvent(this.browserEvent);
6764             }
6765         },
6766
6767         /**
6768          * Prevents the browsers default handling of the event.
6769          */
6770         preventDefault : function(){
6771             if(this.browserEvent){
6772                 E.preventDefault(this.browserEvent);
6773             }
6774         },
6775
6776         /** @private */
6777         isNavKeyPress : function(){
6778             var k = this.keyCode;
6779             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6780             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6781         },
6782
6783         isSpecialKey : function(){
6784             var k = this.keyCode;
6785             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6786             (k == 16) || (k == 17) ||
6787             (k >= 18 && k <= 20) ||
6788             (k >= 33 && k <= 35) ||
6789             (k >= 36 && k <= 39) ||
6790             (k >= 44 && k <= 45);
6791         },
6792         /**
6793          * Cancels bubbling of the event.
6794          */
6795         stopPropagation : function(){
6796             if(this.browserEvent){
6797                 if(this.type == 'mousedown'){
6798                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6799                 }
6800                 E.stopPropagation(this.browserEvent);
6801             }
6802         },
6803
6804         /**
6805          * Gets the key code for the event.
6806          * @return {Number}
6807          */
6808         getCharCode : function(){
6809             return this.charCode || this.keyCode;
6810         },
6811
6812         /**
6813          * Returns a normalized keyCode for the event.
6814          * @return {Number} The key code
6815          */
6816         getKey : function(){
6817             var k = this.keyCode || this.charCode;
6818             return Roo.isSafari ? (safariKeys[k] || k) : k;
6819         },
6820
6821         /**
6822          * Gets the x coordinate of the event.
6823          * @return {Number}
6824          */
6825         getPageX : function(){
6826             return this.xy[0];
6827         },
6828
6829         /**
6830          * Gets the y coordinate of the event.
6831          * @return {Number}
6832          */
6833         getPageY : function(){
6834             return this.xy[1];
6835         },
6836
6837         /**
6838          * Gets the time of the event.
6839          * @return {Number}
6840          */
6841         getTime : function(){
6842             if(this.browserEvent){
6843                 return E.getTime(this.browserEvent);
6844             }
6845             return null;
6846         },
6847
6848         /**
6849          * Gets the page coordinates of the event.
6850          * @return {Array} The xy values like [x, y]
6851          */
6852         getXY : function(){
6853             return this.xy;
6854         },
6855
6856         /**
6857          * Gets the target for the event.
6858          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6859          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6860                 search as a number or element (defaults to 10 || document.body)
6861          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6862          * @return {HTMLelement}
6863          */
6864         getTarget : function(selector, maxDepth, returnEl){
6865             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6866         },
6867         /**
6868          * Gets the related target.
6869          * @return {HTMLElement}
6870          */
6871         getRelatedTarget : function(){
6872             if(this.browserEvent){
6873                 return E.getRelatedTarget(this.browserEvent);
6874             }
6875             return null;
6876         },
6877
6878         /**
6879          * Normalizes mouse wheel delta across browsers
6880          * @return {Number} The delta
6881          */
6882         getWheelDelta : function(){
6883             var e = this.browserEvent;
6884             var delta = 0;
6885             if(e.wheelDelta){ /* IE/Opera. */
6886                 delta = e.wheelDelta/120;
6887             }else if(e.detail){ /* Mozilla case. */
6888                 delta = -e.detail/3;
6889             }
6890             return delta;
6891         },
6892
6893         /**
6894          * Returns true if the control, meta, shift or alt key was pressed during this event.
6895          * @return {Boolean}
6896          */
6897         hasModifier : function(){
6898             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6899         },
6900
6901         /**
6902          * Returns true if the target of this event equals el or is a child of el
6903          * @param {String/HTMLElement/Element} el
6904          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6905          * @return {Boolean}
6906          */
6907         within : function(el, related){
6908             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6909             return t && Roo.fly(el).contains(t);
6910         },
6911
6912         getPoint : function(){
6913             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6914         }
6915     };
6916
6917     return new Roo.EventObjectImpl();
6918 }();
6919             
6920     /*
6921  * Based on:
6922  * Ext JS Library 1.1.1
6923  * Copyright(c) 2006-2007, Ext JS, LLC.
6924  *
6925  * Originally Released Under LGPL - original licence link has changed is not relivant.
6926  *
6927  * Fork - LGPL
6928  * <script type="text/javascript">
6929  */
6930
6931  
6932 // was in Composite Element!??!?!
6933  
6934 (function(){
6935     var D = Roo.lib.Dom;
6936     var E = Roo.lib.Event;
6937     var A = Roo.lib.Anim;
6938
6939     // local style camelizing for speed
6940     var propCache = {};
6941     var camelRe = /(-[a-z])/gi;
6942     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6943     var view = document.defaultView;
6944
6945 /**
6946  * @class Roo.Element
6947  * Represents an Element in the DOM.<br><br>
6948  * Usage:<br>
6949 <pre><code>
6950 var el = Roo.get("my-div");
6951
6952 // or with getEl
6953 var el = getEl("my-div");
6954
6955 // or with a DOM element
6956 var el = Roo.get(myDivElement);
6957 </code></pre>
6958  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6959  * each call instead of constructing a new one.<br><br>
6960  * <b>Animations</b><br />
6961  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6962  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6963 <pre>
6964 Option    Default   Description
6965 --------- --------  ---------------------------------------------
6966 duration  .35       The duration of the animation in seconds
6967 easing    easeOut   The YUI easing method
6968 callback  none      A function to execute when the anim completes
6969 scope     this      The scope (this) of the callback function
6970 </pre>
6971 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6972 * manipulate the animation. Here's an example:
6973 <pre><code>
6974 var el = Roo.get("my-div");
6975
6976 // no animation
6977 el.setWidth(100);
6978
6979 // default animation
6980 el.setWidth(100, true);
6981
6982 // animation with some options set
6983 el.setWidth(100, {
6984     duration: 1,
6985     callback: this.foo,
6986     scope: this
6987 });
6988
6989 // using the "anim" property to get the Anim object
6990 var opt = {
6991     duration: 1,
6992     callback: this.foo,
6993     scope: this
6994 };
6995 el.setWidth(100, opt);
6996 ...
6997 if(opt.anim.isAnimated()){
6998     opt.anim.stop();
6999 }
7000 </code></pre>
7001 * <b> Composite (Collections of) Elements</b><br />
7002  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7003  * @constructor Create a new Element directly.
7004  * @param {String/HTMLElement} element
7005  * @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).
7006  */
7007     Roo.Element = function(element, forceNew){
7008         var dom = typeof element == "string" ?
7009                 document.getElementById(element) : element;
7010         if(!dom){ // invalid id/element
7011             return null;
7012         }
7013         var id = dom.id;
7014         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7015             return Roo.Element.cache[id];
7016         }
7017
7018         /**
7019          * The DOM element
7020          * @type HTMLElement
7021          */
7022         this.dom = dom;
7023
7024         /**
7025          * The DOM element ID
7026          * @type String
7027          */
7028         this.id = id || Roo.id(dom);
7029     };
7030
7031     var El = Roo.Element;
7032
7033     El.prototype = {
7034         /**
7035          * The element's default display mode  (defaults to "")
7036          * @type String
7037          */
7038         originalDisplay : "",
7039
7040         visibilityMode : 1,
7041         /**
7042          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7043          * @type String
7044          */
7045         defaultUnit : "px",
7046         /**
7047          * Sets the element's visibility mode. When setVisible() is called it
7048          * will use this to determine whether to set the visibility or the display property.
7049          * @param visMode Element.VISIBILITY or Element.DISPLAY
7050          * @return {Roo.Element} this
7051          */
7052         setVisibilityMode : function(visMode){
7053             this.visibilityMode = visMode;
7054             return this;
7055         },
7056         /**
7057          * Convenience method for setVisibilityMode(Element.DISPLAY)
7058          * @param {String} display (optional) What to set display to when visible
7059          * @return {Roo.Element} this
7060          */
7061         enableDisplayMode : function(display){
7062             this.setVisibilityMode(El.DISPLAY);
7063             if(typeof display != "undefined") this.originalDisplay = display;
7064             return this;
7065         },
7066
7067         /**
7068          * 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)
7069          * @param {String} selector The simple selector to test
7070          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7071                 search as a number or element (defaults to 10 || document.body)
7072          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7073          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7074          */
7075         findParent : function(simpleSelector, maxDepth, returnEl){
7076             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7077             maxDepth = maxDepth || 50;
7078             if(typeof maxDepth != "number"){
7079                 stopEl = Roo.getDom(maxDepth);
7080                 maxDepth = 10;
7081             }
7082             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7083                 if(dq.is(p, simpleSelector)){
7084                     return returnEl ? Roo.get(p) : p;
7085                 }
7086                 depth++;
7087                 p = p.parentNode;
7088             }
7089             return null;
7090         },
7091
7092
7093         /**
7094          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7095          * @param {String} selector The simple selector to test
7096          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7097                 search as a number or element (defaults to 10 || document.body)
7098          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7099          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7100          */
7101         findParentNode : function(simpleSelector, maxDepth, returnEl){
7102             var p = Roo.fly(this.dom.parentNode, '_internal');
7103             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7104         },
7105
7106         /**
7107          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7108          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7109          * @param {String} selector The simple selector to test
7110          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7111                 search as a number or element (defaults to 10 || document.body)
7112          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7113          */
7114         up : function(simpleSelector, maxDepth){
7115             return this.findParentNode(simpleSelector, maxDepth, true);
7116         },
7117
7118
7119
7120         /**
7121          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7122          * @param {String} selector The simple selector to test
7123          * @return {Boolean} True if this element matches the selector, else false
7124          */
7125         is : function(simpleSelector){
7126             return Roo.DomQuery.is(this.dom, simpleSelector);
7127         },
7128
7129         /**
7130          * Perform animation on this element.
7131          * @param {Object} args The YUI animation control args
7132          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7133          * @param {Function} onComplete (optional) Function to call when animation completes
7134          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7135          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7136          * @return {Roo.Element} this
7137          */
7138         animate : function(args, duration, onComplete, easing, animType){
7139             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7140             return this;
7141         },
7142
7143         /*
7144          * @private Internal animation call
7145          */
7146         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7147             animType = animType || 'run';
7148             opt = opt || {};
7149             var anim = Roo.lib.Anim[animType](
7150                 this.dom, args,
7151                 (opt.duration || defaultDur) || .35,
7152                 (opt.easing || defaultEase) || 'easeOut',
7153                 function(){
7154                     Roo.callback(cb, this);
7155                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7156                 },
7157                 this
7158             );
7159             opt.anim = anim;
7160             return anim;
7161         },
7162
7163         // private legacy anim prep
7164         preanim : function(a, i){
7165             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7166         },
7167
7168         /**
7169          * Removes worthless text nodes
7170          * @param {Boolean} forceReclean (optional) By default the element
7171          * keeps track if it has been cleaned already so
7172          * you can call this over and over. However, if you update the element and
7173          * need to force a reclean, you can pass true.
7174          */
7175         clean : function(forceReclean){
7176             if(this.isCleaned && forceReclean !== true){
7177                 return this;
7178             }
7179             var ns = /\S/;
7180             var d = this.dom, n = d.firstChild, ni = -1;
7181             while(n){
7182                 var nx = n.nextSibling;
7183                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7184                     d.removeChild(n);
7185                 }else{
7186                     n.nodeIndex = ++ni;
7187                 }
7188                 n = nx;
7189             }
7190             this.isCleaned = true;
7191             return this;
7192         },
7193
7194         // private
7195         calcOffsetsTo : function(el){
7196             el = Roo.get(el);
7197             var d = el.dom;
7198             var restorePos = false;
7199             if(el.getStyle('position') == 'static'){
7200                 el.position('relative');
7201                 restorePos = true;
7202             }
7203             var x = 0, y =0;
7204             var op = this.dom;
7205             while(op && op != d && op.tagName != 'HTML'){
7206                 x+= op.offsetLeft;
7207                 y+= op.offsetTop;
7208                 op = op.offsetParent;
7209             }
7210             if(restorePos){
7211                 el.position('static');
7212             }
7213             return [x, y];
7214         },
7215
7216         /**
7217          * Scrolls this element into view within the passed container.
7218          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7219          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7220          * @return {Roo.Element} this
7221          */
7222         scrollIntoView : function(container, hscroll){
7223             var c = Roo.getDom(container) || document.body;
7224             var el = this.dom;
7225
7226             var o = this.calcOffsetsTo(c),
7227                 l = o[0],
7228                 t = o[1],
7229                 b = t+el.offsetHeight,
7230                 r = l+el.offsetWidth;
7231
7232             var ch = c.clientHeight;
7233             var ct = parseInt(c.scrollTop, 10);
7234             var cl = parseInt(c.scrollLeft, 10);
7235             var cb = ct + ch;
7236             var cr = cl + c.clientWidth;
7237
7238             if(t < ct){
7239                 c.scrollTop = t;
7240             }else if(b > cb){
7241                 c.scrollTop = b-ch;
7242             }
7243
7244             if(hscroll !== false){
7245                 if(l < cl){
7246                     c.scrollLeft = l;
7247                 }else if(r > cr){
7248                     c.scrollLeft = r-c.clientWidth;
7249                 }
7250             }
7251             return this;
7252         },
7253
7254         // private
7255         scrollChildIntoView : function(child, hscroll){
7256             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7257         },
7258
7259         /**
7260          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7261          * the new height may not be available immediately.
7262          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7263          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7264          * @param {Function} onComplete (optional) Function to call when animation completes
7265          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7266          * @return {Roo.Element} this
7267          */
7268         autoHeight : function(animate, duration, onComplete, easing){
7269             var oldHeight = this.getHeight();
7270             this.clip();
7271             this.setHeight(1); // force clipping
7272             setTimeout(function(){
7273                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7274                 if(!animate){
7275                     this.setHeight(height);
7276                     this.unclip();
7277                     if(typeof onComplete == "function"){
7278                         onComplete();
7279                     }
7280                 }else{
7281                     this.setHeight(oldHeight); // restore original height
7282                     this.setHeight(height, animate, duration, function(){
7283                         this.unclip();
7284                         if(typeof onComplete == "function") onComplete();
7285                     }.createDelegate(this), easing);
7286                 }
7287             }.createDelegate(this), 0);
7288             return this;
7289         },
7290
7291         /**
7292          * Returns true if this element is an ancestor of the passed element
7293          * @param {HTMLElement/String} el The element to check
7294          * @return {Boolean} True if this element is an ancestor of el, else false
7295          */
7296         contains : function(el){
7297             if(!el){return false;}
7298             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7299         },
7300
7301         /**
7302          * Checks whether the element is currently visible using both visibility and display properties.
7303          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7304          * @return {Boolean} True if the element is currently visible, else false
7305          */
7306         isVisible : function(deep) {
7307             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7308             if(deep !== true || !vis){
7309                 return vis;
7310             }
7311             var p = this.dom.parentNode;
7312             while(p && p.tagName.toLowerCase() != "body"){
7313                 if(!Roo.fly(p, '_isVisible').isVisible()){
7314                     return false;
7315                 }
7316                 p = p.parentNode;
7317             }
7318             return true;
7319         },
7320
7321         /**
7322          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7323          * @param {String} selector The CSS selector
7324          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7325          * @return {CompositeElement/CompositeElementLite} The composite element
7326          */
7327         select : function(selector, unique){
7328             return El.select(selector, unique, this.dom);
7329         },
7330
7331         /**
7332          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7333          * @param {String} selector The CSS selector
7334          * @return {Array} An array of the matched nodes
7335          */
7336         query : function(selector, unique){
7337             return Roo.DomQuery.select(selector, this.dom);
7338         },
7339
7340         /**
7341          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7342          * @param {String} selector The CSS selector
7343          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7344          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7345          */
7346         child : function(selector, returnDom){
7347             var n = Roo.DomQuery.selectNode(selector, this.dom);
7348             return returnDom ? n : Roo.get(n);
7349         },
7350
7351         /**
7352          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7353          * @param {String} selector The CSS selector
7354          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7355          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7356          */
7357         down : function(selector, returnDom){
7358             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7359             return returnDom ? n : Roo.get(n);
7360         },
7361
7362         /**
7363          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7364          * @param {String} group The group the DD object is member of
7365          * @param {Object} config The DD config object
7366          * @param {Object} overrides An object containing methods to override/implement on the DD object
7367          * @return {Roo.dd.DD} The DD object
7368          */
7369         initDD : function(group, config, overrides){
7370             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7371             return Roo.apply(dd, overrides);
7372         },
7373
7374         /**
7375          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7376          * @param {String} group The group the DDProxy object is member of
7377          * @param {Object} config The DDProxy config object
7378          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7379          * @return {Roo.dd.DDProxy} The DDProxy object
7380          */
7381         initDDProxy : function(group, config, overrides){
7382             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7383             return Roo.apply(dd, overrides);
7384         },
7385
7386         /**
7387          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7388          * @param {String} group The group the DDTarget object is member of
7389          * @param {Object} config The DDTarget config object
7390          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7391          * @return {Roo.dd.DDTarget} The DDTarget object
7392          */
7393         initDDTarget : function(group, config, overrides){
7394             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7395             return Roo.apply(dd, overrides);
7396         },
7397
7398         /**
7399          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7400          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7401          * @param {Boolean} visible Whether the element is visible
7402          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7403          * @return {Roo.Element} this
7404          */
7405          setVisible : function(visible, animate){
7406             if(!animate || !A){
7407                 if(this.visibilityMode == El.DISPLAY){
7408                     this.setDisplayed(visible);
7409                 }else{
7410                     this.fixDisplay();
7411                     this.dom.style.visibility = visible ? "visible" : "hidden";
7412                 }
7413             }else{
7414                 // closure for composites
7415                 var dom = this.dom;
7416                 var visMode = this.visibilityMode;
7417                 if(visible){
7418                     this.setOpacity(.01);
7419                     this.setVisible(true);
7420                 }
7421                 this.anim({opacity: { to: (visible?1:0) }},
7422                       this.preanim(arguments, 1),
7423                       null, .35, 'easeIn', function(){
7424                          if(!visible){
7425                              if(visMode == El.DISPLAY){
7426                                  dom.style.display = "none";
7427                              }else{
7428                                  dom.style.visibility = "hidden";
7429                              }
7430                              Roo.get(dom).setOpacity(1);
7431                          }
7432                      });
7433             }
7434             return this;
7435         },
7436
7437         /**
7438          * Returns true if display is not "none"
7439          * @return {Boolean}
7440          */
7441         isDisplayed : function() {
7442             return this.getStyle("display") != "none";
7443         },
7444
7445         /**
7446          * Toggles the element's visibility or display, depending on visibility mode.
7447          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7448          * @return {Roo.Element} this
7449          */
7450         toggle : function(animate){
7451             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7452             return this;
7453         },
7454
7455         /**
7456          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7457          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7458          * @return {Roo.Element} this
7459          */
7460         setDisplayed : function(value) {
7461             if(typeof value == "boolean"){
7462                value = value ? this.originalDisplay : "none";
7463             }
7464             this.setStyle("display", value);
7465             return this;
7466         },
7467
7468         /**
7469          * Tries to focus the element. Any exceptions are caught and ignored.
7470          * @return {Roo.Element} this
7471          */
7472         focus : function() {
7473             try{
7474                 this.dom.focus();
7475             }catch(e){}
7476             return this;
7477         },
7478
7479         /**
7480          * Tries to blur the element. Any exceptions are caught and ignored.
7481          * @return {Roo.Element} this
7482          */
7483         blur : function() {
7484             try{
7485                 this.dom.blur();
7486             }catch(e){}
7487             return this;
7488         },
7489
7490         /**
7491          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7492          * @param {String/Array} className The CSS class to add, or an array of classes
7493          * @return {Roo.Element} this
7494          */
7495         addClass : function(className){
7496             if(className instanceof Array){
7497                 for(var i = 0, len = className.length; i < len; i++) {
7498                     this.addClass(className[i]);
7499                 }
7500             }else{
7501                 if(className && !this.hasClass(className)){
7502                     this.dom.className = this.dom.className + " " + className;
7503                 }
7504             }
7505             return this;
7506         },
7507
7508         /**
7509          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7510          * @param {String/Array} className The CSS class to add, or an array of classes
7511          * @return {Roo.Element} this
7512          */
7513         radioClass : function(className){
7514             var siblings = this.dom.parentNode.childNodes;
7515             for(var i = 0; i < siblings.length; i++) {
7516                 var s = siblings[i];
7517                 if(s.nodeType == 1){
7518                     Roo.get(s).removeClass(className);
7519                 }
7520             }
7521             this.addClass(className);
7522             return this;
7523         },
7524
7525         /**
7526          * Removes one or more CSS classes from the element.
7527          * @param {String/Array} className The CSS class to remove, or an array of classes
7528          * @return {Roo.Element} this
7529          */
7530         removeClass : function(className){
7531             if(!className || !this.dom.className){
7532                 return this;
7533             }
7534             if(className instanceof Array){
7535                 for(var i = 0, len = className.length; i < len; i++) {
7536                     this.removeClass(className[i]);
7537                 }
7538             }else{
7539                 if(this.hasClass(className)){
7540                     var re = this.classReCache[className];
7541                     if (!re) {
7542                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7543                        this.classReCache[className] = re;
7544                     }
7545                     this.dom.className =
7546                         this.dom.className.replace(re, " ");
7547                 }
7548             }
7549             return this;
7550         },
7551
7552         // private
7553         classReCache: {},
7554
7555         /**
7556          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7557          * @param {String} className The CSS class to toggle
7558          * @return {Roo.Element} this
7559          */
7560         toggleClass : function(className){
7561             if(this.hasClass(className)){
7562                 this.removeClass(className);
7563             }else{
7564                 this.addClass(className);
7565             }
7566             return this;
7567         },
7568
7569         /**
7570          * Checks if the specified CSS class exists on this element's DOM node.
7571          * @param {String} className The CSS class to check for
7572          * @return {Boolean} True if the class exists, else false
7573          */
7574         hasClass : function(className){
7575             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7576         },
7577
7578         /**
7579          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7580          * @param {String} oldClassName The CSS class to replace
7581          * @param {String} newClassName The replacement CSS class
7582          * @return {Roo.Element} this
7583          */
7584         replaceClass : function(oldClassName, newClassName){
7585             this.removeClass(oldClassName);
7586             this.addClass(newClassName);
7587             return this;
7588         },
7589
7590         /**
7591          * Returns an object with properties matching the styles requested.
7592          * For example, el.getStyles('color', 'font-size', 'width') might return
7593          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7594          * @param {String} style1 A style name
7595          * @param {String} style2 A style name
7596          * @param {String} etc.
7597          * @return {Object} The style object
7598          */
7599         getStyles : function(){
7600             var a = arguments, len = a.length, r = {};
7601             for(var i = 0; i < len; i++){
7602                 r[a[i]] = this.getStyle(a[i]);
7603             }
7604             return r;
7605         },
7606
7607         /**
7608          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7609          * @param {String} property The style property whose value is returned.
7610          * @return {String} The current value of the style property for this element.
7611          */
7612         getStyle : function(){
7613             return view && view.getComputedStyle ?
7614                 function(prop){
7615                     var el = this.dom, v, cs, camel;
7616                     if(prop == 'float'){
7617                         prop = "cssFloat";
7618                     }
7619                     if(el.style && (v = el.style[prop])){
7620                         return v;
7621                     }
7622                     if(cs = view.getComputedStyle(el, "")){
7623                         if(!(camel = propCache[prop])){
7624                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7625                         }
7626                         return cs[camel];
7627                     }
7628                     return null;
7629                 } :
7630                 function(prop){
7631                     var el = this.dom, v, cs, camel;
7632                     if(prop == 'opacity'){
7633                         if(typeof el.style.filter == 'string'){
7634                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7635                             if(m){
7636                                 var fv = parseFloat(m[1]);
7637                                 if(!isNaN(fv)){
7638                                     return fv ? fv / 100 : 0;
7639                                 }
7640                             }
7641                         }
7642                         return 1;
7643                     }else if(prop == 'float'){
7644                         prop = "styleFloat";
7645                     }
7646                     if(!(camel = propCache[prop])){
7647                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7648                     }
7649                     if(v = el.style[camel]){
7650                         return v;
7651                     }
7652                     if(cs = el.currentStyle){
7653                         return cs[camel];
7654                     }
7655                     return null;
7656                 };
7657         }(),
7658
7659         /**
7660          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7661          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7662          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7663          * @return {Roo.Element} this
7664          */
7665         setStyle : function(prop, value){
7666             if(typeof prop == "string"){
7667                 
7668                 if (prop == 'float') {
7669                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7670                     return this;
7671                 }
7672                 
7673                 var camel;
7674                 if(!(camel = propCache[prop])){
7675                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7676                 }
7677                 
7678                 if(camel == 'opacity') {
7679                     this.setOpacity(value);
7680                 }else{
7681                     this.dom.style[camel] = value;
7682                 }
7683             }else{
7684                 for(var style in prop){
7685                     if(typeof prop[style] != "function"){
7686                        this.setStyle(style, prop[style]);
7687                     }
7688                 }
7689             }
7690             return this;
7691         },
7692
7693         /**
7694          * More flexible version of {@link #setStyle} for setting style properties.
7695          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7696          * a function which returns such a specification.
7697          * @return {Roo.Element} this
7698          */
7699         applyStyles : function(style){
7700             Roo.DomHelper.applyStyles(this.dom, style);
7701             return this;
7702         },
7703
7704         /**
7705           * 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).
7706           * @return {Number} The X position of the element
7707           */
7708         getX : function(){
7709             return D.getX(this.dom);
7710         },
7711
7712         /**
7713           * 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).
7714           * @return {Number} The Y position of the element
7715           */
7716         getY : function(){
7717             return D.getY(this.dom);
7718         },
7719
7720         /**
7721           * 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).
7722           * @return {Array} The XY position of the element
7723           */
7724         getXY : function(){
7725             return D.getXY(this.dom);
7726         },
7727
7728         /**
7729          * 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).
7730          * @param {Number} The X position of the element
7731          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7732          * @return {Roo.Element} this
7733          */
7734         setX : function(x, animate){
7735             if(!animate || !A){
7736                 D.setX(this.dom, x);
7737             }else{
7738                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7739             }
7740             return this;
7741         },
7742
7743         /**
7744          * 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).
7745          * @param {Number} The Y position of the element
7746          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7747          * @return {Roo.Element} this
7748          */
7749         setY : function(y, animate){
7750             if(!animate || !A){
7751                 D.setY(this.dom, y);
7752             }else{
7753                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7754             }
7755             return this;
7756         },
7757
7758         /**
7759          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7760          * @param {String} left The left CSS property value
7761          * @return {Roo.Element} this
7762          */
7763         setLeft : function(left){
7764             this.setStyle("left", this.addUnits(left));
7765             return this;
7766         },
7767
7768         /**
7769          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7770          * @param {String} top The top CSS property value
7771          * @return {Roo.Element} this
7772          */
7773         setTop : function(top){
7774             this.setStyle("top", this.addUnits(top));
7775             return this;
7776         },
7777
7778         /**
7779          * Sets the element's CSS right style.
7780          * @param {String} right The right CSS property value
7781          * @return {Roo.Element} this
7782          */
7783         setRight : function(right){
7784             this.setStyle("right", this.addUnits(right));
7785             return this;
7786         },
7787
7788         /**
7789          * Sets the element's CSS bottom style.
7790          * @param {String} bottom The bottom CSS property value
7791          * @return {Roo.Element} this
7792          */
7793         setBottom : function(bottom){
7794             this.setStyle("bottom", this.addUnits(bottom));
7795             return this;
7796         },
7797
7798         /**
7799          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7800          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7801          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7802          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7803          * @return {Roo.Element} this
7804          */
7805         setXY : function(pos, animate){
7806             if(!animate || !A){
7807                 D.setXY(this.dom, pos);
7808             }else{
7809                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7810             }
7811             return this;
7812         },
7813
7814         /**
7815          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7816          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7817          * @param {Number} x X value for new position (coordinates are page-based)
7818          * @param {Number} y Y value for new position (coordinates are page-based)
7819          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7820          * @return {Roo.Element} this
7821          */
7822         setLocation : function(x, y, animate){
7823             this.setXY([x, y], this.preanim(arguments, 2));
7824             return this;
7825         },
7826
7827         /**
7828          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7829          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7830          * @param {Number} x X value for new position (coordinates are page-based)
7831          * @param {Number} y Y value for new position (coordinates are page-based)
7832          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7833          * @return {Roo.Element} this
7834          */
7835         moveTo : function(x, y, animate){
7836             this.setXY([x, y], this.preanim(arguments, 2));
7837             return this;
7838         },
7839
7840         /**
7841          * Returns the region of the given element.
7842          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7843          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7844          */
7845         getRegion : function(){
7846             return D.getRegion(this.dom);
7847         },
7848
7849         /**
7850          * Returns the offset height of the element
7851          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7852          * @return {Number} The element's height
7853          */
7854         getHeight : function(contentHeight){
7855             var h = this.dom.offsetHeight || 0;
7856             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7857         },
7858
7859         /**
7860          * Returns the offset width of the element
7861          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7862          * @return {Number} The element's width
7863          */
7864         getWidth : function(contentWidth){
7865             var w = this.dom.offsetWidth || 0;
7866             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7867         },
7868
7869         /**
7870          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7871          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7872          * if a height has not been set using CSS.
7873          * @return {Number}
7874          */
7875         getComputedHeight : function(){
7876             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7877             if(!h){
7878                 h = parseInt(this.getStyle('height'), 10) || 0;
7879                 if(!this.isBorderBox()){
7880                     h += this.getFrameWidth('tb');
7881                 }
7882             }
7883             return h;
7884         },
7885
7886         /**
7887          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7888          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7889          * if a width has not been set using CSS.
7890          * @return {Number}
7891          */
7892         getComputedWidth : function(){
7893             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7894             if(!w){
7895                 w = parseInt(this.getStyle('width'), 10) || 0;
7896                 if(!this.isBorderBox()){
7897                     w += this.getFrameWidth('lr');
7898                 }
7899             }
7900             return w;
7901         },
7902
7903         /**
7904          * Returns the size of the element.
7905          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7906          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7907          */
7908         getSize : function(contentSize){
7909             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7910         },
7911
7912         /**
7913          * Returns the width and height of the viewport.
7914          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7915          */
7916         getViewSize : function(){
7917             var d = this.dom, doc = document, aw = 0, ah = 0;
7918             if(d == doc || d == doc.body){
7919                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7920             }else{
7921                 return {
7922                     width : d.clientWidth,
7923                     height: d.clientHeight
7924                 };
7925             }
7926         },
7927
7928         /**
7929          * Returns the value of the "value" attribute
7930          * @param {Boolean} asNumber true to parse the value as a number
7931          * @return {String/Number}
7932          */
7933         getValue : function(asNumber){
7934             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7935         },
7936
7937         // private
7938         adjustWidth : function(width){
7939             if(typeof width == "number"){
7940                 if(this.autoBoxAdjust && !this.isBorderBox()){
7941                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7942                 }
7943                 if(width < 0){
7944                     width = 0;
7945                 }
7946             }
7947             return width;
7948         },
7949
7950         // private
7951         adjustHeight : function(height){
7952             if(typeof height == "number"){
7953                if(this.autoBoxAdjust && !this.isBorderBox()){
7954                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7955                }
7956                if(height < 0){
7957                    height = 0;
7958                }
7959             }
7960             return height;
7961         },
7962
7963         /**
7964          * Set the width of the element
7965          * @param {Number} width The new width
7966          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7967          * @return {Roo.Element} this
7968          */
7969         setWidth : function(width, animate){
7970             width = this.adjustWidth(width);
7971             if(!animate || !A){
7972                 this.dom.style.width = this.addUnits(width);
7973             }else{
7974                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7975             }
7976             return this;
7977         },
7978
7979         /**
7980          * Set the height of the element
7981          * @param {Number} height The new height
7982          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7983          * @return {Roo.Element} this
7984          */
7985          setHeight : function(height, animate){
7986             height = this.adjustHeight(height);
7987             if(!animate || !A){
7988                 this.dom.style.height = this.addUnits(height);
7989             }else{
7990                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7991             }
7992             return this;
7993         },
7994
7995         /**
7996          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
7997          * @param {Number} width The new width
7998          * @param {Number} height The new height
7999          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8000          * @return {Roo.Element} this
8001          */
8002          setSize : function(width, height, animate){
8003             if(typeof width == "object"){ // in case of object from getSize()
8004                 height = width.height; width = width.width;
8005             }
8006             width = this.adjustWidth(width); height = this.adjustHeight(height);
8007             if(!animate || !A){
8008                 this.dom.style.width = this.addUnits(width);
8009                 this.dom.style.height = this.addUnits(height);
8010             }else{
8011                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8012             }
8013             return this;
8014         },
8015
8016         /**
8017          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8018          * @param {Number} x X value for new position (coordinates are page-based)
8019          * @param {Number} y Y value for new position (coordinates are page-based)
8020          * @param {Number} width The new width
8021          * @param {Number} height The new height
8022          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8023          * @return {Roo.Element} this
8024          */
8025         setBounds : function(x, y, width, height, animate){
8026             if(!animate || !A){
8027                 this.setSize(width, height);
8028                 this.setLocation(x, y);
8029             }else{
8030                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8031                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8032                               this.preanim(arguments, 4), 'motion');
8033             }
8034             return this;
8035         },
8036
8037         /**
8038          * 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.
8039          * @param {Roo.lib.Region} region The region to fill
8040          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8041          * @return {Roo.Element} this
8042          */
8043         setRegion : function(region, animate){
8044             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8045             return this;
8046         },
8047
8048         /**
8049          * Appends an event handler
8050          *
8051          * @param {String}   eventName     The type of event to append
8052          * @param {Function} fn        The method the event invokes
8053          * @param {Object} scope       (optional) The scope (this object) of the fn
8054          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8055          */
8056         addListener : function(eventName, fn, scope, options){
8057             if (this.dom) {
8058                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8059             }
8060         },
8061
8062         /**
8063          * Removes an event handler from this element
8064          * @param {String} eventName the type of event to remove
8065          * @param {Function} fn the method the event invokes
8066          * @return {Roo.Element} this
8067          */
8068         removeListener : function(eventName, fn){
8069             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8070             return this;
8071         },
8072
8073         /**
8074          * Removes all previous added listeners from this element
8075          * @return {Roo.Element} this
8076          */
8077         removeAllListeners : function(){
8078             E.purgeElement(this.dom);
8079             return this;
8080         },
8081
8082         relayEvent : function(eventName, observable){
8083             this.on(eventName, function(e){
8084                 observable.fireEvent(eventName, e);
8085             });
8086         },
8087
8088         /**
8089          * Set the opacity of the element
8090          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8091          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8092          * @return {Roo.Element} this
8093          */
8094          setOpacity : function(opacity, animate){
8095             if(!animate || !A){
8096                 var s = this.dom.style;
8097                 if(Roo.isIE){
8098                     s.zoom = 1;
8099                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8100                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8101                 }else{
8102                     s.opacity = opacity;
8103                 }
8104             }else{
8105                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8106             }
8107             return this;
8108         },
8109
8110         /**
8111          * Gets the left X coordinate
8112          * @param {Boolean} local True to get the local css position instead of page coordinate
8113          * @return {Number}
8114          */
8115         getLeft : function(local){
8116             if(!local){
8117                 return this.getX();
8118             }else{
8119                 return parseInt(this.getStyle("left"), 10) || 0;
8120             }
8121         },
8122
8123         /**
8124          * Gets the right X coordinate of the element (element X position + element width)
8125          * @param {Boolean} local True to get the local css position instead of page coordinate
8126          * @return {Number}
8127          */
8128         getRight : function(local){
8129             if(!local){
8130                 return this.getX() + this.getWidth();
8131             }else{
8132                 return (this.getLeft(true) + this.getWidth()) || 0;
8133             }
8134         },
8135
8136         /**
8137          * Gets the top Y coordinate
8138          * @param {Boolean} local True to get the local css position instead of page coordinate
8139          * @return {Number}
8140          */
8141         getTop : function(local) {
8142             if(!local){
8143                 return this.getY();
8144             }else{
8145                 return parseInt(this.getStyle("top"), 10) || 0;
8146             }
8147         },
8148
8149         /**
8150          * Gets the bottom Y coordinate of the element (element Y position + element height)
8151          * @param {Boolean} local True to get the local css position instead of page coordinate
8152          * @return {Number}
8153          */
8154         getBottom : function(local){
8155             if(!local){
8156                 return this.getY() + this.getHeight();
8157             }else{
8158                 return (this.getTop(true) + this.getHeight()) || 0;
8159             }
8160         },
8161
8162         /**
8163         * Initializes positioning on this element. If a desired position is not passed, it will make the
8164         * the element positioned relative IF it is not already positioned.
8165         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8166         * @param {Number} zIndex (optional) The zIndex to apply
8167         * @param {Number} x (optional) Set the page X position
8168         * @param {Number} y (optional) Set the page Y position
8169         */
8170         position : function(pos, zIndex, x, y){
8171             if(!pos){
8172                if(this.getStyle('position') == 'static'){
8173                    this.setStyle('position', 'relative');
8174                }
8175             }else{
8176                 this.setStyle("position", pos);
8177             }
8178             if(zIndex){
8179                 this.setStyle("z-index", zIndex);
8180             }
8181             if(x !== undefined && y !== undefined){
8182                 this.setXY([x, y]);
8183             }else if(x !== undefined){
8184                 this.setX(x);
8185             }else if(y !== undefined){
8186                 this.setY(y);
8187             }
8188         },
8189
8190         /**
8191         * Clear positioning back to the default when the document was loaded
8192         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8193         * @return {Roo.Element} this
8194          */
8195         clearPositioning : function(value){
8196             value = value ||'';
8197             this.setStyle({
8198                 "left": value,
8199                 "right": value,
8200                 "top": value,
8201                 "bottom": value,
8202                 "z-index": "",
8203                 "position" : "static"
8204             });
8205             return this;
8206         },
8207
8208         /**
8209         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8210         * snapshot before performing an update and then restoring the element.
8211         * @return {Object}
8212         */
8213         getPositioning : function(){
8214             var l = this.getStyle("left");
8215             var t = this.getStyle("top");
8216             return {
8217                 "position" : this.getStyle("position"),
8218                 "left" : l,
8219                 "right" : l ? "" : this.getStyle("right"),
8220                 "top" : t,
8221                 "bottom" : t ? "" : this.getStyle("bottom"),
8222                 "z-index" : this.getStyle("z-index")
8223             };
8224         },
8225
8226         /**
8227          * Gets the width of the border(s) for the specified side(s)
8228          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8229          * passing lr would get the border (l)eft width + the border (r)ight width.
8230          * @return {Number} The width of the sides passed added together
8231          */
8232         getBorderWidth : function(side){
8233             return this.addStyles(side, El.borders);
8234         },
8235
8236         /**
8237          * Gets the width of the padding(s) for the specified side(s)
8238          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8239          * passing lr would get the padding (l)eft + the padding (r)ight.
8240          * @return {Number} The padding of the sides passed added together
8241          */
8242         getPadding : function(side){
8243             return this.addStyles(side, El.paddings);
8244         },
8245
8246         /**
8247         * Set positioning with an object returned by getPositioning().
8248         * @param {Object} posCfg
8249         * @return {Roo.Element} this
8250          */
8251         setPositioning : function(pc){
8252             this.applyStyles(pc);
8253             if(pc.right == "auto"){
8254                 this.dom.style.right = "";
8255             }
8256             if(pc.bottom == "auto"){
8257                 this.dom.style.bottom = "";
8258             }
8259             return this;
8260         },
8261
8262         // private
8263         fixDisplay : function(){
8264             if(this.getStyle("display") == "none"){
8265                 this.setStyle("visibility", "hidden");
8266                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8267                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8268                     this.setStyle("display", "block");
8269                 }
8270             }
8271         },
8272
8273         /**
8274          * Quick set left and top adding default units
8275          * @param {String} left The left CSS property value
8276          * @param {String} top The top CSS property value
8277          * @return {Roo.Element} this
8278          */
8279          setLeftTop : function(left, top){
8280             this.dom.style.left = this.addUnits(left);
8281             this.dom.style.top = this.addUnits(top);
8282             return this;
8283         },
8284
8285         /**
8286          * Move this element relative to its current position.
8287          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8288          * @param {Number} distance How far to move the element in pixels
8289          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8290          * @return {Roo.Element} this
8291          */
8292          move : function(direction, distance, animate){
8293             var xy = this.getXY();
8294             direction = direction.toLowerCase();
8295             switch(direction){
8296                 case "l":
8297                 case "left":
8298                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8299                     break;
8300                case "r":
8301                case "right":
8302                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8303                     break;
8304                case "t":
8305                case "top":
8306                case "up":
8307                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8308                     break;
8309                case "b":
8310                case "bottom":
8311                case "down":
8312                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8313                     break;
8314             }
8315             return this;
8316         },
8317
8318         /**
8319          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8320          * @return {Roo.Element} this
8321          */
8322         clip : function(){
8323             if(!this.isClipped){
8324                this.isClipped = true;
8325                this.originalClip = {
8326                    "o": this.getStyle("overflow"),
8327                    "x": this.getStyle("overflow-x"),
8328                    "y": this.getStyle("overflow-y")
8329                };
8330                this.setStyle("overflow", "hidden");
8331                this.setStyle("overflow-x", "hidden");
8332                this.setStyle("overflow-y", "hidden");
8333             }
8334             return this;
8335         },
8336
8337         /**
8338          *  Return clipping (overflow) to original clipping before clip() was called
8339          * @return {Roo.Element} this
8340          */
8341         unclip : function(){
8342             if(this.isClipped){
8343                 this.isClipped = false;
8344                 var o = this.originalClip;
8345                 if(o.o){this.setStyle("overflow", o.o);}
8346                 if(o.x){this.setStyle("overflow-x", o.x);}
8347                 if(o.y){this.setStyle("overflow-y", o.y);}
8348             }
8349             return this;
8350         },
8351
8352
8353         /**
8354          * Gets the x,y coordinates specified by the anchor position on the element.
8355          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8356          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8357          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8358          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8359          * @return {Array} [x, y] An array containing the element's x and y coordinates
8360          */
8361         getAnchorXY : function(anchor, local, s){
8362             //Passing a different size is useful for pre-calculating anchors,
8363             //especially for anchored animations that change the el size.
8364
8365             var w, h, vp = false;
8366             if(!s){
8367                 var d = this.dom;
8368                 if(d == document.body || d == document){
8369                     vp = true;
8370                     w = D.getViewWidth(); h = D.getViewHeight();
8371                 }else{
8372                     w = this.getWidth(); h = this.getHeight();
8373                 }
8374             }else{
8375                 w = s.width;  h = s.height;
8376             }
8377             var x = 0, y = 0, r = Math.round;
8378             switch((anchor || "tl").toLowerCase()){
8379                 case "c":
8380                     x = r(w*.5);
8381                     y = r(h*.5);
8382                 break;
8383                 case "t":
8384                     x = r(w*.5);
8385                     y = 0;
8386                 break;
8387                 case "l":
8388                     x = 0;
8389                     y = r(h*.5);
8390                 break;
8391                 case "r":
8392                     x = w;
8393                     y = r(h*.5);
8394                 break;
8395                 case "b":
8396                     x = r(w*.5);
8397                     y = h;
8398                 break;
8399                 case "tl":
8400                     x = 0;
8401                     y = 0;
8402                 break;
8403                 case "bl":
8404                     x = 0;
8405                     y = h;
8406                 break;
8407                 case "br":
8408                     x = w;
8409                     y = h;
8410                 break;
8411                 case "tr":
8412                     x = w;
8413                     y = 0;
8414                 break;
8415             }
8416             if(local === true){
8417                 return [x, y];
8418             }
8419             if(vp){
8420                 var sc = this.getScroll();
8421                 return [x + sc.left, y + sc.top];
8422             }
8423             //Add the element's offset xy
8424             var o = this.getXY();
8425             return [x+o[0], y+o[1]];
8426         },
8427
8428         /**
8429          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8430          * supported position values.
8431          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8432          * @param {String} position The position to align to.
8433          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8434          * @return {Array} [x, y]
8435          */
8436         getAlignToXY : function(el, p, o){
8437             el = Roo.get(el);
8438             var d = this.dom;
8439             if(!el.dom){
8440                 throw "Element.alignTo with an element that doesn't exist";
8441             }
8442             var c = false; //constrain to viewport
8443             var p1 = "", p2 = "";
8444             o = o || [0,0];
8445
8446             if(!p){
8447                 p = "tl-bl";
8448             }else if(p == "?"){
8449                 p = "tl-bl?";
8450             }else if(p.indexOf("-") == -1){
8451                 p = "tl-" + p;
8452             }
8453             p = p.toLowerCase();
8454             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8455             if(!m){
8456                throw "Element.alignTo with an invalid alignment " + p;
8457             }
8458             p1 = m[1]; p2 = m[2]; c = !!m[3];
8459
8460             //Subtract the aligned el's internal xy from the target's offset xy
8461             //plus custom offset to get the aligned el's new offset xy
8462             var a1 = this.getAnchorXY(p1, true);
8463             var a2 = el.getAnchorXY(p2, false);
8464             var x = a2[0] - a1[0] + o[0];
8465             var y = a2[1] - a1[1] + o[1];
8466             if(c){
8467                 //constrain the aligned el to viewport if necessary
8468                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8469                 // 5px of margin for ie
8470                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8471
8472                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8473                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8474                 //otherwise swap the aligned el to the opposite border of the target.
8475                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8476                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8477                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8478                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8479
8480                var doc = document;
8481                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8482                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8483
8484                if((x+w) > dw + scrollX){
8485                     x = swapX ? r.left-w : dw+scrollX-w;
8486                 }
8487                if(x < scrollX){
8488                    x = swapX ? r.right : scrollX;
8489                }
8490                if((y+h) > dh + scrollY){
8491                     y = swapY ? r.top-h : dh+scrollY-h;
8492                 }
8493                if (y < scrollY){
8494                    y = swapY ? r.bottom : scrollY;
8495                }
8496             }
8497             return [x,y];
8498         },
8499
8500         // private
8501         getConstrainToXY : function(){
8502             var os = {top:0, left:0, bottom:0, right: 0};
8503
8504             return function(el, local, offsets, proposedXY){
8505                 el = Roo.get(el);
8506                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8507
8508                 var vw, vh, vx = 0, vy = 0;
8509                 if(el.dom == document.body || el.dom == document){
8510                     vw = Roo.lib.Dom.getViewWidth();
8511                     vh = Roo.lib.Dom.getViewHeight();
8512                 }else{
8513                     vw = el.dom.clientWidth;
8514                     vh = el.dom.clientHeight;
8515                     if(!local){
8516                         var vxy = el.getXY();
8517                         vx = vxy[0];
8518                         vy = vxy[1];
8519                     }
8520                 }
8521
8522                 var s = el.getScroll();
8523
8524                 vx += offsets.left + s.left;
8525                 vy += offsets.top + s.top;
8526
8527                 vw -= offsets.right;
8528                 vh -= offsets.bottom;
8529
8530                 var vr = vx+vw;
8531                 var vb = vy+vh;
8532
8533                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8534                 var x = xy[0], y = xy[1];
8535                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8536
8537                 // only move it if it needs it
8538                 var moved = false;
8539
8540                 // first validate right/bottom
8541                 if((x + w) > vr){
8542                     x = vr - w;
8543                     moved = true;
8544                 }
8545                 if((y + h) > vb){
8546                     y = vb - h;
8547                     moved = true;
8548                 }
8549                 // then make sure top/left isn't negative
8550                 if(x < vx){
8551                     x = vx;
8552                     moved = true;
8553                 }
8554                 if(y < vy){
8555                     y = vy;
8556                     moved = true;
8557                 }
8558                 return moved ? [x, y] : false;
8559             };
8560         }(),
8561
8562         // private
8563         adjustForConstraints : function(xy, parent, offsets){
8564             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8565         },
8566
8567         /**
8568          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8569          * document it aligns it to the viewport.
8570          * The position parameter is optional, and can be specified in any one of the following formats:
8571          * <ul>
8572          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8573          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8574          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8575          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8576          *   <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
8577          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8578          * </ul>
8579          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8580          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8581          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8582          * that specified in order to enforce the viewport constraints.
8583          * Following are all of the supported anchor positions:
8584     <pre>
8585     Value  Description
8586     -----  -----------------------------
8587     tl     The top left corner (default)
8588     t      The center of the top edge
8589     tr     The top right corner
8590     l      The center of the left edge
8591     c      In the center of the element
8592     r      The center of the right edge
8593     bl     The bottom left corner
8594     b      The center of the bottom edge
8595     br     The bottom right corner
8596     </pre>
8597     Example Usage:
8598     <pre><code>
8599     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8600     el.alignTo("other-el");
8601
8602     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8603     el.alignTo("other-el", "tr?");
8604
8605     // align the bottom right corner of el with the center left edge of other-el
8606     el.alignTo("other-el", "br-l?");
8607
8608     // align the center of el with the bottom left corner of other-el and
8609     // adjust the x position by -6 pixels (and the y position by 0)
8610     el.alignTo("other-el", "c-bl", [-6, 0]);
8611     </code></pre>
8612          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8613          * @param {String} position The position to align to.
8614          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8615          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8616          * @return {Roo.Element} this
8617          */
8618         alignTo : function(element, position, offsets, animate){
8619             var xy = this.getAlignToXY(element, position, offsets);
8620             this.setXY(xy, this.preanim(arguments, 3));
8621             return this;
8622         },
8623
8624         /**
8625          * Anchors an element to another element and realigns it when the window is resized.
8626          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8627          * @param {String} position The position to align to.
8628          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8629          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8630          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8631          * is a number, it is used as the buffer delay (defaults to 50ms).
8632          * @param {Function} callback The function to call after the animation finishes
8633          * @return {Roo.Element} this
8634          */
8635         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8636             var action = function(){
8637                 this.alignTo(el, alignment, offsets, animate);
8638                 Roo.callback(callback, this);
8639             };
8640             Roo.EventManager.onWindowResize(action, this);
8641             var tm = typeof monitorScroll;
8642             if(tm != 'undefined'){
8643                 Roo.EventManager.on(window, 'scroll', action, this,
8644                     {buffer: tm == 'number' ? monitorScroll : 50});
8645             }
8646             action.call(this); // align immediately
8647             return this;
8648         },
8649         /**
8650          * Clears any opacity settings from this element. Required in some cases for IE.
8651          * @return {Roo.Element} this
8652          */
8653         clearOpacity : function(){
8654             if (window.ActiveXObject) {
8655                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8656                     this.dom.style.filter = "";
8657                 }
8658             } else {
8659                 this.dom.style.opacity = "";
8660                 this.dom.style["-moz-opacity"] = "";
8661                 this.dom.style["-khtml-opacity"] = "";
8662             }
8663             return this;
8664         },
8665
8666         /**
8667          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8668          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8669          * @return {Roo.Element} this
8670          */
8671         hide : function(animate){
8672             this.setVisible(false, this.preanim(arguments, 0));
8673             return this;
8674         },
8675
8676         /**
8677         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8678         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8679          * @return {Roo.Element} this
8680          */
8681         show : function(animate){
8682             this.setVisible(true, this.preanim(arguments, 0));
8683             return this;
8684         },
8685
8686         /**
8687          * @private Test if size has a unit, otherwise appends the default
8688          */
8689         addUnits : function(size){
8690             return Roo.Element.addUnits(size, this.defaultUnit);
8691         },
8692
8693         /**
8694          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8695          * @return {Roo.Element} this
8696          */
8697         beginMeasure : function(){
8698             var el = this.dom;
8699             if(el.offsetWidth || el.offsetHeight){
8700                 return this; // offsets work already
8701             }
8702             var changed = [];
8703             var p = this.dom, b = document.body; // start with this element
8704             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8705                 var pe = Roo.get(p);
8706                 if(pe.getStyle('display') == 'none'){
8707                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8708                     p.style.visibility = "hidden";
8709                     p.style.display = "block";
8710                 }
8711                 p = p.parentNode;
8712             }
8713             this._measureChanged = changed;
8714             return this;
8715
8716         },
8717
8718         /**
8719          * Restores displays to before beginMeasure was called
8720          * @return {Roo.Element} this
8721          */
8722         endMeasure : function(){
8723             var changed = this._measureChanged;
8724             if(changed){
8725                 for(var i = 0, len = changed.length; i < len; i++) {
8726                     var r = changed[i];
8727                     r.el.style.visibility = r.visibility;
8728                     r.el.style.display = "none";
8729                 }
8730                 this._measureChanged = null;
8731             }
8732             return this;
8733         },
8734
8735         /**
8736         * Update the innerHTML of this element, optionally searching for and processing scripts
8737         * @param {String} html The new HTML
8738         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8739         * @param {Function} callback For async script loading you can be noticed when the update completes
8740         * @return {Roo.Element} this
8741          */
8742         update : function(html, loadScripts, callback){
8743             if(typeof html == "undefined"){
8744                 html = "";
8745             }
8746             if(loadScripts !== true){
8747                 this.dom.innerHTML = html;
8748                 if(typeof callback == "function"){
8749                     callback();
8750                 }
8751                 return this;
8752             }
8753             var id = Roo.id();
8754             var dom = this.dom;
8755
8756             html += '<span id="' + id + '"></span>';
8757
8758             E.onAvailable(id, function(){
8759                 var hd = document.getElementsByTagName("head")[0];
8760                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8761                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8762                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8763
8764                 var match;
8765                 while(match = re.exec(html)){
8766                     var attrs = match[1];
8767                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8768                     if(srcMatch && srcMatch[2]){
8769                        var s = document.createElement("script");
8770                        s.src = srcMatch[2];
8771                        var typeMatch = attrs.match(typeRe);
8772                        if(typeMatch && typeMatch[2]){
8773                            s.type = typeMatch[2];
8774                        }
8775                        hd.appendChild(s);
8776                     }else if(match[2] && match[2].length > 0){
8777                         if(window.execScript) {
8778                            window.execScript(match[2]);
8779                         } else {
8780                             /**
8781                              * eval:var:id
8782                              * eval:var:dom
8783                              * eval:var:html
8784                              * 
8785                              */
8786                            window.eval(match[2]);
8787                         }
8788                     }
8789                 }
8790                 var el = document.getElementById(id);
8791                 if(el){el.parentNode.removeChild(el);}
8792                 if(typeof callback == "function"){
8793                     callback();
8794                 }
8795             });
8796             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8797             return this;
8798         },
8799
8800         /**
8801          * Direct access to the UpdateManager update() method (takes the same parameters).
8802          * @param {String/Function} url The url for this request or a function to call to get the url
8803          * @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}
8804          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8805          * @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.
8806          * @return {Roo.Element} this
8807          */
8808         load : function(){
8809             var um = this.getUpdateManager();
8810             um.update.apply(um, arguments);
8811             return this;
8812         },
8813
8814         /**
8815         * Gets this element's UpdateManager
8816         * @return {Roo.UpdateManager} The UpdateManager
8817         */
8818         getUpdateManager : function(){
8819             if(!this.updateManager){
8820                 this.updateManager = new Roo.UpdateManager(this);
8821             }
8822             return this.updateManager;
8823         },
8824
8825         /**
8826          * Disables text selection for this element (normalized across browsers)
8827          * @return {Roo.Element} this
8828          */
8829         unselectable : function(){
8830             this.dom.unselectable = "on";
8831             this.swallowEvent("selectstart", true);
8832             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8833             this.addClass("x-unselectable");
8834             return this;
8835         },
8836
8837         /**
8838         * Calculates the x, y to center this element on the screen
8839         * @return {Array} The x, y values [x, y]
8840         */
8841         getCenterXY : function(){
8842             return this.getAlignToXY(document, 'c-c');
8843         },
8844
8845         /**
8846         * Centers the Element in either the viewport, or another Element.
8847         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8848         */
8849         center : function(centerIn){
8850             this.alignTo(centerIn || document, 'c-c');
8851             return this;
8852         },
8853
8854         /**
8855          * Tests various css rules/browsers to determine if this element uses a border box
8856          * @return {Boolean}
8857          */
8858         isBorderBox : function(){
8859             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8860         },
8861
8862         /**
8863          * Return a box {x, y, width, height} that can be used to set another elements
8864          * size/location to match this element.
8865          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8866          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8867          * @return {Object} box An object in the format {x, y, width, height}
8868          */
8869         getBox : function(contentBox, local){
8870             var xy;
8871             if(!local){
8872                 xy = this.getXY();
8873             }else{
8874                 var left = parseInt(this.getStyle("left"), 10) || 0;
8875                 var top = parseInt(this.getStyle("top"), 10) || 0;
8876                 xy = [left, top];
8877             }
8878             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8879             if(!contentBox){
8880                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8881             }else{
8882                 var l = this.getBorderWidth("l")+this.getPadding("l");
8883                 var r = this.getBorderWidth("r")+this.getPadding("r");
8884                 var t = this.getBorderWidth("t")+this.getPadding("t");
8885                 var b = this.getBorderWidth("b")+this.getPadding("b");
8886                 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)};
8887             }
8888             bx.right = bx.x + bx.width;
8889             bx.bottom = bx.y + bx.height;
8890             return bx;
8891         },
8892
8893         /**
8894          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8895          for more information about the sides.
8896          * @param {String} sides
8897          * @return {Number}
8898          */
8899         getFrameWidth : function(sides, onlyContentBox){
8900             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8901         },
8902
8903         /**
8904          * 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.
8905          * @param {Object} box The box to fill {x, y, width, height}
8906          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8907          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8908          * @return {Roo.Element} this
8909          */
8910         setBox : function(box, adjust, animate){
8911             var w = box.width, h = box.height;
8912             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8913                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8914                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8915             }
8916             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8917             return this;
8918         },
8919
8920         /**
8921          * Forces the browser to repaint this element
8922          * @return {Roo.Element} this
8923          */
8924          repaint : function(){
8925             var dom = this.dom;
8926             this.addClass("x-repaint");
8927             setTimeout(function(){
8928                 Roo.get(dom).removeClass("x-repaint");
8929             }, 1);
8930             return this;
8931         },
8932
8933         /**
8934          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8935          * then it returns the calculated width of the sides (see getPadding)
8936          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8937          * @return {Object/Number}
8938          */
8939         getMargins : function(side){
8940             if(!side){
8941                 return {
8942                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8943                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8944                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8945                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8946                 };
8947             }else{
8948                 return this.addStyles(side, El.margins);
8949              }
8950         },
8951
8952         // private
8953         addStyles : function(sides, styles){
8954             var val = 0, v, w;
8955             for(var i = 0, len = sides.length; i < len; i++){
8956                 v = this.getStyle(styles[sides.charAt(i)]);
8957                 if(v){
8958                      w = parseInt(v, 10);
8959                      if(w){ val += w; }
8960                 }
8961             }
8962             return val;
8963         },
8964
8965         /**
8966          * Creates a proxy element of this element
8967          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8968          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8969          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8970          * @return {Roo.Element} The new proxy element
8971          */
8972         createProxy : function(config, renderTo, matchBox){
8973             if(renderTo){
8974                 renderTo = Roo.getDom(renderTo);
8975             }else{
8976                 renderTo = document.body;
8977             }
8978             config = typeof config == "object" ?
8979                 config : {tag : "div", cls: config};
8980             var proxy = Roo.DomHelper.append(renderTo, config, true);
8981             if(matchBox){
8982                proxy.setBox(this.getBox());
8983             }
8984             return proxy;
8985         },
8986
8987         /**
8988          * Puts a mask over this element to disable user interaction. Requires core.css.
8989          * This method can only be applied to elements which accept child nodes.
8990          * @param {String} msg (optional) A message to display in the mask
8991          * @param {String} msgCls (optional) A css class to apply to the msg element
8992          * @return {Element} The mask  element
8993          */
8994         mask : function(msg, msgCls)
8995         {
8996             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
8997                 this.setStyle("position", "relative");
8998             }
8999             if(!this._mask){
9000                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9001             }
9002             this.addClass("x-masked");
9003             this._mask.setDisplayed(true);
9004             
9005             // we wander
9006             var z = 0;
9007             var dom = this.dom
9008             while (dom && dom.style) {
9009                 if (!isNaN(parseInt(dom.style.zIndex))) {
9010                     z = Math.max(z, parseInt(dom.style.zIndex));
9011                 }
9012                 dom = dom.parentNode;
9013             }
9014             // if we are masking the body - then it hides everything..
9015             if (this.dom == document.body) {
9016                 z = 1000000;
9017                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9018                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9019             }
9020            
9021             if(typeof msg == 'string'){
9022                 if(!this._maskMsg){
9023                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9024                 }
9025                 var mm = this._maskMsg;
9026                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9027                 if (mm.dom.firstChild) { // weird IE issue?
9028                     mm.dom.firstChild.innerHTML = msg;
9029                 }
9030                 mm.setDisplayed(true);
9031                 mm.center(this);
9032                 mm.setStyle('z-index', z + 102);
9033             }
9034             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9035                 this._mask.setHeight(this.getHeight());
9036             }
9037             this._mask.setStyle('z-index', z + 100);
9038             
9039             return this._mask;
9040         },
9041
9042         /**
9043          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9044          * it is cached for reuse.
9045          */
9046         unmask : function(removeEl){
9047             if(this._mask){
9048                 if(removeEl === true){
9049                     this._mask.remove();
9050                     delete this._mask;
9051                     if(this._maskMsg){
9052                         this._maskMsg.remove();
9053                         delete this._maskMsg;
9054                     }
9055                 }else{
9056                     this._mask.setDisplayed(false);
9057                     if(this._maskMsg){
9058                         this._maskMsg.setDisplayed(false);
9059                     }
9060                 }
9061             }
9062             this.removeClass("x-masked");
9063         },
9064
9065         /**
9066          * Returns true if this element is masked
9067          * @return {Boolean}
9068          */
9069         isMasked : function(){
9070             return this._mask && this._mask.isVisible();
9071         },
9072
9073         /**
9074          * Creates an iframe shim for this element to keep selects and other windowed objects from
9075          * showing through.
9076          * @return {Roo.Element} The new shim element
9077          */
9078         createShim : function(){
9079             var el = document.createElement('iframe');
9080             el.frameBorder = 'no';
9081             el.className = 'roo-shim';
9082             if(Roo.isIE && Roo.isSecure){
9083                 el.src = Roo.SSL_SECURE_URL;
9084             }
9085             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9086             shim.autoBoxAdjust = false;
9087             return shim;
9088         },
9089
9090         /**
9091          * Removes this element from the DOM and deletes it from the cache
9092          */
9093         remove : function(){
9094             if(this.dom.parentNode){
9095                 this.dom.parentNode.removeChild(this.dom);
9096             }
9097             delete El.cache[this.dom.id];
9098         },
9099
9100         /**
9101          * Sets up event handlers to add and remove a css class when the mouse is over this element
9102          * @param {String} className
9103          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9104          * mouseout events for children elements
9105          * @return {Roo.Element} this
9106          */
9107         addClassOnOver : function(className, preventFlicker){
9108             this.on("mouseover", function(){
9109                 Roo.fly(this, '_internal').addClass(className);
9110             }, this.dom);
9111             var removeFn = function(e){
9112                 if(preventFlicker !== true || !e.within(this, true)){
9113                     Roo.fly(this, '_internal').removeClass(className);
9114                 }
9115             };
9116             this.on("mouseout", removeFn, this.dom);
9117             return this;
9118         },
9119
9120         /**
9121          * Sets up event handlers to add and remove a css class when this element has the focus
9122          * @param {String} className
9123          * @return {Roo.Element} this
9124          */
9125         addClassOnFocus : function(className){
9126             this.on("focus", function(){
9127                 Roo.fly(this, '_internal').addClass(className);
9128             }, this.dom);
9129             this.on("blur", function(){
9130                 Roo.fly(this, '_internal').removeClass(className);
9131             }, this.dom);
9132             return this;
9133         },
9134         /**
9135          * 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)
9136          * @param {String} className
9137          * @return {Roo.Element} this
9138          */
9139         addClassOnClick : function(className){
9140             var dom = this.dom;
9141             this.on("mousedown", function(){
9142                 Roo.fly(dom, '_internal').addClass(className);
9143                 var d = Roo.get(document);
9144                 var fn = function(){
9145                     Roo.fly(dom, '_internal').removeClass(className);
9146                     d.removeListener("mouseup", fn);
9147                 };
9148                 d.on("mouseup", fn);
9149             });
9150             return this;
9151         },
9152
9153         /**
9154          * Stops the specified event from bubbling and optionally prevents the default action
9155          * @param {String} eventName
9156          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9157          * @return {Roo.Element} this
9158          */
9159         swallowEvent : function(eventName, preventDefault){
9160             var fn = function(e){
9161                 e.stopPropagation();
9162                 if(preventDefault){
9163                     e.preventDefault();
9164                 }
9165             };
9166             if(eventName instanceof Array){
9167                 for(var i = 0, len = eventName.length; i < len; i++){
9168                      this.on(eventName[i], fn);
9169                 }
9170                 return this;
9171             }
9172             this.on(eventName, fn);
9173             return this;
9174         },
9175
9176         /**
9177          * @private
9178          */
9179       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9180
9181         /**
9182          * Sizes this element to its parent element's dimensions performing
9183          * neccessary box adjustments.
9184          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9185          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9186          * @return {Roo.Element} this
9187          */
9188         fitToParent : function(monitorResize, targetParent) {
9189           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9190           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9191           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9192             return;
9193           }
9194           var p = Roo.get(targetParent || this.dom.parentNode);
9195           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9196           if (monitorResize === true) {
9197             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9198             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9199           }
9200           return this;
9201         },
9202
9203         /**
9204          * Gets the next sibling, skipping text nodes
9205          * @return {HTMLElement} The next sibling or null
9206          */
9207         getNextSibling : function(){
9208             var n = this.dom.nextSibling;
9209             while(n && n.nodeType != 1){
9210                 n = n.nextSibling;
9211             }
9212             return n;
9213         },
9214
9215         /**
9216          * Gets the previous sibling, skipping text nodes
9217          * @return {HTMLElement} The previous sibling or null
9218          */
9219         getPrevSibling : function(){
9220             var n = this.dom.previousSibling;
9221             while(n && n.nodeType != 1){
9222                 n = n.previousSibling;
9223             }
9224             return n;
9225         },
9226
9227
9228         /**
9229          * Appends the passed element(s) to this element
9230          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9231          * @return {Roo.Element} this
9232          */
9233         appendChild: function(el){
9234             el = Roo.get(el);
9235             el.appendTo(this);
9236             return this;
9237         },
9238
9239         /**
9240          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9241          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9242          * automatically generated with the specified attributes.
9243          * @param {HTMLElement} insertBefore (optional) a child element of this element
9244          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9245          * @return {Roo.Element} The new child element
9246          */
9247         createChild: function(config, insertBefore, returnDom){
9248             config = config || {tag:'div'};
9249             if(insertBefore){
9250                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9251             }
9252             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9253         },
9254
9255         /**
9256          * Appends this element to the passed element
9257          * @param {String/HTMLElement/Element} el The new parent element
9258          * @return {Roo.Element} this
9259          */
9260         appendTo: function(el){
9261             el = Roo.getDom(el);
9262             el.appendChild(this.dom);
9263             return this;
9264         },
9265
9266         /**
9267          * Inserts this element before the passed element in the DOM
9268          * @param {String/HTMLElement/Element} el The element to insert before
9269          * @return {Roo.Element} this
9270          */
9271         insertBefore: function(el){
9272             el = Roo.getDom(el);
9273             el.parentNode.insertBefore(this.dom, el);
9274             return this;
9275         },
9276
9277         /**
9278          * Inserts this element after the passed element in the DOM
9279          * @param {String/HTMLElement/Element} el The element to insert after
9280          * @return {Roo.Element} this
9281          */
9282         insertAfter: function(el){
9283             el = Roo.getDom(el);
9284             el.parentNode.insertBefore(this.dom, el.nextSibling);
9285             return this;
9286         },
9287
9288         /**
9289          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9290          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9291          * @return {Roo.Element} The new child
9292          */
9293         insertFirst: function(el, returnDom){
9294             el = el || {};
9295             if(typeof el == 'object' && !el.nodeType){ // dh config
9296                 return this.createChild(el, this.dom.firstChild, returnDom);
9297             }else{
9298                 el = Roo.getDom(el);
9299                 this.dom.insertBefore(el, this.dom.firstChild);
9300                 return !returnDom ? Roo.get(el) : el;
9301             }
9302         },
9303
9304         /**
9305          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9306          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9307          * @param {String} where (optional) 'before' or 'after' defaults to before
9308          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9309          * @return {Roo.Element} the inserted Element
9310          */
9311         insertSibling: function(el, where, returnDom){
9312             where = where ? where.toLowerCase() : 'before';
9313             el = el || {};
9314             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9315
9316             if(typeof el == 'object' && !el.nodeType){ // dh config
9317                 if(where == 'after' && !this.dom.nextSibling){
9318                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9319                 }else{
9320                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9321                 }
9322
9323             }else{
9324                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9325                             where == 'before' ? this.dom : this.dom.nextSibling);
9326                 if(!returnDom){
9327                     rt = Roo.get(rt);
9328                 }
9329             }
9330             return rt;
9331         },
9332
9333         /**
9334          * Creates and wraps this element with another element
9335          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9336          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9337          * @return {HTMLElement/Element} The newly created wrapper element
9338          */
9339         wrap: function(config, returnDom){
9340             if(!config){
9341                 config = {tag: "div"};
9342             }
9343             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9344             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9345             return newEl;
9346         },
9347
9348         /**
9349          * Replaces the passed element with this element
9350          * @param {String/HTMLElement/Element} el The element to replace
9351          * @return {Roo.Element} this
9352          */
9353         replace: function(el){
9354             el = Roo.get(el);
9355             this.insertBefore(el);
9356             el.remove();
9357             return this;
9358         },
9359
9360         /**
9361          * Inserts an html fragment into this element
9362          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9363          * @param {String} html The HTML fragment
9364          * @param {Boolean} returnEl True to return an Roo.Element
9365          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9366          */
9367         insertHtml : function(where, html, returnEl){
9368             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9369             return returnEl ? Roo.get(el) : el;
9370         },
9371
9372         /**
9373          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9374          * @param {Object} o The object with the attributes
9375          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9376          * @return {Roo.Element} this
9377          */
9378         set : function(o, useSet){
9379             var el = this.dom;
9380             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9381             for(var attr in o){
9382                 if(attr == "style" || typeof o[attr] == "function") continue;
9383                 if(attr=="cls"){
9384                     el.className = o["cls"];
9385                 }else{
9386                     if(useSet) el.setAttribute(attr, o[attr]);
9387                     else el[attr] = o[attr];
9388                 }
9389             }
9390             if(o.style){
9391                 Roo.DomHelper.applyStyles(el, o.style);
9392             }
9393             return this;
9394         },
9395
9396         /**
9397          * Convenience method for constructing a KeyMap
9398          * @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:
9399          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9400          * @param {Function} fn The function to call
9401          * @param {Object} scope (optional) The scope of the function
9402          * @return {Roo.KeyMap} The KeyMap created
9403          */
9404         addKeyListener : function(key, fn, scope){
9405             var config;
9406             if(typeof key != "object" || key instanceof Array){
9407                 config = {
9408                     key: key,
9409                     fn: fn,
9410                     scope: scope
9411                 };
9412             }else{
9413                 config = {
9414                     key : key.key,
9415                     shift : key.shift,
9416                     ctrl : key.ctrl,
9417                     alt : key.alt,
9418                     fn: fn,
9419                     scope: scope
9420                 };
9421             }
9422             return new Roo.KeyMap(this, config);
9423         },
9424
9425         /**
9426          * Creates a KeyMap for this element
9427          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9428          * @return {Roo.KeyMap} The KeyMap created
9429          */
9430         addKeyMap : function(config){
9431             return new Roo.KeyMap(this, config);
9432         },
9433
9434         /**
9435          * Returns true if this element is scrollable.
9436          * @return {Boolean}
9437          */
9438          isScrollable : function(){
9439             var dom = this.dom;
9440             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9441         },
9442
9443         /**
9444          * 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().
9445          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9446          * @param {Number} value The new scroll value
9447          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9448          * @return {Element} this
9449          */
9450
9451         scrollTo : function(side, value, animate){
9452             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9453             if(!animate || !A){
9454                 this.dom[prop] = value;
9455             }else{
9456                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9457                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9458             }
9459             return this;
9460         },
9461
9462         /**
9463          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9464          * within this element's scrollable range.
9465          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9466          * @param {Number} distance How far to scroll the element in pixels
9467          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9468          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9469          * was scrolled as far as it could go.
9470          */
9471          scroll : function(direction, distance, animate){
9472              if(!this.isScrollable()){
9473                  return;
9474              }
9475              var el = this.dom;
9476              var l = el.scrollLeft, t = el.scrollTop;
9477              var w = el.scrollWidth, h = el.scrollHeight;
9478              var cw = el.clientWidth, ch = el.clientHeight;
9479              direction = direction.toLowerCase();
9480              var scrolled = false;
9481              var a = this.preanim(arguments, 2);
9482              switch(direction){
9483                  case "l":
9484                  case "left":
9485                      if(w - l > cw){
9486                          var v = Math.min(l + distance, w-cw);
9487                          this.scrollTo("left", v, a);
9488                          scrolled = true;
9489                      }
9490                      break;
9491                 case "r":
9492                 case "right":
9493                      if(l > 0){
9494                          var v = Math.max(l - distance, 0);
9495                          this.scrollTo("left", v, a);
9496                          scrolled = true;
9497                      }
9498                      break;
9499                 case "t":
9500                 case "top":
9501                 case "up":
9502                      if(t > 0){
9503                          var v = Math.max(t - distance, 0);
9504                          this.scrollTo("top", v, a);
9505                          scrolled = true;
9506                      }
9507                      break;
9508                 case "b":
9509                 case "bottom":
9510                 case "down":
9511                      if(h - t > ch){
9512                          var v = Math.min(t + distance, h-ch);
9513                          this.scrollTo("top", v, a);
9514                          scrolled = true;
9515                      }
9516                      break;
9517              }
9518              return scrolled;
9519         },
9520
9521         /**
9522          * Translates the passed page coordinates into left/top css values for this element
9523          * @param {Number/Array} x The page x or an array containing [x, y]
9524          * @param {Number} y The page y
9525          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9526          */
9527         translatePoints : function(x, y){
9528             if(typeof x == 'object' || x instanceof Array){
9529                 y = x[1]; x = x[0];
9530             }
9531             var p = this.getStyle('position');
9532             var o = this.getXY();
9533
9534             var l = parseInt(this.getStyle('left'), 10);
9535             var t = parseInt(this.getStyle('top'), 10);
9536
9537             if(isNaN(l)){
9538                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9539             }
9540             if(isNaN(t)){
9541                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9542             }
9543
9544             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9545         },
9546
9547         /**
9548          * Returns the current scroll position of the element.
9549          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9550          */
9551         getScroll : function(){
9552             var d = this.dom, doc = document;
9553             if(d == doc || d == doc.body){
9554                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9555                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9556                 return {left: l, top: t};
9557             }else{
9558                 return {left: d.scrollLeft, top: d.scrollTop};
9559             }
9560         },
9561
9562         /**
9563          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9564          * are convert to standard 6 digit hex color.
9565          * @param {String} attr The css attribute
9566          * @param {String} defaultValue The default value to use when a valid color isn't found
9567          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9568          * YUI color anims.
9569          */
9570         getColor : function(attr, defaultValue, prefix){
9571             var v = this.getStyle(attr);
9572             if(!v || v == "transparent" || v == "inherit") {
9573                 return defaultValue;
9574             }
9575             var color = typeof prefix == "undefined" ? "#" : prefix;
9576             if(v.substr(0, 4) == "rgb("){
9577                 var rvs = v.slice(4, v.length -1).split(",");
9578                 for(var i = 0; i < 3; i++){
9579                     var h = parseInt(rvs[i]).toString(16);
9580                     if(h < 16){
9581                         h = "0" + h;
9582                     }
9583                     color += h;
9584                 }
9585             } else {
9586                 if(v.substr(0, 1) == "#"){
9587                     if(v.length == 4) {
9588                         for(var i = 1; i < 4; i++){
9589                             var c = v.charAt(i);
9590                             color +=  c + c;
9591                         }
9592                     }else if(v.length == 7){
9593                         color += v.substr(1);
9594                     }
9595                 }
9596             }
9597             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9598         },
9599
9600         /**
9601          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9602          * gradient background, rounded corners and a 4-way shadow.
9603          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9604          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9605          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9606          * @return {Roo.Element} this
9607          */
9608         boxWrap : function(cls){
9609             cls = cls || 'x-box';
9610             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9611             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9612             return el;
9613         },
9614
9615         /**
9616          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9617          * @param {String} namespace The namespace in which to look for the attribute
9618          * @param {String} name The attribute name
9619          * @return {String} The attribute value
9620          */
9621         getAttributeNS : Roo.isIE ? function(ns, name){
9622             var d = this.dom;
9623             var type = typeof d[ns+":"+name];
9624             if(type != 'undefined' && type != 'unknown'){
9625                 return d[ns+":"+name];
9626             }
9627             return d[name];
9628         } : function(ns, name){
9629             var d = this.dom;
9630             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9631         },
9632         
9633         
9634         /**
9635          * Sets or Returns the value the dom attribute value
9636          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9637          * @param {String} value (optional) The value to set the attribute to
9638          * @return {String} The attribute value
9639          */
9640         attr : function(name){
9641             if (arguments.length > 1) {
9642                 this.dom.setAttribute(name, arguments[1]);
9643                 return arguments[1];
9644             }
9645             if (typeof(name) == 'object') {
9646                 for(var i in name) {
9647                     this.attr(i, name[i]);
9648                 }
9649                 return name;
9650             }
9651             
9652             
9653             if (!this.dom.hasAttribute(name)) {
9654                 return undefined;
9655             }
9656             return this.dom.getAttribute(name);
9657         }
9658         
9659         
9660         
9661     };
9662
9663     var ep = El.prototype;
9664
9665     /**
9666      * Appends an event handler (Shorthand for addListener)
9667      * @param {String}   eventName     The type of event to append
9668      * @param {Function} fn        The method the event invokes
9669      * @param {Object} scope       (optional) The scope (this object) of the fn
9670      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9671      * @method
9672      */
9673     ep.on = ep.addListener;
9674         // backwards compat
9675     ep.mon = ep.addListener;
9676
9677     /**
9678      * Removes an event handler from this element (shorthand for removeListener)
9679      * @param {String} eventName the type of event to remove
9680      * @param {Function} fn the method the event invokes
9681      * @return {Roo.Element} this
9682      * @method
9683      */
9684     ep.un = ep.removeListener;
9685
9686     /**
9687      * true to automatically adjust width and height settings for box-model issues (default to true)
9688      */
9689     ep.autoBoxAdjust = true;
9690
9691     // private
9692     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9693
9694     // private
9695     El.addUnits = function(v, defaultUnit){
9696         if(v === "" || v == "auto"){
9697             return v;
9698         }
9699         if(v === undefined){
9700             return '';
9701         }
9702         if(typeof v == "number" || !El.unitPattern.test(v)){
9703             return v + (defaultUnit || 'px');
9704         }
9705         return v;
9706     };
9707
9708     // special markup used throughout Roo when box wrapping elements
9709     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>';
9710     /**
9711      * Visibility mode constant - Use visibility to hide element
9712      * @static
9713      * @type Number
9714      */
9715     El.VISIBILITY = 1;
9716     /**
9717      * Visibility mode constant - Use display to hide element
9718      * @static
9719      * @type Number
9720      */
9721     El.DISPLAY = 2;
9722
9723     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9724     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9725     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9726
9727
9728
9729     /**
9730      * @private
9731      */
9732     El.cache = {};
9733
9734     var docEl;
9735
9736     /**
9737      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9738      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9739      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9740      * @return {Element} The Element object
9741      * @static
9742      */
9743     El.get = function(el){
9744         var ex, elm, id;
9745         if(!el){ return null; }
9746         if(typeof el == "string"){ // element id
9747             if(!(elm = document.getElementById(el))){
9748                 return null;
9749             }
9750             if(ex = El.cache[el]){
9751                 ex.dom = elm;
9752             }else{
9753                 ex = El.cache[el] = new El(elm);
9754             }
9755             return ex;
9756         }else if(el.tagName){ // dom element
9757             if(!(id = el.id)){
9758                 id = Roo.id(el);
9759             }
9760             if(ex = El.cache[id]){
9761                 ex.dom = el;
9762             }else{
9763                 ex = El.cache[id] = new El(el);
9764             }
9765             return ex;
9766         }else if(el instanceof El){
9767             if(el != docEl){
9768                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9769                                                               // catch case where it hasn't been appended
9770                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9771             }
9772             return el;
9773         }else if(el.isComposite){
9774             return el;
9775         }else if(el instanceof Array){
9776             return El.select(el);
9777         }else if(el == document){
9778             // create a bogus element object representing the document object
9779             if(!docEl){
9780                 var f = function(){};
9781                 f.prototype = El.prototype;
9782                 docEl = new f();
9783                 docEl.dom = document;
9784             }
9785             return docEl;
9786         }
9787         return null;
9788     };
9789
9790     // private
9791     El.uncache = function(el){
9792         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9793             if(a[i]){
9794                 delete El.cache[a[i].id || a[i]];
9795             }
9796         }
9797     };
9798
9799     // private
9800     // Garbage collection - uncache elements/purge listeners on orphaned elements
9801     // so we don't hold a reference and cause the browser to retain them
9802     El.garbageCollect = function(){
9803         if(!Roo.enableGarbageCollector){
9804             clearInterval(El.collectorThread);
9805             return;
9806         }
9807         for(var eid in El.cache){
9808             var el = El.cache[eid], d = el.dom;
9809             // -------------------------------------------------------
9810             // Determining what is garbage:
9811             // -------------------------------------------------------
9812             // !d
9813             // dom node is null, definitely garbage
9814             // -------------------------------------------------------
9815             // !d.parentNode
9816             // no parentNode == direct orphan, definitely garbage
9817             // -------------------------------------------------------
9818             // !d.offsetParent && !document.getElementById(eid)
9819             // display none elements have no offsetParent so we will
9820             // also try to look it up by it's id. However, check
9821             // offsetParent first so we don't do unneeded lookups.
9822             // This enables collection of elements that are not orphans
9823             // directly, but somewhere up the line they have an orphan
9824             // parent.
9825             // -------------------------------------------------------
9826             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9827                 delete El.cache[eid];
9828                 if(d && Roo.enableListenerCollection){
9829                     E.purgeElement(d);
9830                 }
9831             }
9832         }
9833     }
9834     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9835
9836
9837     // dom is optional
9838     El.Flyweight = function(dom){
9839         this.dom = dom;
9840     };
9841     El.Flyweight.prototype = El.prototype;
9842
9843     El._flyweights = {};
9844     /**
9845      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9846      * the dom node can be overwritten by other code.
9847      * @param {String/HTMLElement} el The dom node or id
9848      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9849      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9850      * @static
9851      * @return {Element} The shared Element object
9852      */
9853     El.fly = function(el, named){
9854         named = named || '_global';
9855         el = Roo.getDom(el);
9856         if(!el){
9857             return null;
9858         }
9859         if(!El._flyweights[named]){
9860             El._flyweights[named] = new El.Flyweight();
9861         }
9862         El._flyweights[named].dom = el;
9863         return El._flyweights[named];
9864     };
9865
9866     /**
9867      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9868      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9869      * Shorthand of {@link Roo.Element#get}
9870      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9871      * @return {Element} The Element object
9872      * @member Roo
9873      * @method get
9874      */
9875     Roo.get = El.get;
9876     /**
9877      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9878      * the dom node can be overwritten by other code.
9879      * Shorthand of {@link Roo.Element#fly}
9880      * @param {String/HTMLElement} el The dom node or id
9881      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9882      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9883      * @static
9884      * @return {Element} The shared Element object
9885      * @member Roo
9886      * @method fly
9887      */
9888     Roo.fly = El.fly;
9889
9890     // speedy lookup for elements never to box adjust
9891     var noBoxAdjust = Roo.isStrict ? {
9892         select:1
9893     } : {
9894         input:1, select:1, textarea:1
9895     };
9896     if(Roo.isIE || Roo.isGecko){
9897         noBoxAdjust['button'] = 1;
9898     }
9899
9900
9901     Roo.EventManager.on(window, 'unload', function(){
9902         delete El.cache;
9903         delete El._flyweights;
9904     });
9905 })();
9906
9907
9908
9909
9910 if(Roo.DomQuery){
9911     Roo.Element.selectorFunction = Roo.DomQuery.select;
9912 }
9913
9914 Roo.Element.select = function(selector, unique, root){
9915     var els;
9916     if(typeof selector == "string"){
9917         els = Roo.Element.selectorFunction(selector, root);
9918     }else if(selector.length !== undefined){
9919         els = selector;
9920     }else{
9921         throw "Invalid selector";
9922     }
9923     if(unique === true){
9924         return new Roo.CompositeElement(els);
9925     }else{
9926         return new Roo.CompositeElementLite(els);
9927     }
9928 };
9929 /**
9930  * Selects elements based on the passed CSS selector to enable working on them as 1.
9931  * @param {String/Array} selector The CSS selector or an array of elements
9932  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9933  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9934  * @return {CompositeElementLite/CompositeElement}
9935  * @member Roo
9936  * @method select
9937  */
9938 Roo.select = Roo.Element.select;
9939
9940
9941
9942
9943
9944
9945
9946
9947
9948
9949
9950
9951
9952
9953 /*
9954  * Based on:
9955  * Ext JS Library 1.1.1
9956  * Copyright(c) 2006-2007, Ext JS, LLC.
9957  *
9958  * Originally Released Under LGPL - original licence link has changed is not relivant.
9959  *
9960  * Fork - LGPL
9961  * <script type="text/javascript">
9962  */
9963
9964
9965
9966 //Notifies Element that fx methods are available
9967 Roo.enableFx = true;
9968
9969 /**
9970  * @class Roo.Fx
9971  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9972  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9973  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9974  * Element effects to work.</p><br/>
9975  *
9976  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9977  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9978  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9979  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9980  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9981  * expected results and should be done with care.</p><br/>
9982  *
9983  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9984  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9985 <pre>
9986 Value  Description
9987 -----  -----------------------------
9988 tl     The top left corner
9989 t      The center of the top edge
9990 tr     The top right corner
9991 l      The center of the left edge
9992 r      The center of the right edge
9993 bl     The bottom left corner
9994 b      The center of the bottom edge
9995 br     The bottom right corner
9996 </pre>
9997  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
9998  * below are common options that can be passed to any Fx method.</b>
9999  * @cfg {Function} callback A function called when the effect is finished
10000  * @cfg {Object} scope The scope of the effect function
10001  * @cfg {String} easing A valid Easing value for the effect
10002  * @cfg {String} afterCls A css class to apply after the effect
10003  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10004  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10005  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10006  * effects that end with the element being visually hidden, ignored otherwise)
10007  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10008  * a function which returns such a specification that will be applied to the Element after the effect finishes
10009  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10010  * @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
10011  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10012  */
10013 Roo.Fx = {
10014         /**
10015          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10016          * origin for the slide effect.  This function automatically handles wrapping the element with
10017          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10018          * Usage:
10019          *<pre><code>
10020 // default: slide the element in from the top
10021 el.slideIn();
10022
10023 // custom: slide the element in from the right with a 2-second duration
10024 el.slideIn('r', { duration: 2 });
10025
10026 // common config options shown with default values
10027 el.slideIn('t', {
10028     easing: 'easeOut',
10029     duration: .5
10030 });
10031 </code></pre>
10032          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10033          * @param {Object} options (optional) Object literal with any of the Fx config options
10034          * @return {Roo.Element} The Element
10035          */
10036     slideIn : function(anchor, o){
10037         var el = this.getFxEl();
10038         o = o || {};
10039
10040         el.queueFx(o, function(){
10041
10042             anchor = anchor || "t";
10043
10044             // fix display to visibility
10045             this.fixDisplay();
10046
10047             // restore values after effect
10048             var r = this.getFxRestore();
10049             var b = this.getBox();
10050             // fixed size for slide
10051             this.setSize(b);
10052
10053             // wrap if needed
10054             var wrap = this.fxWrap(r.pos, o, "hidden");
10055
10056             var st = this.dom.style;
10057             st.visibility = "visible";
10058             st.position = "absolute";
10059
10060             // clear out temp styles after slide and unwrap
10061             var after = function(){
10062                 el.fxUnwrap(wrap, r.pos, o);
10063                 st.width = r.width;
10064                 st.height = r.height;
10065                 el.afterFx(o);
10066             };
10067             // time to calc the positions
10068             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10069
10070             switch(anchor.toLowerCase()){
10071                 case "t":
10072                     wrap.setSize(b.width, 0);
10073                     st.left = st.bottom = "0";
10074                     a = {height: bh};
10075                 break;
10076                 case "l":
10077                     wrap.setSize(0, b.height);
10078                     st.right = st.top = "0";
10079                     a = {width: bw};
10080                 break;
10081                 case "r":
10082                     wrap.setSize(0, b.height);
10083                     wrap.setX(b.right);
10084                     st.left = st.top = "0";
10085                     a = {width: bw, points: pt};
10086                 break;
10087                 case "b":
10088                     wrap.setSize(b.width, 0);
10089                     wrap.setY(b.bottom);
10090                     st.left = st.top = "0";
10091                     a = {height: bh, points: pt};
10092                 break;
10093                 case "tl":
10094                     wrap.setSize(0, 0);
10095                     st.right = st.bottom = "0";
10096                     a = {width: bw, height: bh};
10097                 break;
10098                 case "bl":
10099                     wrap.setSize(0, 0);
10100                     wrap.setY(b.y+b.height);
10101                     st.right = st.top = "0";
10102                     a = {width: bw, height: bh, points: pt};
10103                 break;
10104                 case "br":
10105                     wrap.setSize(0, 0);
10106                     wrap.setXY([b.right, b.bottom]);
10107                     st.left = st.top = "0";
10108                     a = {width: bw, height: bh, points: pt};
10109                 break;
10110                 case "tr":
10111                     wrap.setSize(0, 0);
10112                     wrap.setX(b.x+b.width);
10113                     st.left = st.bottom = "0";
10114                     a = {width: bw, height: bh, points: pt};
10115                 break;
10116             }
10117             this.dom.style.visibility = "visible";
10118             wrap.show();
10119
10120             arguments.callee.anim = wrap.fxanim(a,
10121                 o,
10122                 'motion',
10123                 .5,
10124                 'easeOut', after);
10125         });
10126         return this;
10127     },
10128     
10129         /**
10130          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10131          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10132          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10133          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10134          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10135          * Usage:
10136          *<pre><code>
10137 // default: slide the element out to the top
10138 el.slideOut();
10139
10140 // custom: slide the element out to the right with a 2-second duration
10141 el.slideOut('r', { duration: 2 });
10142
10143 // common config options shown with default values
10144 el.slideOut('t', {
10145     easing: 'easeOut',
10146     duration: .5,
10147     remove: false,
10148     useDisplay: false
10149 });
10150 </code></pre>
10151          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10152          * @param {Object} options (optional) Object literal with any of the Fx config options
10153          * @return {Roo.Element} The Element
10154          */
10155     slideOut : function(anchor, o){
10156         var el = this.getFxEl();
10157         o = o || {};
10158
10159         el.queueFx(o, function(){
10160
10161             anchor = anchor || "t";
10162
10163             // restore values after effect
10164             var r = this.getFxRestore();
10165             
10166             var b = this.getBox();
10167             // fixed size for slide
10168             this.setSize(b);
10169
10170             // wrap if needed
10171             var wrap = this.fxWrap(r.pos, o, "visible");
10172
10173             var st = this.dom.style;
10174             st.visibility = "visible";
10175             st.position = "absolute";
10176
10177             wrap.setSize(b);
10178
10179             var after = function(){
10180                 if(o.useDisplay){
10181                     el.setDisplayed(false);
10182                 }else{
10183                     el.hide();
10184                 }
10185
10186                 el.fxUnwrap(wrap, r.pos, o);
10187
10188                 st.width = r.width;
10189                 st.height = r.height;
10190
10191                 el.afterFx(o);
10192             };
10193
10194             var a, zero = {to: 0};
10195             switch(anchor.toLowerCase()){
10196                 case "t":
10197                     st.left = st.bottom = "0";
10198                     a = {height: zero};
10199                 break;
10200                 case "l":
10201                     st.right = st.top = "0";
10202                     a = {width: zero};
10203                 break;
10204                 case "r":
10205                     st.left = st.top = "0";
10206                     a = {width: zero, points: {to:[b.right, b.y]}};
10207                 break;
10208                 case "b":
10209                     st.left = st.top = "0";
10210                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10211                 break;
10212                 case "tl":
10213                     st.right = st.bottom = "0";
10214                     a = {width: zero, height: zero};
10215                 break;
10216                 case "bl":
10217                     st.right = st.top = "0";
10218                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10219                 break;
10220                 case "br":
10221                     st.left = st.top = "0";
10222                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10223                 break;
10224                 case "tr":
10225                     st.left = st.bottom = "0";
10226                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10227                 break;
10228             }
10229
10230             arguments.callee.anim = wrap.fxanim(a,
10231                 o,
10232                 'motion',
10233                 .5,
10234                 "easeOut", after);
10235         });
10236         return this;
10237     },
10238
10239         /**
10240          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10241          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10242          * The element must be removed from the DOM using the 'remove' config option if desired.
10243          * Usage:
10244          *<pre><code>
10245 // default
10246 el.puff();
10247
10248 // common config options shown with default values
10249 el.puff({
10250     easing: 'easeOut',
10251     duration: .5,
10252     remove: false,
10253     useDisplay: false
10254 });
10255 </code></pre>
10256          * @param {Object} options (optional) Object literal with any of the Fx config options
10257          * @return {Roo.Element} The Element
10258          */
10259     puff : function(o){
10260         var el = this.getFxEl();
10261         o = o || {};
10262
10263         el.queueFx(o, function(){
10264             this.clearOpacity();
10265             this.show();
10266
10267             // restore values after effect
10268             var r = this.getFxRestore();
10269             var st = this.dom.style;
10270
10271             var after = function(){
10272                 if(o.useDisplay){
10273                     el.setDisplayed(false);
10274                 }else{
10275                     el.hide();
10276                 }
10277
10278                 el.clearOpacity();
10279
10280                 el.setPositioning(r.pos);
10281                 st.width = r.width;
10282                 st.height = r.height;
10283                 st.fontSize = '';
10284                 el.afterFx(o);
10285             };
10286
10287             var width = this.getWidth();
10288             var height = this.getHeight();
10289
10290             arguments.callee.anim = this.fxanim({
10291                     width : {to: this.adjustWidth(width * 2)},
10292                     height : {to: this.adjustHeight(height * 2)},
10293                     points : {by: [-(width * .5), -(height * .5)]},
10294                     opacity : {to: 0},
10295                     fontSize: {to:200, unit: "%"}
10296                 },
10297                 o,
10298                 'motion',
10299                 .5,
10300                 "easeOut", after);
10301         });
10302         return this;
10303     },
10304
10305         /**
10306          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10307          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10308          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10309          * Usage:
10310          *<pre><code>
10311 // default
10312 el.switchOff();
10313
10314 // all config options shown with default values
10315 el.switchOff({
10316     easing: 'easeIn',
10317     duration: .3,
10318     remove: false,
10319     useDisplay: false
10320 });
10321 </code></pre>
10322          * @param {Object} options (optional) Object literal with any of the Fx config options
10323          * @return {Roo.Element} The Element
10324          */
10325     switchOff : function(o){
10326         var el = this.getFxEl();
10327         o = o || {};
10328
10329         el.queueFx(o, function(){
10330             this.clearOpacity();
10331             this.clip();
10332
10333             // restore values after effect
10334             var r = this.getFxRestore();
10335             var st = this.dom.style;
10336
10337             var after = function(){
10338                 if(o.useDisplay){
10339                     el.setDisplayed(false);
10340                 }else{
10341                     el.hide();
10342                 }
10343
10344                 el.clearOpacity();
10345                 el.setPositioning(r.pos);
10346                 st.width = r.width;
10347                 st.height = r.height;
10348
10349                 el.afterFx(o);
10350             };
10351
10352             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10353                 this.clearOpacity();
10354                 (function(){
10355                     this.fxanim({
10356                         height:{to:1},
10357                         points:{by:[0, this.getHeight() * .5]}
10358                     }, o, 'motion', 0.3, 'easeIn', after);
10359                 }).defer(100, this);
10360             });
10361         });
10362         return this;
10363     },
10364
10365     /**
10366      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10367      * changed using the "attr" config option) and then fading back to the original color. If no original
10368      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10369      * Usage:
10370 <pre><code>
10371 // default: highlight background to yellow
10372 el.highlight();
10373
10374 // custom: highlight foreground text to blue for 2 seconds
10375 el.highlight("0000ff", { attr: 'color', duration: 2 });
10376
10377 // common config options shown with default values
10378 el.highlight("ffff9c", {
10379     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10380     endColor: (current color) or "ffffff",
10381     easing: 'easeIn',
10382     duration: 1
10383 });
10384 </code></pre>
10385      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10386      * @param {Object} options (optional) Object literal with any of the Fx config options
10387      * @return {Roo.Element} The Element
10388      */ 
10389     highlight : function(color, o){
10390         var el = this.getFxEl();
10391         o = o || {};
10392
10393         el.queueFx(o, function(){
10394             color = color || "ffff9c";
10395             attr = o.attr || "backgroundColor";
10396
10397             this.clearOpacity();
10398             this.show();
10399
10400             var origColor = this.getColor(attr);
10401             var restoreColor = this.dom.style[attr];
10402             endColor = (o.endColor || origColor) || "ffffff";
10403
10404             var after = function(){
10405                 el.dom.style[attr] = restoreColor;
10406                 el.afterFx(o);
10407             };
10408
10409             var a = {};
10410             a[attr] = {from: color, to: endColor};
10411             arguments.callee.anim = this.fxanim(a,
10412                 o,
10413                 'color',
10414                 1,
10415                 'easeIn', after);
10416         });
10417         return this;
10418     },
10419
10420    /**
10421     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10422     * Usage:
10423 <pre><code>
10424 // default: a single light blue ripple
10425 el.frame();
10426
10427 // custom: 3 red ripples lasting 3 seconds total
10428 el.frame("ff0000", 3, { duration: 3 });
10429
10430 // common config options shown with default values
10431 el.frame("C3DAF9", 1, {
10432     duration: 1 //duration of entire animation (not each individual ripple)
10433     // Note: Easing is not configurable and will be ignored if included
10434 });
10435 </code></pre>
10436     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10437     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10438     * @param {Object} options (optional) Object literal with any of the Fx config options
10439     * @return {Roo.Element} The Element
10440     */
10441     frame : function(color, count, o){
10442         var el = this.getFxEl();
10443         o = o || {};
10444
10445         el.queueFx(o, function(){
10446             color = color || "#C3DAF9";
10447             if(color.length == 6){
10448                 color = "#" + color;
10449             }
10450             count = count || 1;
10451             duration = o.duration || 1;
10452             this.show();
10453
10454             var b = this.getBox();
10455             var animFn = function(){
10456                 var proxy = this.createProxy({
10457
10458                      style:{
10459                         visbility:"hidden",
10460                         position:"absolute",
10461                         "z-index":"35000", // yee haw
10462                         border:"0px solid " + color
10463                      }
10464                   });
10465                 var scale = Roo.isBorderBox ? 2 : 1;
10466                 proxy.animate({
10467                     top:{from:b.y, to:b.y - 20},
10468                     left:{from:b.x, to:b.x - 20},
10469                     borderWidth:{from:0, to:10},
10470                     opacity:{from:1, to:0},
10471                     height:{from:b.height, to:(b.height + (20*scale))},
10472                     width:{from:b.width, to:(b.width + (20*scale))}
10473                 }, duration, function(){
10474                     proxy.remove();
10475                 });
10476                 if(--count > 0){
10477                      animFn.defer((duration/2)*1000, this);
10478                 }else{
10479                     el.afterFx(o);
10480                 }
10481             };
10482             animFn.call(this);
10483         });
10484         return this;
10485     },
10486
10487    /**
10488     * Creates a pause before any subsequent queued effects begin.  If there are
10489     * no effects queued after the pause it will have no effect.
10490     * Usage:
10491 <pre><code>
10492 el.pause(1);
10493 </code></pre>
10494     * @param {Number} seconds The length of time to pause (in seconds)
10495     * @return {Roo.Element} The Element
10496     */
10497     pause : function(seconds){
10498         var el = this.getFxEl();
10499         var o = {};
10500
10501         el.queueFx(o, function(){
10502             setTimeout(function(){
10503                 el.afterFx(o);
10504             }, seconds * 1000);
10505         });
10506         return this;
10507     },
10508
10509    /**
10510     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10511     * using the "endOpacity" config option.
10512     * Usage:
10513 <pre><code>
10514 // default: fade in from opacity 0 to 100%
10515 el.fadeIn();
10516
10517 // custom: fade in from opacity 0 to 75% over 2 seconds
10518 el.fadeIn({ endOpacity: .75, duration: 2});
10519
10520 // common config options shown with default values
10521 el.fadeIn({
10522     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10523     easing: 'easeOut',
10524     duration: .5
10525 });
10526 </code></pre>
10527     * @param {Object} options (optional) Object literal with any of the Fx config options
10528     * @return {Roo.Element} The Element
10529     */
10530     fadeIn : function(o){
10531         var el = this.getFxEl();
10532         o = o || {};
10533         el.queueFx(o, function(){
10534             this.setOpacity(0);
10535             this.fixDisplay();
10536             this.dom.style.visibility = 'visible';
10537             var to = o.endOpacity || 1;
10538             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10539                 o, null, .5, "easeOut", function(){
10540                 if(to == 1){
10541                     this.clearOpacity();
10542                 }
10543                 el.afterFx(o);
10544             });
10545         });
10546         return this;
10547     },
10548
10549    /**
10550     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10551     * using the "endOpacity" config option.
10552     * Usage:
10553 <pre><code>
10554 // default: fade out from the element's current opacity to 0
10555 el.fadeOut();
10556
10557 // custom: fade out from the element's current opacity to 25% over 2 seconds
10558 el.fadeOut({ endOpacity: .25, duration: 2});
10559
10560 // common config options shown with default values
10561 el.fadeOut({
10562     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10563     easing: 'easeOut',
10564     duration: .5
10565     remove: false,
10566     useDisplay: false
10567 });
10568 </code></pre>
10569     * @param {Object} options (optional) Object literal with any of the Fx config options
10570     * @return {Roo.Element} The Element
10571     */
10572     fadeOut : function(o){
10573         var el = this.getFxEl();
10574         o = o || {};
10575         el.queueFx(o, function(){
10576             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10577                 o, null, .5, "easeOut", function(){
10578                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10579                      this.dom.style.display = "none";
10580                 }else{
10581                      this.dom.style.visibility = "hidden";
10582                 }
10583                 this.clearOpacity();
10584                 el.afterFx(o);
10585             });
10586         });
10587         return this;
10588     },
10589
10590    /**
10591     * Animates the transition of an element's dimensions from a starting height/width
10592     * to an ending height/width.
10593     * Usage:
10594 <pre><code>
10595 // change height and width to 100x100 pixels
10596 el.scale(100, 100);
10597
10598 // common config options shown with default values.  The height and width will default to
10599 // the element's existing values if passed as null.
10600 el.scale(
10601     [element's width],
10602     [element's height], {
10603     easing: 'easeOut',
10604     duration: .35
10605 });
10606 </code></pre>
10607     * @param {Number} width  The new width (pass undefined to keep the original width)
10608     * @param {Number} height  The new height (pass undefined to keep the original height)
10609     * @param {Object} options (optional) Object literal with any of the Fx config options
10610     * @return {Roo.Element} The Element
10611     */
10612     scale : function(w, h, o){
10613         this.shift(Roo.apply({}, o, {
10614             width: w,
10615             height: h
10616         }));
10617         return this;
10618     },
10619
10620    /**
10621     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10622     * Any of these properties not specified in the config object will not be changed.  This effect 
10623     * requires that at least one new dimension, position or opacity setting must be passed in on
10624     * the config object in order for the function to have any effect.
10625     * Usage:
10626 <pre><code>
10627 // slide the element horizontally to x position 200 while changing the height and opacity
10628 el.shift({ x: 200, height: 50, opacity: .8 });
10629
10630 // common config options shown with default values.
10631 el.shift({
10632     width: [element's width],
10633     height: [element's height],
10634     x: [element's x position],
10635     y: [element's y position],
10636     opacity: [element's opacity],
10637     easing: 'easeOut',
10638     duration: .35
10639 });
10640 </code></pre>
10641     * @param {Object} options  Object literal with any of the Fx config options
10642     * @return {Roo.Element} The Element
10643     */
10644     shift : function(o){
10645         var el = this.getFxEl();
10646         o = o || {};
10647         el.queueFx(o, function(){
10648             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10649             if(w !== undefined){
10650                 a.width = {to: this.adjustWidth(w)};
10651             }
10652             if(h !== undefined){
10653                 a.height = {to: this.adjustHeight(h)};
10654             }
10655             if(x !== undefined || y !== undefined){
10656                 a.points = {to: [
10657                     x !== undefined ? x : this.getX(),
10658                     y !== undefined ? y : this.getY()
10659                 ]};
10660             }
10661             if(op !== undefined){
10662                 a.opacity = {to: op};
10663             }
10664             if(o.xy !== undefined){
10665                 a.points = {to: o.xy};
10666             }
10667             arguments.callee.anim = this.fxanim(a,
10668                 o, 'motion', .35, "easeOut", function(){
10669                 el.afterFx(o);
10670             });
10671         });
10672         return this;
10673     },
10674
10675         /**
10676          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10677          * ending point of the effect.
10678          * Usage:
10679          *<pre><code>
10680 // default: slide the element downward while fading out
10681 el.ghost();
10682
10683 // custom: slide the element out to the right with a 2-second duration
10684 el.ghost('r', { duration: 2 });
10685
10686 // common config options shown with default values
10687 el.ghost('b', {
10688     easing: 'easeOut',
10689     duration: .5
10690     remove: false,
10691     useDisplay: false
10692 });
10693 </code></pre>
10694          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10695          * @param {Object} options (optional) Object literal with any of the Fx config options
10696          * @return {Roo.Element} The Element
10697          */
10698     ghost : function(anchor, o){
10699         var el = this.getFxEl();
10700         o = o || {};
10701
10702         el.queueFx(o, function(){
10703             anchor = anchor || "b";
10704
10705             // restore values after effect
10706             var r = this.getFxRestore();
10707             var w = this.getWidth(),
10708                 h = this.getHeight();
10709
10710             var st = this.dom.style;
10711
10712             var after = function(){
10713                 if(o.useDisplay){
10714                     el.setDisplayed(false);
10715                 }else{
10716                     el.hide();
10717                 }
10718
10719                 el.clearOpacity();
10720                 el.setPositioning(r.pos);
10721                 st.width = r.width;
10722                 st.height = r.height;
10723
10724                 el.afterFx(o);
10725             };
10726
10727             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10728             switch(anchor.toLowerCase()){
10729                 case "t":
10730                     pt.by = [0, -h];
10731                 break;
10732                 case "l":
10733                     pt.by = [-w, 0];
10734                 break;
10735                 case "r":
10736                     pt.by = [w, 0];
10737                 break;
10738                 case "b":
10739                     pt.by = [0, h];
10740                 break;
10741                 case "tl":
10742                     pt.by = [-w, -h];
10743                 break;
10744                 case "bl":
10745                     pt.by = [-w, h];
10746                 break;
10747                 case "br":
10748                     pt.by = [w, h];
10749                 break;
10750                 case "tr":
10751                     pt.by = [w, -h];
10752                 break;
10753             }
10754
10755             arguments.callee.anim = this.fxanim(a,
10756                 o,
10757                 'motion',
10758                 .5,
10759                 "easeOut", after);
10760         });
10761         return this;
10762     },
10763
10764         /**
10765          * Ensures that all effects queued after syncFx is called on the element are
10766          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10767          * @return {Roo.Element} The Element
10768          */
10769     syncFx : function(){
10770         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10771             block : false,
10772             concurrent : true,
10773             stopFx : false
10774         });
10775         return this;
10776     },
10777
10778         /**
10779          * Ensures that all effects queued after sequenceFx is called on the element are
10780          * run in sequence.  This is the opposite of {@link #syncFx}.
10781          * @return {Roo.Element} The Element
10782          */
10783     sequenceFx : function(){
10784         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10785             block : false,
10786             concurrent : false,
10787             stopFx : false
10788         });
10789         return this;
10790     },
10791
10792         /* @private */
10793     nextFx : function(){
10794         var ef = this.fxQueue[0];
10795         if(ef){
10796             ef.call(this);
10797         }
10798     },
10799
10800         /**
10801          * Returns true if the element has any effects actively running or queued, else returns false.
10802          * @return {Boolean} True if element has active effects, else false
10803          */
10804     hasActiveFx : function(){
10805         return this.fxQueue && this.fxQueue[0];
10806     },
10807
10808         /**
10809          * Stops any running effects and clears the element's internal effects queue if it contains
10810          * any additional effects that haven't started yet.
10811          * @return {Roo.Element} The Element
10812          */
10813     stopFx : function(){
10814         if(this.hasActiveFx()){
10815             var cur = this.fxQueue[0];
10816             if(cur && cur.anim && cur.anim.isAnimated()){
10817                 this.fxQueue = [cur]; // clear out others
10818                 cur.anim.stop(true);
10819             }
10820         }
10821         return this;
10822     },
10823
10824         /* @private */
10825     beforeFx : function(o){
10826         if(this.hasActiveFx() && !o.concurrent){
10827            if(o.stopFx){
10828                this.stopFx();
10829                return true;
10830            }
10831            return false;
10832         }
10833         return true;
10834     },
10835
10836         /**
10837          * Returns true if the element is currently blocking so that no other effect can be queued
10838          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10839          * used to ensure that an effect initiated by a user action runs to completion prior to the
10840          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10841          * @return {Boolean} True if blocking, else false
10842          */
10843     hasFxBlock : function(){
10844         var q = this.fxQueue;
10845         return q && q[0] && q[0].block;
10846     },
10847
10848         /* @private */
10849     queueFx : function(o, fn){
10850         if(!this.fxQueue){
10851             this.fxQueue = [];
10852         }
10853         if(!this.hasFxBlock()){
10854             Roo.applyIf(o, this.fxDefaults);
10855             if(!o.concurrent){
10856                 var run = this.beforeFx(o);
10857                 fn.block = o.block;
10858                 this.fxQueue.push(fn);
10859                 if(run){
10860                     this.nextFx();
10861                 }
10862             }else{
10863                 fn.call(this);
10864             }
10865         }
10866         return this;
10867     },
10868
10869         /* @private */
10870     fxWrap : function(pos, o, vis){
10871         var wrap;
10872         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10873             var wrapXY;
10874             if(o.fixPosition){
10875                 wrapXY = this.getXY();
10876             }
10877             var div = document.createElement("div");
10878             div.style.visibility = vis;
10879             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10880             wrap.setPositioning(pos);
10881             if(wrap.getStyle("position") == "static"){
10882                 wrap.position("relative");
10883             }
10884             this.clearPositioning('auto');
10885             wrap.clip();
10886             wrap.dom.appendChild(this.dom);
10887             if(wrapXY){
10888                 wrap.setXY(wrapXY);
10889             }
10890         }
10891         return wrap;
10892     },
10893
10894         /* @private */
10895     fxUnwrap : function(wrap, pos, o){
10896         this.clearPositioning();
10897         this.setPositioning(pos);
10898         if(!o.wrap){
10899             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10900             wrap.remove();
10901         }
10902     },
10903
10904         /* @private */
10905     getFxRestore : function(){
10906         var st = this.dom.style;
10907         return {pos: this.getPositioning(), width: st.width, height : st.height};
10908     },
10909
10910         /* @private */
10911     afterFx : function(o){
10912         if(o.afterStyle){
10913             this.applyStyles(o.afterStyle);
10914         }
10915         if(o.afterCls){
10916             this.addClass(o.afterCls);
10917         }
10918         if(o.remove === true){
10919             this.remove();
10920         }
10921         Roo.callback(o.callback, o.scope, [this]);
10922         if(!o.concurrent){
10923             this.fxQueue.shift();
10924             this.nextFx();
10925         }
10926     },
10927
10928         /* @private */
10929     getFxEl : function(){ // support for composite element fx
10930         return Roo.get(this.dom);
10931     },
10932
10933         /* @private */
10934     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10935         animType = animType || 'run';
10936         opt = opt || {};
10937         var anim = Roo.lib.Anim[animType](
10938             this.dom, args,
10939             (opt.duration || defaultDur) || .35,
10940             (opt.easing || defaultEase) || 'easeOut',
10941             function(){
10942                 Roo.callback(cb, this);
10943             },
10944             this
10945         );
10946         opt.anim = anim;
10947         return anim;
10948     }
10949 };
10950
10951 // backwords compat
10952 Roo.Fx.resize = Roo.Fx.scale;
10953
10954 //When included, Roo.Fx is automatically applied to Element so that all basic
10955 //effects are available directly via the Element API
10956 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10957  * Based on:
10958  * Ext JS Library 1.1.1
10959  * Copyright(c) 2006-2007, Ext JS, LLC.
10960  *
10961  * Originally Released Under LGPL - original licence link has changed is not relivant.
10962  *
10963  * Fork - LGPL
10964  * <script type="text/javascript">
10965  */
10966
10967
10968 /**
10969  * @class Roo.CompositeElement
10970  * Standard composite class. Creates a Roo.Element for every element in the collection.
10971  * <br><br>
10972  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10973  * actions will be performed on all the elements in this collection.</b>
10974  * <br><br>
10975  * All methods return <i>this</i> and can be chained.
10976  <pre><code>
10977  var els = Roo.select("#some-el div.some-class", true);
10978  // or select directly from an existing element
10979  var el = Roo.get('some-el');
10980  el.select('div.some-class', true);
10981
10982  els.setWidth(100); // all elements become 100 width
10983  els.hide(true); // all elements fade out and hide
10984  // or
10985  els.setWidth(100).hide(true);
10986  </code></pre>
10987  */
10988 Roo.CompositeElement = function(els){
10989     this.elements = [];
10990     this.addElements(els);
10991 };
10992 Roo.CompositeElement.prototype = {
10993     isComposite: true,
10994     addElements : function(els){
10995         if(!els) return this;
10996         if(typeof els == "string"){
10997             els = Roo.Element.selectorFunction(els);
10998         }
10999         var yels = this.elements;
11000         var index = yels.length-1;
11001         for(var i = 0, len = els.length; i < len; i++) {
11002                 yels[++index] = Roo.get(els[i]);
11003         }
11004         return this;
11005     },
11006
11007     /**
11008     * Clears this composite and adds the elements returned by the passed selector.
11009     * @param {String/Array} els A string CSS selector, an array of elements or an element
11010     * @return {CompositeElement} this
11011     */
11012     fill : function(els){
11013         this.elements = [];
11014         this.add(els);
11015         return this;
11016     },
11017
11018     /**
11019     * Filters this composite to only elements that match the passed selector.
11020     * @param {String} selector A string CSS selector
11021     * @param {Boolean} inverse return inverse filter (not matches)
11022     * @return {CompositeElement} this
11023     */
11024     filter : function(selector, inverse){
11025         var els = [];
11026         inverse = inverse || false;
11027         this.each(function(el){
11028             var match = inverse ? !el.is(selector) : el.is(selector);
11029             if(match){
11030                 els[els.length] = el.dom;
11031             }
11032         });
11033         this.fill(els);
11034         return this;
11035     },
11036
11037     invoke : function(fn, args){
11038         var els = this.elements;
11039         for(var i = 0, len = els.length; i < len; i++) {
11040                 Roo.Element.prototype[fn].apply(els[i], args);
11041         }
11042         return this;
11043     },
11044     /**
11045     * Adds elements to this composite.
11046     * @param {String/Array} els A string CSS selector, an array of elements or an element
11047     * @return {CompositeElement} this
11048     */
11049     add : function(els){
11050         if(typeof els == "string"){
11051             this.addElements(Roo.Element.selectorFunction(els));
11052         }else if(els.length !== undefined){
11053             this.addElements(els);
11054         }else{
11055             this.addElements([els]);
11056         }
11057         return this;
11058     },
11059     /**
11060     * Calls the passed function passing (el, this, index) for each element in this composite.
11061     * @param {Function} fn The function to call
11062     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11063     * @return {CompositeElement} this
11064     */
11065     each : function(fn, scope){
11066         var els = this.elements;
11067         for(var i = 0, len = els.length; i < len; i++){
11068             if(fn.call(scope || els[i], els[i], this, i) === false) {
11069                 break;
11070             }
11071         }
11072         return this;
11073     },
11074
11075     /**
11076      * Returns the Element object at the specified index
11077      * @param {Number} index
11078      * @return {Roo.Element}
11079      */
11080     item : function(index){
11081         return this.elements[index] || null;
11082     },
11083
11084     /**
11085      * Returns the first Element
11086      * @return {Roo.Element}
11087      */
11088     first : function(){
11089         return this.item(0);
11090     },
11091
11092     /**
11093      * Returns the last Element
11094      * @return {Roo.Element}
11095      */
11096     last : function(){
11097         return this.item(this.elements.length-1);
11098     },
11099
11100     /**
11101      * Returns the number of elements in this composite
11102      * @return Number
11103      */
11104     getCount : function(){
11105         return this.elements.length;
11106     },
11107
11108     /**
11109      * Returns true if this composite contains the passed element
11110      * @return Boolean
11111      */
11112     contains : function(el){
11113         return this.indexOf(el) !== -1;
11114     },
11115
11116     /**
11117      * Returns true if this composite contains the passed element
11118      * @return Boolean
11119      */
11120     indexOf : function(el){
11121         return this.elements.indexOf(Roo.get(el));
11122     },
11123
11124
11125     /**
11126     * Removes the specified element(s).
11127     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11128     * or an array of any of those.
11129     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11130     * @return {CompositeElement} this
11131     */
11132     removeElement : function(el, removeDom){
11133         if(el instanceof Array){
11134             for(var i = 0, len = el.length; i < len; i++){
11135                 this.removeElement(el[i]);
11136             }
11137             return this;
11138         }
11139         var index = typeof el == 'number' ? el : this.indexOf(el);
11140         if(index !== -1){
11141             if(removeDom){
11142                 var d = this.elements[index];
11143                 if(d.dom){
11144                     d.remove();
11145                 }else{
11146                     d.parentNode.removeChild(d);
11147                 }
11148             }
11149             this.elements.splice(index, 1);
11150         }
11151         return this;
11152     },
11153
11154     /**
11155     * Replaces the specified element with the passed element.
11156     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11157     * to replace.
11158     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11159     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11160     * @return {CompositeElement} this
11161     */
11162     replaceElement : function(el, replacement, domReplace){
11163         var index = typeof el == 'number' ? el : this.indexOf(el);
11164         if(index !== -1){
11165             if(domReplace){
11166                 this.elements[index].replaceWith(replacement);
11167             }else{
11168                 this.elements.splice(index, 1, Roo.get(replacement))
11169             }
11170         }
11171         return this;
11172     },
11173
11174     /**
11175      * Removes all elements.
11176      */
11177     clear : function(){
11178         this.elements = [];
11179     }
11180 };
11181 (function(){
11182     Roo.CompositeElement.createCall = function(proto, fnName){
11183         if(!proto[fnName]){
11184             proto[fnName] = function(){
11185                 return this.invoke(fnName, arguments);
11186             };
11187         }
11188     };
11189     for(var fnName in Roo.Element.prototype){
11190         if(typeof Roo.Element.prototype[fnName] == "function"){
11191             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11192         }
11193     };
11194 })();
11195 /*
11196  * Based on:
11197  * Ext JS Library 1.1.1
11198  * Copyright(c) 2006-2007, Ext JS, LLC.
11199  *
11200  * Originally Released Under LGPL - original licence link has changed is not relivant.
11201  *
11202  * Fork - LGPL
11203  * <script type="text/javascript">
11204  */
11205
11206 /**
11207  * @class Roo.CompositeElementLite
11208  * @extends Roo.CompositeElement
11209  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11210  <pre><code>
11211  var els = Roo.select("#some-el div.some-class");
11212  // or select directly from an existing element
11213  var el = Roo.get('some-el');
11214  el.select('div.some-class');
11215
11216  els.setWidth(100); // all elements become 100 width
11217  els.hide(true); // all elements fade out and hide
11218  // or
11219  els.setWidth(100).hide(true);
11220  </code></pre><br><br>
11221  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11222  * actions will be performed on all the elements in this collection.</b>
11223  */
11224 Roo.CompositeElementLite = function(els){
11225     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11226     this.el = new Roo.Element.Flyweight();
11227 };
11228 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11229     addElements : function(els){
11230         if(els){
11231             if(els instanceof Array){
11232                 this.elements = this.elements.concat(els);
11233             }else{
11234                 var yels = this.elements;
11235                 var index = yels.length-1;
11236                 for(var i = 0, len = els.length; i < len; i++) {
11237                     yels[++index] = els[i];
11238                 }
11239             }
11240         }
11241         return this;
11242     },
11243     invoke : function(fn, args){
11244         var els = this.elements;
11245         var el = this.el;
11246         for(var i = 0, len = els.length; i < len; i++) {
11247             el.dom = els[i];
11248                 Roo.Element.prototype[fn].apply(el, args);
11249         }
11250         return this;
11251     },
11252     /**
11253      * Returns a flyweight Element of the dom element object at the specified index
11254      * @param {Number} index
11255      * @return {Roo.Element}
11256      */
11257     item : function(index){
11258         if(!this.elements[index]){
11259             return null;
11260         }
11261         this.el.dom = this.elements[index];
11262         return this.el;
11263     },
11264
11265     // fixes scope with flyweight
11266     addListener : function(eventName, handler, scope, opt){
11267         var els = this.elements;
11268         for(var i = 0, len = els.length; i < len; i++) {
11269             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11270         }
11271         return this;
11272     },
11273
11274     /**
11275     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11276     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11277     * a reference to the dom node, use el.dom.</b>
11278     * @param {Function} fn The function to call
11279     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11280     * @return {CompositeElement} this
11281     */
11282     each : function(fn, scope){
11283         var els = this.elements;
11284         var el = this.el;
11285         for(var i = 0, len = els.length; i < len; i++){
11286             el.dom = els[i];
11287                 if(fn.call(scope || el, el, this, i) === false){
11288                 break;
11289             }
11290         }
11291         return this;
11292     },
11293
11294     indexOf : function(el){
11295         return this.elements.indexOf(Roo.getDom(el));
11296     },
11297
11298     replaceElement : function(el, replacement, domReplace){
11299         var index = typeof el == 'number' ? el : this.indexOf(el);
11300         if(index !== -1){
11301             replacement = Roo.getDom(replacement);
11302             if(domReplace){
11303                 var d = this.elements[index];
11304                 d.parentNode.insertBefore(replacement, d);
11305                 d.parentNode.removeChild(d);
11306             }
11307             this.elements.splice(index, 1, replacement);
11308         }
11309         return this;
11310     }
11311 });
11312 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11313
11314 /*
11315  * Based on:
11316  * Ext JS Library 1.1.1
11317  * Copyright(c) 2006-2007, Ext JS, LLC.
11318  *
11319  * Originally Released Under LGPL - original licence link has changed is not relivant.
11320  *
11321  * Fork - LGPL
11322  * <script type="text/javascript">
11323  */
11324
11325  
11326
11327 /**
11328  * @class Roo.data.Connection
11329  * @extends Roo.util.Observable
11330  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11331  * either to a configured URL, or to a URL specified at request time.<br><br>
11332  * <p>
11333  * Requests made by this class are asynchronous, and will return immediately. No data from
11334  * the server will be available to the statement immediately following the {@link #request} call.
11335  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11336  * <p>
11337  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11338  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11339  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11340  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11341  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11342  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11343  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11344  * standard DOM methods.
11345  * @constructor
11346  * @param {Object} config a configuration object.
11347  */
11348 Roo.data.Connection = function(config){
11349     Roo.apply(this, config);
11350     this.addEvents({
11351         /**
11352          * @event beforerequest
11353          * Fires before a network request is made to retrieve a data object.
11354          * @param {Connection} conn This Connection object.
11355          * @param {Object} options The options config object passed to the {@link #request} method.
11356          */
11357         "beforerequest" : true,
11358         /**
11359          * @event requestcomplete
11360          * Fires if the request was successfully completed.
11361          * @param {Connection} conn This Connection object.
11362          * @param {Object} response The XHR object containing the response data.
11363          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11364          * @param {Object} options The options config object passed to the {@link #request} method.
11365          */
11366         "requestcomplete" : true,
11367         /**
11368          * @event requestexception
11369          * Fires if an error HTTP status was returned from the server.
11370          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11371          * @param {Connection} conn This Connection object.
11372          * @param {Object} response The XHR object containing the response data.
11373          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11374          * @param {Object} options The options config object passed to the {@link #request} method.
11375          */
11376         "requestexception" : true
11377     });
11378     Roo.data.Connection.superclass.constructor.call(this);
11379 };
11380
11381 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11382     /**
11383      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11384      */
11385     /**
11386      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11387      * extra parameters to each request made by this object. (defaults to undefined)
11388      */
11389     /**
11390      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11391      *  to each request made by this object. (defaults to undefined)
11392      */
11393     /**
11394      * @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)
11395      */
11396     /**
11397      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11398      */
11399     timeout : 30000,
11400     /**
11401      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11402      * @type Boolean
11403      */
11404     autoAbort:false,
11405
11406     /**
11407      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11408      * @type Boolean
11409      */
11410     disableCaching: true,
11411
11412     /**
11413      * Sends an HTTP request to a remote server.
11414      * @param {Object} options An object which may contain the following properties:<ul>
11415      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11416      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11417      * request, a url encoded string or a function to call to get either.</li>
11418      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11419      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11420      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11421      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11422      * <li>options {Object} The parameter to the request call.</li>
11423      * <li>success {Boolean} True if the request succeeded.</li>
11424      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11425      * </ul></li>
11426      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11427      * The callback is passed the following parameters:<ul>
11428      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11429      * <li>options {Object} The parameter to the request call.</li>
11430      * </ul></li>
11431      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11432      * The callback is passed the following parameters:<ul>
11433      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11434      * <li>options {Object} The parameter to the request call.</li>
11435      * </ul></li>
11436      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11437      * for the callback function. Defaults to the browser window.</li>
11438      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11439      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11440      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11441      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11442      * params for the post data. Any params will be appended to the URL.</li>
11443      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11444      * </ul>
11445      * @return {Number} transactionId
11446      */
11447     request : function(o){
11448         if(this.fireEvent("beforerequest", this, o) !== false){
11449             var p = o.params;
11450
11451             if(typeof p == "function"){
11452                 p = p.call(o.scope||window, o);
11453             }
11454             if(typeof p == "object"){
11455                 p = Roo.urlEncode(o.params);
11456             }
11457             if(this.extraParams){
11458                 var extras = Roo.urlEncode(this.extraParams);
11459                 p = p ? (p + '&' + extras) : extras;
11460             }
11461
11462             var url = o.url || this.url;
11463             if(typeof url == 'function'){
11464                 url = url.call(o.scope||window, o);
11465             }
11466
11467             if(o.form){
11468                 var form = Roo.getDom(o.form);
11469                 url = url || form.action;
11470
11471                 var enctype = form.getAttribute("enctype");
11472                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11473                     return this.doFormUpload(o, p, url);
11474                 }
11475                 var f = Roo.lib.Ajax.serializeForm(form);
11476                 p = p ? (p + '&' + f) : f;
11477             }
11478
11479             var hs = o.headers;
11480             if(this.defaultHeaders){
11481                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11482                 if(!o.headers){
11483                     o.headers = hs;
11484                 }
11485             }
11486
11487             var cb = {
11488                 success: this.handleResponse,
11489                 failure: this.handleFailure,
11490                 scope: this,
11491                 argument: {options: o},
11492                 timeout : o.timeout || this.timeout
11493             };
11494
11495             var method = o.method||this.method||(p ? "POST" : "GET");
11496
11497             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11498                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11499             }
11500
11501             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11502                 if(o.autoAbort){
11503                     this.abort();
11504                 }
11505             }else if(this.autoAbort !== false){
11506                 this.abort();
11507             }
11508
11509             if((method == 'GET' && p) || o.xmlData){
11510                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11511                 p = '';
11512             }
11513             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11514             return this.transId;
11515         }else{
11516             Roo.callback(o.callback, o.scope, [o, null, null]);
11517             return null;
11518         }
11519     },
11520
11521     /**
11522      * Determine whether this object has a request outstanding.
11523      * @param {Number} transactionId (Optional) defaults to the last transaction
11524      * @return {Boolean} True if there is an outstanding request.
11525      */
11526     isLoading : function(transId){
11527         if(transId){
11528             return Roo.lib.Ajax.isCallInProgress(transId);
11529         }else{
11530             return this.transId ? true : false;
11531         }
11532     },
11533
11534     /**
11535      * Aborts any outstanding request.
11536      * @param {Number} transactionId (Optional) defaults to the last transaction
11537      */
11538     abort : function(transId){
11539         if(transId || this.isLoading()){
11540             Roo.lib.Ajax.abort(transId || this.transId);
11541         }
11542     },
11543
11544     // private
11545     handleResponse : function(response){
11546         this.transId = false;
11547         var options = response.argument.options;
11548         response.argument = options ? options.argument : null;
11549         this.fireEvent("requestcomplete", this, response, options);
11550         Roo.callback(options.success, options.scope, [response, options]);
11551         Roo.callback(options.callback, options.scope, [options, true, response]);
11552     },
11553
11554     // private
11555     handleFailure : function(response, e){
11556         this.transId = false;
11557         var options = response.argument.options;
11558         response.argument = options ? options.argument : null;
11559         this.fireEvent("requestexception", this, response, options, e);
11560         Roo.callback(options.failure, options.scope, [response, options]);
11561         Roo.callback(options.callback, options.scope, [options, false, response]);
11562     },
11563
11564     // private
11565     doFormUpload : function(o, ps, url){
11566         var id = Roo.id();
11567         var frame = document.createElement('iframe');
11568         frame.id = id;
11569         frame.name = id;
11570         frame.className = 'x-hidden';
11571         if(Roo.isIE){
11572             frame.src = Roo.SSL_SECURE_URL;
11573         }
11574         document.body.appendChild(frame);
11575
11576         if(Roo.isIE){
11577            document.frames[id].name = id;
11578         }
11579
11580         var form = Roo.getDom(o.form);
11581         form.target = id;
11582         form.method = 'POST';
11583         form.enctype = form.encoding = 'multipart/form-data';
11584         if(url){
11585             form.action = url;
11586         }
11587
11588         var hiddens, hd;
11589         if(ps){ // add dynamic params
11590             hiddens = [];
11591             ps = Roo.urlDecode(ps, false);
11592             for(var k in ps){
11593                 if(ps.hasOwnProperty(k)){
11594                     hd = document.createElement('input');
11595                     hd.type = 'hidden';
11596                     hd.name = k;
11597                     hd.value = ps[k];
11598                     form.appendChild(hd);
11599                     hiddens.push(hd);
11600                 }
11601             }
11602         }
11603
11604         function cb(){
11605             var r = {  // bogus response object
11606                 responseText : '',
11607                 responseXML : null
11608             };
11609
11610             r.argument = o ? o.argument : null;
11611
11612             try { //
11613                 var doc;
11614                 if(Roo.isIE){
11615                     doc = frame.contentWindow.document;
11616                 }else {
11617                     doc = (frame.contentDocument || window.frames[id].document);
11618                 }
11619                 if(doc && doc.body){
11620                     r.responseText = doc.body.innerHTML;
11621                 }
11622                 if(doc && doc.XMLDocument){
11623                     r.responseXML = doc.XMLDocument;
11624                 }else {
11625                     r.responseXML = doc;
11626                 }
11627             }
11628             catch(e) {
11629                 // ignore
11630             }
11631
11632             Roo.EventManager.removeListener(frame, 'load', cb, this);
11633
11634             this.fireEvent("requestcomplete", this, r, o);
11635             Roo.callback(o.success, o.scope, [r, o]);
11636             Roo.callback(o.callback, o.scope, [o, true, r]);
11637
11638             setTimeout(function(){document.body.removeChild(frame);}, 100);
11639         }
11640
11641         Roo.EventManager.on(frame, 'load', cb, this);
11642         form.submit();
11643
11644         if(hiddens){ // remove dynamic params
11645             for(var i = 0, len = hiddens.length; i < len; i++){
11646                 form.removeChild(hiddens[i]);
11647             }
11648         }
11649     }
11650 });
11651 /*
11652  * Based on:
11653  * Ext JS Library 1.1.1
11654  * Copyright(c) 2006-2007, Ext JS, LLC.
11655  *
11656  * Originally Released Under LGPL - original licence link has changed is not relivant.
11657  *
11658  * Fork - LGPL
11659  * <script type="text/javascript">
11660  */
11661  
11662 /**
11663  * Global Ajax request class.
11664  * 
11665  * @class Roo.Ajax
11666  * @extends Roo.data.Connection
11667  * @static
11668  * 
11669  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11670  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11671  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11672  * @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)
11673  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11674  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11675  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11676  */
11677 Roo.Ajax = new Roo.data.Connection({
11678     // fix up the docs
11679     /**
11680      * @scope Roo.Ajax
11681      * @type {Boolear} 
11682      */
11683     autoAbort : false,
11684
11685     /**
11686      * Serialize the passed form into a url encoded string
11687      * @scope Roo.Ajax
11688      * @param {String/HTMLElement} form
11689      * @return {String}
11690      */
11691     serializeForm : function(form){
11692         return Roo.lib.Ajax.serializeForm(form);
11693     }
11694 });/*
11695  * Based on:
11696  * Ext JS Library 1.1.1
11697  * Copyright(c) 2006-2007, Ext JS, LLC.
11698  *
11699  * Originally Released Under LGPL - original licence link has changed is not relivant.
11700  *
11701  * Fork - LGPL
11702  * <script type="text/javascript">
11703  */
11704
11705  
11706 /**
11707  * @class Roo.UpdateManager
11708  * @extends Roo.util.Observable
11709  * Provides AJAX-style update for Element object.<br><br>
11710  * Usage:<br>
11711  * <pre><code>
11712  * // Get it from a Roo.Element object
11713  * var el = Roo.get("foo");
11714  * var mgr = el.getUpdateManager();
11715  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11716  * ...
11717  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11718  * <br>
11719  * // or directly (returns the same UpdateManager instance)
11720  * var mgr = new Roo.UpdateManager("myElementId");
11721  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11722  * mgr.on("update", myFcnNeedsToKnow);
11723  * <br>
11724    // short handed call directly from the element object
11725    Roo.get("foo").load({
11726         url: "bar.php",
11727         scripts:true,
11728         params: "for=bar",
11729         text: "Loading Foo..."
11730    });
11731  * </code></pre>
11732  * @constructor
11733  * Create new UpdateManager directly.
11734  * @param {String/HTMLElement/Roo.Element} el The element to update
11735  * @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).
11736  */
11737 Roo.UpdateManager = function(el, forceNew){
11738     el = Roo.get(el);
11739     if(!forceNew && el.updateManager){
11740         return el.updateManager;
11741     }
11742     /**
11743      * The Element object
11744      * @type Roo.Element
11745      */
11746     this.el = el;
11747     /**
11748      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11749      * @type String
11750      */
11751     this.defaultUrl = null;
11752
11753     this.addEvents({
11754         /**
11755          * @event beforeupdate
11756          * Fired before an update is made, return false from your handler and the update is cancelled.
11757          * @param {Roo.Element} el
11758          * @param {String/Object/Function} url
11759          * @param {String/Object} params
11760          */
11761         "beforeupdate": true,
11762         /**
11763          * @event update
11764          * Fired after successful update is made.
11765          * @param {Roo.Element} el
11766          * @param {Object} oResponseObject The response Object
11767          */
11768         "update": true,
11769         /**
11770          * @event failure
11771          * Fired on update failure.
11772          * @param {Roo.Element} el
11773          * @param {Object} oResponseObject The response Object
11774          */
11775         "failure": true
11776     });
11777     var d = Roo.UpdateManager.defaults;
11778     /**
11779      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11780      * @type String
11781      */
11782     this.sslBlankUrl = d.sslBlankUrl;
11783     /**
11784      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11785      * @type Boolean
11786      */
11787     this.disableCaching = d.disableCaching;
11788     /**
11789      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11790      * @type String
11791      */
11792     this.indicatorText = d.indicatorText;
11793     /**
11794      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11795      * @type String
11796      */
11797     this.showLoadIndicator = d.showLoadIndicator;
11798     /**
11799      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11800      * @type Number
11801      */
11802     this.timeout = d.timeout;
11803
11804     /**
11805      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11806      * @type Boolean
11807      */
11808     this.loadScripts = d.loadScripts;
11809
11810     /**
11811      * Transaction object of current executing transaction
11812      */
11813     this.transaction = null;
11814
11815     /**
11816      * @private
11817      */
11818     this.autoRefreshProcId = null;
11819     /**
11820      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11821      * @type Function
11822      */
11823     this.refreshDelegate = this.refresh.createDelegate(this);
11824     /**
11825      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11826      * @type Function
11827      */
11828     this.updateDelegate = this.update.createDelegate(this);
11829     /**
11830      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11831      * @type Function
11832      */
11833     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11834     /**
11835      * @private
11836      */
11837     this.successDelegate = this.processSuccess.createDelegate(this);
11838     /**
11839      * @private
11840      */
11841     this.failureDelegate = this.processFailure.createDelegate(this);
11842
11843     if(!this.renderer){
11844      /**
11845       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11846       */
11847     this.renderer = new Roo.UpdateManager.BasicRenderer();
11848     }
11849     
11850     Roo.UpdateManager.superclass.constructor.call(this);
11851 };
11852
11853 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11854     /**
11855      * Get the Element this UpdateManager is bound to
11856      * @return {Roo.Element} The element
11857      */
11858     getEl : function(){
11859         return this.el;
11860     },
11861     /**
11862      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11863      * @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:
11864 <pre><code>
11865 um.update({<br/>
11866     url: "your-url.php",<br/>
11867     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11868     callback: yourFunction,<br/>
11869     scope: yourObject, //(optional scope)  <br/>
11870     discardUrl: false, <br/>
11871     nocache: false,<br/>
11872     text: "Loading...",<br/>
11873     timeout: 30,<br/>
11874     scripts: false<br/>
11875 });
11876 </code></pre>
11877      * The only required property is url. The optional properties nocache, text and scripts
11878      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11879      * @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}
11880      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11881      * @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.
11882      */
11883     update : function(url, params, callback, discardUrl){
11884         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11885             var method = this.method,
11886                 cfg;
11887             if(typeof url == "object"){ // must be config object
11888                 cfg = url;
11889                 url = cfg.url;
11890                 params = params || cfg.params;
11891                 callback = callback || cfg.callback;
11892                 discardUrl = discardUrl || cfg.discardUrl;
11893                 if(callback && cfg.scope){
11894                     callback = callback.createDelegate(cfg.scope);
11895                 }
11896                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11897                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11898                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11899                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11900                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11901             }
11902             this.showLoading();
11903             if(!discardUrl){
11904                 this.defaultUrl = url;
11905             }
11906             if(typeof url == "function"){
11907                 url = url.call(this);
11908             }
11909
11910             method = method || (params ? "POST" : "GET");
11911             if(method == "GET"){
11912                 url = this.prepareUrl(url);
11913             }
11914
11915             var o = Roo.apply(cfg ||{}, {
11916                 url : url,
11917                 params: params,
11918                 success: this.successDelegate,
11919                 failure: this.failureDelegate,
11920                 callback: undefined,
11921                 timeout: (this.timeout*1000),
11922                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11923             });
11924             Roo.log("updated manager called with timeout of " + o.timeout);
11925             this.transaction = Roo.Ajax.request(o);
11926         }
11927     },
11928
11929     /**
11930      * 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.
11931      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11932      * @param {String/HTMLElement} form The form Id or form element
11933      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11934      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11935      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11936      */
11937     formUpdate : function(form, url, reset, callback){
11938         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11939             if(typeof url == "function"){
11940                 url = url.call(this);
11941             }
11942             form = Roo.getDom(form);
11943             this.transaction = Roo.Ajax.request({
11944                 form: form,
11945                 url:url,
11946                 success: this.successDelegate,
11947                 failure: this.failureDelegate,
11948                 timeout: (this.timeout*1000),
11949                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11950             });
11951             this.showLoading.defer(1, this);
11952         }
11953     },
11954
11955     /**
11956      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11957      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11958      */
11959     refresh : function(callback){
11960         if(this.defaultUrl == null){
11961             return;
11962         }
11963         this.update(this.defaultUrl, null, callback, true);
11964     },
11965
11966     /**
11967      * Set this element to auto refresh.
11968      * @param {Number} interval How often to update (in seconds).
11969      * @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)
11970      * @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}
11971      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11972      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11973      */
11974     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11975         if(refreshNow){
11976             this.update(url || this.defaultUrl, params, callback, true);
11977         }
11978         if(this.autoRefreshProcId){
11979             clearInterval(this.autoRefreshProcId);
11980         }
11981         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11982     },
11983
11984     /**
11985      * Stop auto refresh on this element.
11986      */
11987      stopAutoRefresh : function(){
11988         if(this.autoRefreshProcId){
11989             clearInterval(this.autoRefreshProcId);
11990             delete this.autoRefreshProcId;
11991         }
11992     },
11993
11994     isAutoRefreshing : function(){
11995        return this.autoRefreshProcId ? true : false;
11996     },
11997     /**
11998      * Called to update the element to "Loading" state. Override to perform custom action.
11999      */
12000     showLoading : function(){
12001         if(this.showLoadIndicator){
12002             this.el.update(this.indicatorText);
12003         }
12004     },
12005
12006     /**
12007      * Adds unique parameter to query string if disableCaching = true
12008      * @private
12009      */
12010     prepareUrl : function(url){
12011         if(this.disableCaching){
12012             var append = "_dc=" + (new Date().getTime());
12013             if(url.indexOf("?") !== -1){
12014                 url += "&" + append;
12015             }else{
12016                 url += "?" + append;
12017             }
12018         }
12019         return url;
12020     },
12021
12022     /**
12023      * @private
12024      */
12025     processSuccess : function(response){
12026         this.transaction = null;
12027         if(response.argument.form && response.argument.reset){
12028             try{ // put in try/catch since some older FF releases had problems with this
12029                 response.argument.form.reset();
12030             }catch(e){}
12031         }
12032         if(this.loadScripts){
12033             this.renderer.render(this.el, response, this,
12034                 this.updateComplete.createDelegate(this, [response]));
12035         }else{
12036             this.renderer.render(this.el, response, this);
12037             this.updateComplete(response);
12038         }
12039     },
12040
12041     updateComplete : function(response){
12042         this.fireEvent("update", this.el, response);
12043         if(typeof response.argument.callback == "function"){
12044             response.argument.callback(this.el, true, response);
12045         }
12046     },
12047
12048     /**
12049      * @private
12050      */
12051     processFailure : function(response){
12052         this.transaction = null;
12053         this.fireEvent("failure", this.el, response);
12054         if(typeof response.argument.callback == "function"){
12055             response.argument.callback(this.el, false, response);
12056         }
12057     },
12058
12059     /**
12060      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12061      * @param {Object} renderer The object implementing the render() method
12062      */
12063     setRenderer : function(renderer){
12064         this.renderer = renderer;
12065     },
12066
12067     getRenderer : function(){
12068        return this.renderer;
12069     },
12070
12071     /**
12072      * Set the defaultUrl used for updates
12073      * @param {String/Function} defaultUrl The url or a function to call to get the url
12074      */
12075     setDefaultUrl : function(defaultUrl){
12076         this.defaultUrl = defaultUrl;
12077     },
12078
12079     /**
12080      * Aborts the executing transaction
12081      */
12082     abort : function(){
12083         if(this.transaction){
12084             Roo.Ajax.abort(this.transaction);
12085         }
12086     },
12087
12088     /**
12089      * Returns true if an update is in progress
12090      * @return {Boolean}
12091      */
12092     isUpdating : function(){
12093         if(this.transaction){
12094             return Roo.Ajax.isLoading(this.transaction);
12095         }
12096         return false;
12097     }
12098 });
12099
12100 /**
12101  * @class Roo.UpdateManager.defaults
12102  * @static (not really - but it helps the doc tool)
12103  * The defaults collection enables customizing the default properties of UpdateManager
12104  */
12105    Roo.UpdateManager.defaults = {
12106        /**
12107          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12108          * @type Number
12109          */
12110          timeout : 30,
12111
12112          /**
12113          * True to process scripts by default (Defaults to false).
12114          * @type Boolean
12115          */
12116         loadScripts : false,
12117
12118         /**
12119         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12120         * @type String
12121         */
12122         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12123         /**
12124          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12125          * @type Boolean
12126          */
12127         disableCaching : false,
12128         /**
12129          * Whether to show indicatorText when loading (Defaults to true).
12130          * @type Boolean
12131          */
12132         showLoadIndicator : true,
12133         /**
12134          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12135          * @type String
12136          */
12137         indicatorText : '<div class="loading-indicator">Loading...</div>'
12138    };
12139
12140 /**
12141  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12142  *Usage:
12143  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12144  * @param {String/HTMLElement/Roo.Element} el The element to update
12145  * @param {String} url The url
12146  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12147  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12148  * @static
12149  * @deprecated
12150  * @member Roo.UpdateManager
12151  */
12152 Roo.UpdateManager.updateElement = function(el, url, params, options){
12153     var um = Roo.get(el, true).getUpdateManager();
12154     Roo.apply(um, options);
12155     um.update(url, params, options ? options.callback : null);
12156 };
12157 // alias for backwards compat
12158 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12159 /**
12160  * @class Roo.UpdateManager.BasicRenderer
12161  * Default Content renderer. Updates the elements innerHTML with the responseText.
12162  */
12163 Roo.UpdateManager.BasicRenderer = function(){};
12164
12165 Roo.UpdateManager.BasicRenderer.prototype = {
12166     /**
12167      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12168      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12169      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12170      * @param {Roo.Element} el The element being rendered
12171      * @param {Object} response The YUI Connect response object
12172      * @param {UpdateManager} updateManager The calling update manager
12173      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12174      */
12175      render : function(el, response, updateManager, callback){
12176         el.update(response.responseText, updateManager.loadScripts, callback);
12177     }
12178 };
12179 /*
12180  * Based on:
12181  * Roo JS
12182  * (c)) Alan Knowles
12183  * Licence : LGPL
12184  */
12185
12186
12187 /**
12188  * @class Roo.DomTemplate
12189  * @extends Roo.Template
12190  * An effort at a dom based template engine..
12191  *
12192  * Similar to XTemplate, except it uses dom parsing to create the template..
12193  *
12194  * Supported features:
12195  *
12196  *  Tags:
12197
12198 <pre><code>
12199       {a_variable} - output encoded.
12200       {a_variable.format:("Y-m-d")} - call a method on the variable
12201       {a_variable:raw} - unencoded output
12202       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12203       {a_variable:this.method_on_template(...)} - call a method on the template object.
12204  
12205 </code></pre>
12206  *  The tpl tag:
12207 <pre><code>
12208         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12209         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12210         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12211         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12212   
12213 </code></pre>
12214  *      
12215  */
12216 Roo.DomTemplate = function()
12217 {
12218      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12219      if (this.html) {
12220         this.compile();
12221      }
12222 };
12223
12224
12225 Roo.extend(Roo.DomTemplate, Roo.Template, {
12226     /**
12227      * id counter for sub templates.
12228      */
12229     id : 0,
12230     /**
12231      * flag to indicate if dom parser is inside a pre,
12232      * it will strip whitespace if not.
12233      */
12234     inPre : false,
12235     
12236     /**
12237      * The various sub templates
12238      */
12239     tpls : false,
12240     
12241     
12242     
12243     /**
12244      *
12245      * basic tag replacing syntax
12246      * WORD:WORD()
12247      *
12248      * // you can fake an object call by doing this
12249      *  x.t:(test,tesT) 
12250      * 
12251      */
12252     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12253     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12254     
12255     iterChild : function (node, method) {
12256         
12257         var oldPre = this.inPre;
12258         if (node.tagName == 'PRE') {
12259             this.inPre = true;
12260         }
12261         for( var i = 0; i < node.childNodes.length; i++) {
12262             method.call(this, node.childNodes[i]);
12263         }
12264         this.inPre = oldPre;
12265     },
12266     
12267     
12268     
12269     /**
12270      * compile the template
12271      *
12272      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12273      *
12274      */
12275     compile: function()
12276     {
12277         var s = this.html;
12278         
12279         // covert the html into DOM...
12280         var doc = false;
12281         var div =false;
12282         try {
12283             doc = document.implementation.createHTMLDocument("");
12284             doc.documentElement.innerHTML =   this.html  ;
12285             div = doc.documentElement;
12286         } catch (e) {
12287             // old IE... - nasty -- it causes all sorts of issues.. with
12288             // images getting pulled from server..
12289             div = document.createElement('div');
12290             div.innerHTML = this.html;
12291         }
12292         //doc.documentElement.innerHTML = htmlBody
12293          
12294         
12295         
12296         this.tpls = [];
12297         var _t = this;
12298         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12299         
12300         var tpls = this.tpls;
12301         
12302         // create a top level template from the snippet..
12303         
12304         //Roo.log(div.innerHTML);
12305         
12306         var tpl = {
12307             uid : 'master',
12308             id : this.id++,
12309             attr : false,
12310             value : false,
12311             body : div.innerHTML,
12312             
12313             forCall : false,
12314             execCall : false,
12315             dom : div,
12316             isTop : true
12317             
12318         };
12319         tpls.unshift(tpl);
12320         
12321         
12322         // compile them...
12323         this.tpls = [];
12324         Roo.each(tpls, function(tp){
12325             this.compileTpl(tp);
12326             this.tpls[tp.id] = tp;
12327         }, this);
12328         
12329         this.master = tpls[0];
12330         return this;
12331         
12332         
12333     },
12334     
12335     compileNode : function(node, istop) {
12336         // test for
12337         //Roo.log(node);
12338         
12339         
12340         // skip anything not a tag..
12341         if (node.nodeType != 1) {
12342             if (node.nodeType == 3 && !this.inPre) {
12343                 // reduce white space..
12344                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12345                 
12346             }
12347             return;
12348         }
12349         
12350         var tpl = {
12351             uid : false,
12352             id : false,
12353             attr : false,
12354             value : false,
12355             body : '',
12356             
12357             forCall : false,
12358             execCall : false,
12359             dom : false,
12360             isTop : istop
12361             
12362             
12363         };
12364         
12365         
12366         switch(true) {
12367             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12368             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12369             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12370             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12371             // no default..
12372         }
12373         
12374         
12375         if (!tpl.attr) {
12376             // just itterate children..
12377             this.iterChild(node,this.compileNode);
12378             return;
12379         }
12380         tpl.uid = this.id++;
12381         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12382         node.removeAttribute('roo-'+ tpl.attr);
12383         if (tpl.attr != 'name') {
12384             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12385             node.parentNode.replaceChild(placeholder,  node);
12386         } else {
12387             
12388             var placeholder =  document.createElement('span');
12389             placeholder.className = 'roo-tpl-' + tpl.value;
12390             node.parentNode.replaceChild(placeholder,  node);
12391         }
12392         
12393         // parent now sees '{domtplXXXX}
12394         this.iterChild(node,this.compileNode);
12395         
12396         // we should now have node body...
12397         var div = document.createElement('div');
12398         div.appendChild(node);
12399         tpl.dom = node;
12400         // this has the unfortunate side effect of converting tagged attributes
12401         // eg. href="{...}" into %7C...%7D
12402         // this has been fixed by searching for those combo's although it's a bit hacky..
12403         
12404         
12405         tpl.body = div.innerHTML;
12406         
12407         
12408          
12409         tpl.id = tpl.uid;
12410         switch(tpl.attr) {
12411             case 'for' :
12412                 switch (tpl.value) {
12413                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12414                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12415                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12416                 }
12417                 break;
12418             
12419             case 'exec':
12420                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12421                 break;
12422             
12423             case 'if':     
12424                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12425                 break;
12426             
12427             case 'name':
12428                 tpl.id  = tpl.value; // replace non characters???
12429                 break;
12430             
12431         }
12432         
12433         
12434         this.tpls.push(tpl);
12435         
12436         
12437         
12438     },
12439     
12440     
12441     
12442     
12443     /**
12444      * Compile a segment of the template into a 'sub-template'
12445      *
12446      * 
12447      * 
12448      *
12449      */
12450     compileTpl : function(tpl)
12451     {
12452         var fm = Roo.util.Format;
12453         var useF = this.disableFormats !== true;
12454         
12455         var sep = Roo.isGecko ? "+\n" : ",\n";
12456         
12457         var undef = function(str) {
12458             Roo.debug && Roo.log("Property not found :"  + str);
12459             return '';
12460         };
12461           
12462         //Roo.log(tpl.body);
12463         
12464         
12465         
12466         var fn = function(m, lbrace, name, format, args)
12467         {
12468             //Roo.log("ARGS");
12469             //Roo.log(arguments);
12470             args = args ? args.replace(/\\'/g,"'") : args;
12471             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12472             if (typeof(format) == 'undefined') {
12473                 format =  'htmlEncode'; 
12474             }
12475             if (format == 'raw' ) {
12476                 format = false;
12477             }
12478             
12479             if(name.substr(0, 6) == 'domtpl'){
12480                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12481             }
12482             
12483             // build an array of options to determine if value is undefined..
12484             
12485             // basically get 'xxxx.yyyy' then do
12486             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12487             //    (function () { Roo.log("Property not found"); return ''; })() :
12488             //    ......
12489             
12490             var udef_ar = [];
12491             var lookfor = '';
12492             Roo.each(name.split('.'), function(st) {
12493                 lookfor += (lookfor.length ? '.': '') + st;
12494                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12495             });
12496             
12497             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12498             
12499             
12500             if(format && useF){
12501                 
12502                 args = args ? ',' + args : "";
12503                  
12504                 if(format.substr(0, 5) != "this."){
12505                     format = "fm." + format + '(';
12506                 }else{
12507                     format = 'this.call("'+ format.substr(5) + '", ';
12508                     args = ", values";
12509                 }
12510                 
12511                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12512             }
12513              
12514             if (args && args.length) {
12515                 // called with xxyx.yuu:(test,test)
12516                 // change to ()
12517                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12518             }
12519             // raw.. - :raw modifier..
12520             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12521             
12522         };
12523         var body;
12524         // branched to use + in gecko and [].join() in others
12525         if(Roo.isGecko){
12526             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12527                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12528                     "';};};";
12529         }else{
12530             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12531             body.push(tpl.body.replace(/(\r\n|\n)/g,
12532                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12533             body.push("'].join('');};};");
12534             body = body.join('');
12535         }
12536         
12537         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12538        
12539         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12540         eval(body);
12541         
12542         return this;
12543     },
12544      
12545     /**
12546      * same as applyTemplate, except it's done to one of the subTemplates
12547      * when using named templates, you can do:
12548      *
12549      * var str = pl.applySubTemplate('your-name', values);
12550      *
12551      * 
12552      * @param {Number} id of the template
12553      * @param {Object} values to apply to template
12554      * @param {Object} parent (normaly the instance of this object)
12555      */
12556     applySubTemplate : function(id, values, parent)
12557     {
12558         
12559         
12560         var t = this.tpls[id];
12561         
12562         
12563         try { 
12564             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12565                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12566                 return '';
12567             }
12568         } catch(e) {
12569             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12570             Roo.log(values);
12571           
12572             return '';
12573         }
12574         try { 
12575             
12576             if(t.execCall && t.execCall.call(this, values, parent)){
12577                 return '';
12578             }
12579         } catch(e) {
12580             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12581             Roo.log(values);
12582             return '';
12583         }
12584         
12585         try {
12586             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12587             parent = t.target ? values : parent;
12588             if(t.forCall && vs instanceof Array){
12589                 var buf = [];
12590                 for(var i = 0, len = vs.length; i < len; i++){
12591                     try {
12592                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12593                     } catch (e) {
12594                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12595                         Roo.log(e.body);
12596                         //Roo.log(t.compiled);
12597                         Roo.log(vs[i]);
12598                     }   
12599                 }
12600                 return buf.join('');
12601             }
12602         } catch (e) {
12603             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12604             Roo.log(values);
12605             return '';
12606         }
12607         try {
12608             return t.compiled.call(this, vs, parent);
12609         } catch (e) {
12610             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12611             Roo.log(e.body);
12612             //Roo.log(t.compiled);
12613             Roo.log(values);
12614             return '';
12615         }
12616     },
12617
12618    
12619
12620     applyTemplate : function(values){
12621         return this.master.compiled.call(this, values, {});
12622         //var s = this.subs;
12623     },
12624
12625     apply : function(){
12626         return this.applyTemplate.apply(this, arguments);
12627     }
12628
12629  });
12630
12631 Roo.DomTemplate.from = function(el){
12632     el = Roo.getDom(el);
12633     return new Roo.Domtemplate(el.value || el.innerHTML);
12634 };/*
12635  * Based on:
12636  * Ext JS Library 1.1.1
12637  * Copyright(c) 2006-2007, Ext JS, LLC.
12638  *
12639  * Originally Released Under LGPL - original licence link has changed is not relivant.
12640  *
12641  * Fork - LGPL
12642  * <script type="text/javascript">
12643  */
12644
12645 /**
12646  * @class Roo.util.DelayedTask
12647  * Provides a convenient method of performing setTimeout where a new
12648  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12649  * You can use this class to buffer
12650  * the keypress events for a certain number of milliseconds, and perform only if they stop
12651  * for that amount of time.
12652  * @constructor The parameters to this constructor serve as defaults and are not required.
12653  * @param {Function} fn (optional) The default function to timeout
12654  * @param {Object} scope (optional) The default scope of that timeout
12655  * @param {Array} args (optional) The default Array of arguments
12656  */
12657 Roo.util.DelayedTask = function(fn, scope, args){
12658     var id = null, d, t;
12659
12660     var call = function(){
12661         var now = new Date().getTime();
12662         if(now - t >= d){
12663             clearInterval(id);
12664             id = null;
12665             fn.apply(scope, args || []);
12666         }
12667     };
12668     /**
12669      * Cancels any pending timeout and queues a new one
12670      * @param {Number} delay The milliseconds to delay
12671      * @param {Function} newFn (optional) Overrides function passed to constructor
12672      * @param {Object} newScope (optional) Overrides scope passed to constructor
12673      * @param {Array} newArgs (optional) Overrides args passed to constructor
12674      */
12675     this.delay = function(delay, newFn, newScope, newArgs){
12676         if(id && delay != d){
12677             this.cancel();
12678         }
12679         d = delay;
12680         t = new Date().getTime();
12681         fn = newFn || fn;
12682         scope = newScope || scope;
12683         args = newArgs || args;
12684         if(!id){
12685             id = setInterval(call, d);
12686         }
12687     };
12688
12689     /**
12690      * Cancel the last queued timeout
12691      */
12692     this.cancel = function(){
12693         if(id){
12694             clearInterval(id);
12695             id = null;
12696         }
12697     };
12698 };/*
12699  * Based on:
12700  * Ext JS Library 1.1.1
12701  * Copyright(c) 2006-2007, Ext JS, LLC.
12702  *
12703  * Originally Released Under LGPL - original licence link has changed is not relivant.
12704  *
12705  * Fork - LGPL
12706  * <script type="text/javascript">
12707  */
12708  
12709  
12710 Roo.util.TaskRunner = function(interval){
12711     interval = interval || 10;
12712     var tasks = [], removeQueue = [];
12713     var id = 0;
12714     var running = false;
12715
12716     var stopThread = function(){
12717         running = false;
12718         clearInterval(id);
12719         id = 0;
12720     };
12721
12722     var startThread = function(){
12723         if(!running){
12724             running = true;
12725             id = setInterval(runTasks, interval);
12726         }
12727     };
12728
12729     var removeTask = function(task){
12730         removeQueue.push(task);
12731         if(task.onStop){
12732             task.onStop();
12733         }
12734     };
12735
12736     var runTasks = function(){
12737         if(removeQueue.length > 0){
12738             for(var i = 0, len = removeQueue.length; i < len; i++){
12739                 tasks.remove(removeQueue[i]);
12740             }
12741             removeQueue = [];
12742             if(tasks.length < 1){
12743                 stopThread();
12744                 return;
12745             }
12746         }
12747         var now = new Date().getTime();
12748         for(var i = 0, len = tasks.length; i < len; ++i){
12749             var t = tasks[i];
12750             var itime = now - t.taskRunTime;
12751             if(t.interval <= itime){
12752                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12753                 t.taskRunTime = now;
12754                 if(rt === false || t.taskRunCount === t.repeat){
12755                     removeTask(t);
12756                     return;
12757                 }
12758             }
12759             if(t.duration && t.duration <= (now - t.taskStartTime)){
12760                 removeTask(t);
12761             }
12762         }
12763     };
12764
12765     /**
12766      * Queues a new task.
12767      * @param {Object} task
12768      */
12769     this.start = function(task){
12770         tasks.push(task);
12771         task.taskStartTime = new Date().getTime();
12772         task.taskRunTime = 0;
12773         task.taskRunCount = 0;
12774         startThread();
12775         return task;
12776     };
12777
12778     this.stop = function(task){
12779         removeTask(task);
12780         return task;
12781     };
12782
12783     this.stopAll = function(){
12784         stopThread();
12785         for(var i = 0, len = tasks.length; i < len; i++){
12786             if(tasks[i].onStop){
12787                 tasks[i].onStop();
12788             }
12789         }
12790         tasks = [];
12791         removeQueue = [];
12792     };
12793 };
12794
12795 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12796  * Based on:
12797  * Ext JS Library 1.1.1
12798  * Copyright(c) 2006-2007, Ext JS, LLC.
12799  *
12800  * Originally Released Under LGPL - original licence link has changed is not relivant.
12801  *
12802  * Fork - LGPL
12803  * <script type="text/javascript">
12804  */
12805
12806  
12807 /**
12808  * @class Roo.util.MixedCollection
12809  * @extends Roo.util.Observable
12810  * A Collection class that maintains both numeric indexes and keys and exposes events.
12811  * @constructor
12812  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12813  * collection (defaults to false)
12814  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12815  * and return the key value for that item.  This is used when available to look up the key on items that
12816  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12817  * equivalent to providing an implementation for the {@link #getKey} method.
12818  */
12819 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12820     this.items = [];
12821     this.map = {};
12822     this.keys = [];
12823     this.length = 0;
12824     this.addEvents({
12825         /**
12826          * @event clear
12827          * Fires when the collection is cleared.
12828          */
12829         "clear" : true,
12830         /**
12831          * @event add
12832          * Fires when an item is added to the collection.
12833          * @param {Number} index The index at which the item was added.
12834          * @param {Object} o The item added.
12835          * @param {String} key The key associated with the added item.
12836          */
12837         "add" : true,
12838         /**
12839          * @event replace
12840          * Fires when an item is replaced in the collection.
12841          * @param {String} key he key associated with the new added.
12842          * @param {Object} old The item being replaced.
12843          * @param {Object} new The new item.
12844          */
12845         "replace" : true,
12846         /**
12847          * @event remove
12848          * Fires when an item is removed from the collection.
12849          * @param {Object} o The item being removed.
12850          * @param {String} key (optional) The key associated with the removed item.
12851          */
12852         "remove" : true,
12853         "sort" : true
12854     });
12855     this.allowFunctions = allowFunctions === true;
12856     if(keyFn){
12857         this.getKey = keyFn;
12858     }
12859     Roo.util.MixedCollection.superclass.constructor.call(this);
12860 };
12861
12862 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12863     allowFunctions : false,
12864     
12865 /**
12866  * Adds an item to the collection.
12867  * @param {String} key The key to associate with the item
12868  * @param {Object} o The item to add.
12869  * @return {Object} The item added.
12870  */
12871     add : function(key, o){
12872         if(arguments.length == 1){
12873             o = arguments[0];
12874             key = this.getKey(o);
12875         }
12876         if(typeof key == "undefined" || key === null){
12877             this.length++;
12878             this.items.push(o);
12879             this.keys.push(null);
12880         }else{
12881             var old = this.map[key];
12882             if(old){
12883                 return this.replace(key, o);
12884             }
12885             this.length++;
12886             this.items.push(o);
12887             this.map[key] = o;
12888             this.keys.push(key);
12889         }
12890         this.fireEvent("add", this.length-1, o, key);
12891         return o;
12892     },
12893        
12894 /**
12895   * MixedCollection has a generic way to fetch keys if you implement getKey.
12896 <pre><code>
12897 // normal way
12898 var mc = new Roo.util.MixedCollection();
12899 mc.add(someEl.dom.id, someEl);
12900 mc.add(otherEl.dom.id, otherEl);
12901 //and so on
12902
12903 // using getKey
12904 var mc = new Roo.util.MixedCollection();
12905 mc.getKey = function(el){
12906    return el.dom.id;
12907 };
12908 mc.add(someEl);
12909 mc.add(otherEl);
12910
12911 // or via the constructor
12912 var mc = new Roo.util.MixedCollection(false, function(el){
12913    return el.dom.id;
12914 });
12915 mc.add(someEl);
12916 mc.add(otherEl);
12917 </code></pre>
12918  * @param o {Object} The item for which to find the key.
12919  * @return {Object} The key for the passed item.
12920  */
12921     getKey : function(o){
12922          return o.id; 
12923     },
12924    
12925 /**
12926  * Replaces an item in the collection.
12927  * @param {String} key The key associated with the item to replace, or the item to replace.
12928  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12929  * @return {Object}  The new item.
12930  */
12931     replace : function(key, o){
12932         if(arguments.length == 1){
12933             o = arguments[0];
12934             key = this.getKey(o);
12935         }
12936         var old = this.item(key);
12937         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12938              return this.add(key, o);
12939         }
12940         var index = this.indexOfKey(key);
12941         this.items[index] = o;
12942         this.map[key] = o;
12943         this.fireEvent("replace", key, old, o);
12944         return o;
12945     },
12946    
12947 /**
12948  * Adds all elements of an Array or an Object to the collection.
12949  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12950  * an Array of values, each of which are added to the collection.
12951  */
12952     addAll : function(objs){
12953         if(arguments.length > 1 || objs instanceof Array){
12954             var args = arguments.length > 1 ? arguments : objs;
12955             for(var i = 0, len = args.length; i < len; i++){
12956                 this.add(args[i]);
12957             }
12958         }else{
12959             for(var key in objs){
12960                 if(this.allowFunctions || typeof objs[key] != "function"){
12961                     this.add(key, objs[key]);
12962                 }
12963             }
12964         }
12965     },
12966    
12967 /**
12968  * Executes the specified function once for every item in the collection, passing each
12969  * item as the first and only parameter. returning false from the function will stop the iteration.
12970  * @param {Function} fn The function to execute for each item.
12971  * @param {Object} scope (optional) The scope in which to execute the function.
12972  */
12973     each : function(fn, scope){
12974         var items = [].concat(this.items); // each safe for removal
12975         for(var i = 0, len = items.length; i < len; i++){
12976             if(fn.call(scope || items[i], items[i], i, len) === false){
12977                 break;
12978             }
12979         }
12980     },
12981    
12982 /**
12983  * Executes the specified function once for every key in the collection, passing each
12984  * key, and its associated item as the first two parameters.
12985  * @param {Function} fn The function to execute for each item.
12986  * @param {Object} scope (optional) The scope in which to execute the function.
12987  */
12988     eachKey : function(fn, scope){
12989         for(var i = 0, len = this.keys.length; i < len; i++){
12990             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12991         }
12992     },
12993    
12994 /**
12995  * Returns the first item in the collection which elicits a true return value from the
12996  * passed selection function.
12997  * @param {Function} fn The selection function to execute for each item.
12998  * @param {Object} scope (optional) The scope in which to execute the function.
12999  * @return {Object} The first item in the collection which returned true from the selection function.
13000  */
13001     find : function(fn, scope){
13002         for(var i = 0, len = this.items.length; i < len; i++){
13003             if(fn.call(scope || window, this.items[i], this.keys[i])){
13004                 return this.items[i];
13005             }
13006         }
13007         return null;
13008     },
13009    
13010 /**
13011  * Inserts an item at the specified index in the collection.
13012  * @param {Number} index The index to insert the item at.
13013  * @param {String} key The key to associate with the new item, or the item itself.
13014  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13015  * @return {Object} The item inserted.
13016  */
13017     insert : function(index, key, o){
13018         if(arguments.length == 2){
13019             o = arguments[1];
13020             key = this.getKey(o);
13021         }
13022         if(index >= this.length){
13023             return this.add(key, o);
13024         }
13025         this.length++;
13026         this.items.splice(index, 0, o);
13027         if(typeof key != "undefined" && key != null){
13028             this.map[key] = o;
13029         }
13030         this.keys.splice(index, 0, key);
13031         this.fireEvent("add", index, o, key);
13032         return o;
13033     },
13034    
13035 /**
13036  * Removed an item from the collection.
13037  * @param {Object} o The item to remove.
13038  * @return {Object} The item removed.
13039  */
13040     remove : function(o){
13041         return this.removeAt(this.indexOf(o));
13042     },
13043    
13044 /**
13045  * Remove an item from a specified index in the collection.
13046  * @param {Number} index The index within the collection of the item to remove.
13047  */
13048     removeAt : function(index){
13049         if(index < this.length && index >= 0){
13050             this.length--;
13051             var o = this.items[index];
13052             this.items.splice(index, 1);
13053             var key = this.keys[index];
13054             if(typeof key != "undefined"){
13055                 delete this.map[key];
13056             }
13057             this.keys.splice(index, 1);
13058             this.fireEvent("remove", o, key);
13059         }
13060     },
13061    
13062 /**
13063  * Removed an item associated with the passed key fom the collection.
13064  * @param {String} key The key of the item to remove.
13065  */
13066     removeKey : function(key){
13067         return this.removeAt(this.indexOfKey(key));
13068     },
13069    
13070 /**
13071  * Returns the number of items in the collection.
13072  * @return {Number} the number of items in the collection.
13073  */
13074     getCount : function(){
13075         return this.length; 
13076     },
13077    
13078 /**
13079  * Returns index within the collection of the passed Object.
13080  * @param {Object} o The item to find the index of.
13081  * @return {Number} index of the item.
13082  */
13083     indexOf : function(o){
13084         if(!this.items.indexOf){
13085             for(var i = 0, len = this.items.length; i < len; i++){
13086                 if(this.items[i] == o) return i;
13087             }
13088             return -1;
13089         }else{
13090             return this.items.indexOf(o);
13091         }
13092     },
13093    
13094 /**
13095  * Returns index within the collection of the passed key.
13096  * @param {String} key The key to find the index of.
13097  * @return {Number} index of the key.
13098  */
13099     indexOfKey : function(key){
13100         if(!this.keys.indexOf){
13101             for(var i = 0, len = this.keys.length; i < len; i++){
13102                 if(this.keys[i] == key) return i;
13103             }
13104             return -1;
13105         }else{
13106             return this.keys.indexOf(key);
13107         }
13108     },
13109    
13110 /**
13111  * Returns the item associated with the passed key OR index. Key has priority over index.
13112  * @param {String/Number} key The key or index of the item.
13113  * @return {Object} The item associated with the passed key.
13114  */
13115     item : function(key){
13116         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13117         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13118     },
13119     
13120 /**
13121  * Returns the item at the specified index.
13122  * @param {Number} index The index of the item.
13123  * @return {Object}
13124  */
13125     itemAt : function(index){
13126         return this.items[index];
13127     },
13128     
13129 /**
13130  * Returns the item associated with the passed key.
13131  * @param {String/Number} key The key of the item.
13132  * @return {Object} The item associated with the passed key.
13133  */
13134     key : function(key){
13135         return this.map[key];
13136     },
13137    
13138 /**
13139  * Returns true if the collection contains the passed Object as an item.
13140  * @param {Object} o  The Object to look for in the collection.
13141  * @return {Boolean} True if the collection contains the Object as an item.
13142  */
13143     contains : function(o){
13144         return this.indexOf(o) != -1;
13145     },
13146    
13147 /**
13148  * Returns true if the collection contains the passed Object as a key.
13149  * @param {String} key The key to look for in the collection.
13150  * @return {Boolean} True if the collection contains the Object as a key.
13151  */
13152     containsKey : function(key){
13153         return typeof this.map[key] != "undefined";
13154     },
13155    
13156 /**
13157  * Removes all items from the collection.
13158  */
13159     clear : function(){
13160         this.length = 0;
13161         this.items = [];
13162         this.keys = [];
13163         this.map = {};
13164         this.fireEvent("clear");
13165     },
13166    
13167 /**
13168  * Returns the first item in the collection.
13169  * @return {Object} the first item in the collection..
13170  */
13171     first : function(){
13172         return this.items[0]; 
13173     },
13174    
13175 /**
13176  * Returns the last item in the collection.
13177  * @return {Object} the last item in the collection..
13178  */
13179     last : function(){
13180         return this.items[this.length-1];   
13181     },
13182     
13183     _sort : function(property, dir, fn){
13184         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13185         fn = fn || function(a, b){
13186             return a-b;
13187         };
13188         var c = [], k = this.keys, items = this.items;
13189         for(var i = 0, len = items.length; i < len; i++){
13190             c[c.length] = {key: k[i], value: items[i], index: i};
13191         }
13192         c.sort(function(a, b){
13193             var v = fn(a[property], b[property]) * dsc;
13194             if(v == 0){
13195                 v = (a.index < b.index ? -1 : 1);
13196             }
13197             return v;
13198         });
13199         for(var i = 0, len = c.length; i < len; i++){
13200             items[i] = c[i].value;
13201             k[i] = c[i].key;
13202         }
13203         this.fireEvent("sort", this);
13204     },
13205     
13206     /**
13207      * Sorts this collection with the passed comparison function
13208      * @param {String} direction (optional) "ASC" or "DESC"
13209      * @param {Function} fn (optional) comparison function
13210      */
13211     sort : function(dir, fn){
13212         this._sort("value", dir, fn);
13213     },
13214     
13215     /**
13216      * Sorts this collection by keys
13217      * @param {String} direction (optional) "ASC" or "DESC"
13218      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13219      */
13220     keySort : function(dir, fn){
13221         this._sort("key", dir, fn || function(a, b){
13222             return String(a).toUpperCase()-String(b).toUpperCase();
13223         });
13224     },
13225     
13226     /**
13227      * Returns a range of items in this collection
13228      * @param {Number} startIndex (optional) defaults to 0
13229      * @param {Number} endIndex (optional) default to the last item
13230      * @return {Array} An array of items
13231      */
13232     getRange : function(start, end){
13233         var items = this.items;
13234         if(items.length < 1){
13235             return [];
13236         }
13237         start = start || 0;
13238         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13239         var r = [];
13240         if(start <= end){
13241             for(var i = start; i <= end; i++) {
13242                     r[r.length] = items[i];
13243             }
13244         }else{
13245             for(var i = start; i >= end; i--) {
13246                     r[r.length] = items[i];
13247             }
13248         }
13249         return r;
13250     },
13251         
13252     /**
13253      * Filter the <i>objects</i> in this collection by a specific property. 
13254      * Returns a new collection that has been filtered.
13255      * @param {String} property A property on your objects
13256      * @param {String/RegExp} value Either string that the property values 
13257      * should start with or a RegExp to test against the property
13258      * @return {MixedCollection} The new filtered collection
13259      */
13260     filter : function(property, value){
13261         if(!value.exec){ // not a regex
13262             value = String(value);
13263             if(value.length == 0){
13264                 return this.clone();
13265             }
13266             value = new RegExp("^" + Roo.escapeRe(value), "i");
13267         }
13268         return this.filterBy(function(o){
13269             return o && value.test(o[property]);
13270         });
13271         },
13272     
13273     /**
13274      * Filter by a function. * Returns a new collection that has been filtered.
13275      * The passed function will be called with each 
13276      * object in the collection. If the function returns true, the value is included 
13277      * otherwise it is filtered.
13278      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13279      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13280      * @return {MixedCollection} The new filtered collection
13281      */
13282     filterBy : function(fn, scope){
13283         var r = new Roo.util.MixedCollection();
13284         r.getKey = this.getKey;
13285         var k = this.keys, it = this.items;
13286         for(var i = 0, len = it.length; i < len; i++){
13287             if(fn.call(scope||this, it[i], k[i])){
13288                                 r.add(k[i], it[i]);
13289                         }
13290         }
13291         return r;
13292     },
13293     
13294     /**
13295      * Creates a duplicate of this collection
13296      * @return {MixedCollection}
13297      */
13298     clone : function(){
13299         var r = new Roo.util.MixedCollection();
13300         var k = this.keys, it = this.items;
13301         for(var i = 0, len = it.length; i < len; i++){
13302             r.add(k[i], it[i]);
13303         }
13304         r.getKey = this.getKey;
13305         return r;
13306     }
13307 });
13308 /**
13309  * Returns the item associated with the passed key or index.
13310  * @method
13311  * @param {String/Number} key The key or index of the item.
13312  * @return {Object} The item associated with the passed key.
13313  */
13314 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13315  * Based on:
13316  * Ext JS Library 1.1.1
13317  * Copyright(c) 2006-2007, Ext JS, LLC.
13318  *
13319  * Originally Released Under LGPL - original licence link has changed is not relivant.
13320  *
13321  * Fork - LGPL
13322  * <script type="text/javascript">
13323  */
13324 /**
13325  * @class Roo.util.JSON
13326  * Modified version of Douglas Crockford"s json.js that doesn"t
13327  * mess with the Object prototype 
13328  * http://www.json.org/js.html
13329  * @singleton
13330  */
13331 Roo.util.JSON = new (function(){
13332     var useHasOwn = {}.hasOwnProperty ? true : false;
13333     
13334     // crashes Safari in some instances
13335     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13336     
13337     var pad = function(n) {
13338         return n < 10 ? "0" + n : n;
13339     };
13340     
13341     var m = {
13342         "\b": '\\b',
13343         "\t": '\\t',
13344         "\n": '\\n',
13345         "\f": '\\f',
13346         "\r": '\\r',
13347         '"' : '\\"',
13348         "\\": '\\\\'
13349     };
13350
13351     var encodeString = function(s){
13352         if (/["\\\x00-\x1f]/.test(s)) {
13353             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13354                 var c = m[b];
13355                 if(c){
13356                     return c;
13357                 }
13358                 c = b.charCodeAt();
13359                 return "\\u00" +
13360                     Math.floor(c / 16).toString(16) +
13361                     (c % 16).toString(16);
13362             }) + '"';
13363         }
13364         return '"' + s + '"';
13365     };
13366     
13367     var encodeArray = function(o){
13368         var a = ["["], b, i, l = o.length, v;
13369             for (i = 0; i < l; i += 1) {
13370                 v = o[i];
13371                 switch (typeof v) {
13372                     case "undefined":
13373                     case "function":
13374                     case "unknown":
13375                         break;
13376                     default:
13377                         if (b) {
13378                             a.push(',');
13379                         }
13380                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13381                         b = true;
13382                 }
13383             }
13384             a.push("]");
13385             return a.join("");
13386     };
13387     
13388     var encodeDate = function(o){
13389         return '"' + o.getFullYear() + "-" +
13390                 pad(o.getMonth() + 1) + "-" +
13391                 pad(o.getDate()) + "T" +
13392                 pad(o.getHours()) + ":" +
13393                 pad(o.getMinutes()) + ":" +
13394                 pad(o.getSeconds()) + '"';
13395     };
13396     
13397     /**
13398      * Encodes an Object, Array or other value
13399      * @param {Mixed} o The variable to encode
13400      * @return {String} The JSON string
13401      */
13402     this.encode = function(o)
13403     {
13404         // should this be extended to fully wrap stringify..
13405         
13406         if(typeof o == "undefined" || o === null){
13407             return "null";
13408         }else if(o instanceof Array){
13409             return encodeArray(o);
13410         }else if(o instanceof Date){
13411             return encodeDate(o);
13412         }else if(typeof o == "string"){
13413             return encodeString(o);
13414         }else if(typeof o == "number"){
13415             return isFinite(o) ? String(o) : "null";
13416         }else if(typeof o == "boolean"){
13417             return String(o);
13418         }else {
13419             var a = ["{"], b, i, v;
13420             for (i in o) {
13421                 if(!useHasOwn || o.hasOwnProperty(i)) {
13422                     v = o[i];
13423                     switch (typeof v) {
13424                     case "undefined":
13425                     case "function":
13426                     case "unknown":
13427                         break;
13428                     default:
13429                         if(b){
13430                             a.push(',');
13431                         }
13432                         a.push(this.encode(i), ":",
13433                                 v === null ? "null" : this.encode(v));
13434                         b = true;
13435                     }
13436                 }
13437             }
13438             a.push("}");
13439             return a.join("");
13440         }
13441     };
13442     
13443     /**
13444      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13445      * @param {String} json The JSON string
13446      * @return {Object} The resulting object
13447      */
13448     this.decode = function(json){
13449         
13450         return  /** eval:var:json */ eval("(" + json + ')');
13451     };
13452 })();
13453 /** 
13454  * Shorthand for {@link Roo.util.JSON#encode}
13455  * @member Roo encode 
13456  * @method */
13457 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13458 /** 
13459  * Shorthand for {@link Roo.util.JSON#decode}
13460  * @member Roo decode 
13461  * @method */
13462 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13463 /*
13464  * Based on:
13465  * Ext JS Library 1.1.1
13466  * Copyright(c) 2006-2007, Ext JS, LLC.
13467  *
13468  * Originally Released Under LGPL - original licence link has changed is not relivant.
13469  *
13470  * Fork - LGPL
13471  * <script type="text/javascript">
13472  */
13473  
13474 /**
13475  * @class Roo.util.Format
13476  * Reusable data formatting functions
13477  * @singleton
13478  */
13479 Roo.util.Format = function(){
13480     var trimRe = /^\s+|\s+$/g;
13481     return {
13482         /**
13483          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13484          * @param {String} value The string to truncate
13485          * @param {Number} length The maximum length to allow before truncating
13486          * @return {String} The converted text
13487          */
13488         ellipsis : function(value, len){
13489             if(value && value.length > len){
13490                 return value.substr(0, len-3)+"...";
13491             }
13492             return value;
13493         },
13494
13495         /**
13496          * Checks a reference and converts it to empty string if it is undefined
13497          * @param {Mixed} value Reference to check
13498          * @return {Mixed} Empty string if converted, otherwise the original value
13499          */
13500         undef : function(value){
13501             return typeof value != "undefined" ? value : "";
13502         },
13503
13504         /**
13505          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13506          * @param {String} value The string to encode
13507          * @return {String} The encoded text
13508          */
13509         htmlEncode : function(value){
13510             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13511         },
13512
13513         /**
13514          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13515          * @param {String} value The string to decode
13516          * @return {String} The decoded text
13517          */
13518         htmlDecode : function(value){
13519             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13520         },
13521
13522         /**
13523          * Trims any whitespace from either side of a string
13524          * @param {String} value The text to trim
13525          * @return {String} The trimmed text
13526          */
13527         trim : function(value){
13528             return String(value).replace(trimRe, "");
13529         },
13530
13531         /**
13532          * Returns a substring from within an original string
13533          * @param {String} value The original text
13534          * @param {Number} start The start index of the substring
13535          * @param {Number} length The length of the substring
13536          * @return {String} The substring
13537          */
13538         substr : function(value, start, length){
13539             return String(value).substr(start, length);
13540         },
13541
13542         /**
13543          * Converts a string to all lower case letters
13544          * @param {String} value The text to convert
13545          * @return {String} The converted text
13546          */
13547         lowercase : function(value){
13548             return String(value).toLowerCase();
13549         },
13550
13551         /**
13552          * Converts a string to all upper case letters
13553          * @param {String} value The text to convert
13554          * @return {String} The converted text
13555          */
13556         uppercase : function(value){
13557             return String(value).toUpperCase();
13558         },
13559
13560         /**
13561          * Converts the first character only of a string to upper case
13562          * @param {String} value The text to convert
13563          * @return {String} The converted text
13564          */
13565         capitalize : function(value){
13566             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13567         },
13568
13569         // private
13570         call : function(value, fn){
13571             if(arguments.length > 2){
13572                 var args = Array.prototype.slice.call(arguments, 2);
13573                 args.unshift(value);
13574                  
13575                 return /** eval:var:value */  eval(fn).apply(window, args);
13576             }else{
13577                 /** eval:var:value */
13578                 return /** eval:var:value */ eval(fn).call(window, value);
13579             }
13580         },
13581
13582        
13583         /**
13584          * safer version of Math.toFixed..??/
13585          * @param {Number/String} value The numeric value to format
13586          * @param {Number/String} value Decimal places 
13587          * @return {String} The formatted currency string
13588          */
13589         toFixed : function(v, n)
13590         {
13591             // why not use to fixed - precision is buggered???
13592             if (!n) {
13593                 return Math.round(v-0);
13594             }
13595             var fact = Math.pow(10,n+1);
13596             v = (Math.round((v-0)*fact))/fact;
13597             var z = (''+fact).substring(2);
13598             if (v == Math.floor(v)) {
13599                 return Math.floor(v) + '.' + z;
13600             }
13601             
13602             // now just padd decimals..
13603             var ps = String(v).split('.');
13604             var fd = (ps[1] + z);
13605             var r = fd.substring(0,n); 
13606             var rm = fd.substring(n); 
13607             if (rm < 5) {
13608                 return ps[0] + '.' + r;
13609             }
13610             r*=1; // turn it into a number;
13611             r++;
13612             if (String(r).length != n) {
13613                 ps[0]*=1;
13614                 ps[0]++;
13615                 r = String(r).substring(1); // chop the end off.
13616             }
13617             
13618             return ps[0] + '.' + r;
13619              
13620         },
13621         
13622         /**
13623          * Format a number as US currency
13624          * @param {Number/String} value The numeric value to format
13625          * @return {String} The formatted currency string
13626          */
13627         usMoney : function(v){
13628             return '$' + Roo.util.Format.number(v);
13629         },
13630         
13631         /**
13632          * Format a number
13633          * eventually this should probably emulate php's number_format
13634          * @param {Number/String} value The numeric value to format
13635          * @param {Number} decimals number of decimal places
13636          * @return {String} The formatted currency string
13637          */
13638         number : function(v,decimals)
13639         {
13640             // multiply and round.
13641             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13642             var mul = Math.pow(10, decimals);
13643             var zero = String(mul).substring(1);
13644             v = (Math.round((v-0)*mul))/mul;
13645             
13646             // if it's '0' number.. then
13647             
13648             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13649             v = String(v);
13650             var ps = v.split('.');
13651             var whole = ps[0];
13652             
13653             
13654             var r = /(\d+)(\d{3})/;
13655             // add comma's
13656             while (r.test(whole)) {
13657                 whole = whole.replace(r, '$1' + ',' + '$2');
13658             }
13659             
13660             
13661             var sub = ps[1] ?
13662                     // has decimals..
13663                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13664                     // does not have decimals
13665                     (decimals ? ('.' + zero) : '');
13666             
13667             
13668             return whole + sub ;
13669         },
13670         
13671         /**
13672          * Parse a value into a formatted date using the specified format pattern.
13673          * @param {Mixed} value The value to format
13674          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13675          * @return {String} The formatted date string
13676          */
13677         date : function(v, format){
13678             if(!v){
13679                 return "";
13680             }
13681             if(!(v instanceof Date)){
13682                 v = new Date(Date.parse(v));
13683             }
13684             return v.dateFormat(format || Roo.util.Format.defaults.date);
13685         },
13686
13687         /**
13688          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13689          * @param {String} format Any valid date format string
13690          * @return {Function} The date formatting function
13691          */
13692         dateRenderer : function(format){
13693             return function(v){
13694                 return Roo.util.Format.date(v, format);  
13695             };
13696         },
13697
13698         // private
13699         stripTagsRE : /<\/?[^>]+>/gi,
13700         
13701         /**
13702          * Strips all HTML tags
13703          * @param {Mixed} value The text from which to strip tags
13704          * @return {String} The stripped text
13705          */
13706         stripTags : function(v){
13707             return !v ? v : String(v).replace(this.stripTagsRE, "");
13708         }
13709     };
13710 }();
13711 Roo.util.Format.defaults = {
13712     date : 'd/M/Y'
13713 };/*
13714  * Based on:
13715  * Ext JS Library 1.1.1
13716  * Copyright(c) 2006-2007, Ext JS, LLC.
13717  *
13718  * Originally Released Under LGPL - original licence link has changed is not relivant.
13719  *
13720  * Fork - LGPL
13721  * <script type="text/javascript">
13722  */
13723
13724
13725  
13726
13727 /**
13728  * @class Roo.MasterTemplate
13729  * @extends Roo.Template
13730  * Provides a template that can have child templates. The syntax is:
13731 <pre><code>
13732 var t = new Roo.MasterTemplate(
13733         '&lt;select name="{name}"&gt;',
13734                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13735         '&lt;/select&gt;'
13736 );
13737 t.add('options', {value: 'foo', text: 'bar'});
13738 // or you can add multiple child elements in one shot
13739 t.addAll('options', [
13740     {value: 'foo', text: 'bar'},
13741     {value: 'foo2', text: 'bar2'},
13742     {value: 'foo3', text: 'bar3'}
13743 ]);
13744 // then append, applying the master template values
13745 t.append('my-form', {name: 'my-select'});
13746 </code></pre>
13747 * A name attribute for the child template is not required if you have only one child
13748 * template or you want to refer to them by index.
13749  */
13750 Roo.MasterTemplate = function(){
13751     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13752     this.originalHtml = this.html;
13753     var st = {};
13754     var m, re = this.subTemplateRe;
13755     re.lastIndex = 0;
13756     var subIndex = 0;
13757     while(m = re.exec(this.html)){
13758         var name = m[1], content = m[2];
13759         st[subIndex] = {
13760             name: name,
13761             index: subIndex,
13762             buffer: [],
13763             tpl : new Roo.Template(content)
13764         };
13765         if(name){
13766             st[name] = st[subIndex];
13767         }
13768         st[subIndex].tpl.compile();
13769         st[subIndex].tpl.call = this.call.createDelegate(this);
13770         subIndex++;
13771     }
13772     this.subCount = subIndex;
13773     this.subs = st;
13774 };
13775 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13776     /**
13777     * The regular expression used to match sub templates
13778     * @type RegExp
13779     * @property
13780     */
13781     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13782
13783     /**
13784      * Applies the passed values to a child template.
13785      * @param {String/Number} name (optional) The name or index of the child template
13786      * @param {Array/Object} values The values to be applied to the template
13787      * @return {MasterTemplate} this
13788      */
13789      add : function(name, values){
13790         if(arguments.length == 1){
13791             values = arguments[0];
13792             name = 0;
13793         }
13794         var s = this.subs[name];
13795         s.buffer[s.buffer.length] = s.tpl.apply(values);
13796         return this;
13797     },
13798
13799     /**
13800      * Applies all the passed values to a child template.
13801      * @param {String/Number} name (optional) The name or index of the child template
13802      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13803      * @param {Boolean} reset (optional) True to reset the template first
13804      * @return {MasterTemplate} this
13805      */
13806     fill : function(name, values, reset){
13807         var a = arguments;
13808         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13809             values = a[0];
13810             name = 0;
13811             reset = a[1];
13812         }
13813         if(reset){
13814             this.reset();
13815         }
13816         for(var i = 0, len = values.length; i < len; i++){
13817             this.add(name, values[i]);
13818         }
13819         return this;
13820     },
13821
13822     /**
13823      * Resets the template for reuse
13824      * @return {MasterTemplate} this
13825      */
13826      reset : function(){
13827         var s = this.subs;
13828         for(var i = 0; i < this.subCount; i++){
13829             s[i].buffer = [];
13830         }
13831         return this;
13832     },
13833
13834     applyTemplate : function(values){
13835         var s = this.subs;
13836         var replaceIndex = -1;
13837         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13838             return s[++replaceIndex].buffer.join("");
13839         });
13840         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13841     },
13842
13843     apply : function(){
13844         return this.applyTemplate.apply(this, arguments);
13845     },
13846
13847     compile : function(){return this;}
13848 });
13849
13850 /**
13851  * Alias for fill().
13852  * @method
13853  */
13854 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13855  /**
13856  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13857  * var tpl = Roo.MasterTemplate.from('element-id');
13858  * @param {String/HTMLElement} el
13859  * @param {Object} config
13860  * @static
13861  */
13862 Roo.MasterTemplate.from = function(el, config){
13863     el = Roo.getDom(el);
13864     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13865 };/*
13866  * Based on:
13867  * Ext JS Library 1.1.1
13868  * Copyright(c) 2006-2007, Ext JS, LLC.
13869  *
13870  * Originally Released Under LGPL - original licence link has changed is not relivant.
13871  *
13872  * Fork - LGPL
13873  * <script type="text/javascript">
13874  */
13875
13876  
13877 /**
13878  * @class Roo.util.CSS
13879  * Utility class for manipulating CSS rules
13880  * @singleton
13881  */
13882 Roo.util.CSS = function(){
13883         var rules = null;
13884         var doc = document;
13885
13886     var camelRe = /(-[a-z])/gi;
13887     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13888
13889    return {
13890    /**
13891     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13892     * tag and appended to the HEAD of the document.
13893     * @param {String|Object} cssText The text containing the css rules
13894     * @param {String} id An id to add to the stylesheet for later removal
13895     * @return {StyleSheet}
13896     */
13897     createStyleSheet : function(cssText, id){
13898         var ss;
13899         var head = doc.getElementsByTagName("head")[0];
13900         var nrules = doc.createElement("style");
13901         nrules.setAttribute("type", "text/css");
13902         if(id){
13903             nrules.setAttribute("id", id);
13904         }
13905         if (typeof(cssText) != 'string') {
13906             // support object maps..
13907             // not sure if this a good idea.. 
13908             // perhaps it should be merged with the general css handling
13909             // and handle js style props.
13910             var cssTextNew = [];
13911             for(var n in cssText) {
13912                 var citems = [];
13913                 for(var k in cssText[n]) {
13914                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13915                 }
13916                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13917                 
13918             }
13919             cssText = cssTextNew.join("\n");
13920             
13921         }
13922        
13923        
13924        if(Roo.isIE){
13925            head.appendChild(nrules);
13926            ss = nrules.styleSheet;
13927            ss.cssText = cssText;
13928        }else{
13929            try{
13930                 nrules.appendChild(doc.createTextNode(cssText));
13931            }catch(e){
13932                nrules.cssText = cssText; 
13933            }
13934            head.appendChild(nrules);
13935            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13936        }
13937        this.cacheStyleSheet(ss);
13938        return ss;
13939    },
13940
13941    /**
13942     * Removes a style or link tag by id
13943     * @param {String} id The id of the tag
13944     */
13945    removeStyleSheet : function(id){
13946        var existing = doc.getElementById(id);
13947        if(existing){
13948            existing.parentNode.removeChild(existing);
13949        }
13950    },
13951
13952    /**
13953     * Dynamically swaps an existing stylesheet reference for a new one
13954     * @param {String} id The id of an existing link tag to remove
13955     * @param {String} url The href of the new stylesheet to include
13956     */
13957    swapStyleSheet : function(id, url){
13958        this.removeStyleSheet(id);
13959        var ss = doc.createElement("link");
13960        ss.setAttribute("rel", "stylesheet");
13961        ss.setAttribute("type", "text/css");
13962        ss.setAttribute("id", id);
13963        ss.setAttribute("href", url);
13964        doc.getElementsByTagName("head")[0].appendChild(ss);
13965    },
13966    
13967    /**
13968     * Refresh the rule cache if you have dynamically added stylesheets
13969     * @return {Object} An object (hash) of rules indexed by selector
13970     */
13971    refreshCache : function(){
13972        return this.getRules(true);
13973    },
13974
13975    // private
13976    cacheStyleSheet : function(stylesheet){
13977        if(!rules){
13978            rules = {};
13979        }
13980        try{// try catch for cross domain access issue
13981            var ssRules = stylesheet.cssRules || stylesheet.rules;
13982            for(var j = ssRules.length-1; j >= 0; --j){
13983                rules[ssRules[j].selectorText] = ssRules[j];
13984            }
13985        }catch(e){}
13986    },
13987    
13988    /**
13989     * Gets all css rules for the document
13990     * @param {Boolean} refreshCache true to refresh the internal cache
13991     * @return {Object} An object (hash) of rules indexed by selector
13992     */
13993    getRules : function(refreshCache){
13994                 if(rules == null || refreshCache){
13995                         rules = {};
13996                         var ds = doc.styleSheets;
13997                         for(var i =0, len = ds.length; i < len; i++){
13998                             try{
13999                         this.cacheStyleSheet(ds[i]);
14000                     }catch(e){} 
14001                 }
14002                 }
14003                 return rules;
14004         },
14005         
14006         /**
14007     * Gets an an individual CSS rule by selector(s)
14008     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14009     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14010     * @return {CSSRule} The CSS rule or null if one is not found
14011     */
14012    getRule : function(selector, refreshCache){
14013                 var rs = this.getRules(refreshCache);
14014                 if(!(selector instanceof Array)){
14015                     return rs[selector];
14016                 }
14017                 for(var i = 0; i < selector.length; i++){
14018                         if(rs[selector[i]]){
14019                                 return rs[selector[i]];
14020                         }
14021                 }
14022                 return null;
14023         },
14024         
14025         
14026         /**
14027     * Updates a rule property
14028     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14029     * @param {String} property The css property
14030     * @param {String} value The new value for the property
14031     * @return {Boolean} true If a rule was found and updated
14032     */
14033    updateRule : function(selector, property, value){
14034                 if(!(selector instanceof Array)){
14035                         var rule = this.getRule(selector);
14036                         if(rule){
14037                                 rule.style[property.replace(camelRe, camelFn)] = value;
14038                                 return true;
14039                         }
14040                 }else{
14041                         for(var i = 0; i < selector.length; i++){
14042                                 if(this.updateRule(selector[i], property, value)){
14043                                         return true;
14044                                 }
14045                         }
14046                 }
14047                 return false;
14048         }
14049    };   
14050 }();/*
14051  * Based on:
14052  * Ext JS Library 1.1.1
14053  * Copyright(c) 2006-2007, Ext JS, LLC.
14054  *
14055  * Originally Released Under LGPL - original licence link has changed is not relivant.
14056  *
14057  * Fork - LGPL
14058  * <script type="text/javascript">
14059  */
14060
14061  
14062
14063 /**
14064  * @class Roo.util.ClickRepeater
14065  * @extends Roo.util.Observable
14066  * 
14067  * A wrapper class which can be applied to any element. Fires a "click" event while the
14068  * mouse is pressed. The interval between firings may be specified in the config but
14069  * defaults to 10 milliseconds.
14070  * 
14071  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14072  * 
14073  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14074  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14075  * Similar to an autorepeat key delay.
14076  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14077  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14078  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14079  *           "interval" and "delay" are ignored. "immediate" is honored.
14080  * @cfg {Boolean} preventDefault True to prevent the default click event
14081  * @cfg {Boolean} stopDefault True to stop the default click event
14082  * 
14083  * @history
14084  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14085  *     2007-02-02 jvs Renamed to ClickRepeater
14086  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14087  *
14088  *  @constructor
14089  * @param {String/HTMLElement/Element} el The element to listen on
14090  * @param {Object} config
14091  **/
14092 Roo.util.ClickRepeater = function(el, config)
14093 {
14094     this.el = Roo.get(el);
14095     this.el.unselectable();
14096
14097     Roo.apply(this, config);
14098
14099     this.addEvents({
14100     /**
14101      * @event mousedown
14102      * Fires when the mouse button is depressed.
14103      * @param {Roo.util.ClickRepeater} this
14104      */
14105         "mousedown" : true,
14106     /**
14107      * @event click
14108      * Fires on a specified interval during the time the element is pressed.
14109      * @param {Roo.util.ClickRepeater} this
14110      */
14111         "click" : true,
14112     /**
14113      * @event mouseup
14114      * Fires when the mouse key is released.
14115      * @param {Roo.util.ClickRepeater} this
14116      */
14117         "mouseup" : true
14118     });
14119
14120     this.el.on("mousedown", this.handleMouseDown, this);
14121     if(this.preventDefault || this.stopDefault){
14122         this.el.on("click", function(e){
14123             if(this.preventDefault){
14124                 e.preventDefault();
14125             }
14126             if(this.stopDefault){
14127                 e.stopEvent();
14128             }
14129         }, this);
14130     }
14131
14132     // allow inline handler
14133     if(this.handler){
14134         this.on("click", this.handler,  this.scope || this);
14135     }
14136
14137     Roo.util.ClickRepeater.superclass.constructor.call(this);
14138 };
14139
14140 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14141     interval : 20,
14142     delay: 250,
14143     preventDefault : true,
14144     stopDefault : false,
14145     timer : 0,
14146
14147     // private
14148     handleMouseDown : function(){
14149         clearTimeout(this.timer);
14150         this.el.blur();
14151         if(this.pressClass){
14152             this.el.addClass(this.pressClass);
14153         }
14154         this.mousedownTime = new Date();
14155
14156         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14157         this.el.on("mouseout", this.handleMouseOut, this);
14158
14159         this.fireEvent("mousedown", this);
14160         this.fireEvent("click", this);
14161         
14162         this.timer = this.click.defer(this.delay || this.interval, this);
14163     },
14164
14165     // private
14166     click : function(){
14167         this.fireEvent("click", this);
14168         this.timer = this.click.defer(this.getInterval(), this);
14169     },
14170
14171     // private
14172     getInterval: function(){
14173         if(!this.accelerate){
14174             return this.interval;
14175         }
14176         var pressTime = this.mousedownTime.getElapsed();
14177         if(pressTime < 500){
14178             return 400;
14179         }else if(pressTime < 1700){
14180             return 320;
14181         }else if(pressTime < 2600){
14182             return 250;
14183         }else if(pressTime < 3500){
14184             return 180;
14185         }else if(pressTime < 4400){
14186             return 140;
14187         }else if(pressTime < 5300){
14188             return 80;
14189         }else if(pressTime < 6200){
14190             return 50;
14191         }else{
14192             return 10;
14193         }
14194     },
14195
14196     // private
14197     handleMouseOut : function(){
14198         clearTimeout(this.timer);
14199         if(this.pressClass){
14200             this.el.removeClass(this.pressClass);
14201         }
14202         this.el.on("mouseover", this.handleMouseReturn, this);
14203     },
14204
14205     // private
14206     handleMouseReturn : function(){
14207         this.el.un("mouseover", this.handleMouseReturn);
14208         if(this.pressClass){
14209             this.el.addClass(this.pressClass);
14210         }
14211         this.click();
14212     },
14213
14214     // private
14215     handleMouseUp : function(){
14216         clearTimeout(this.timer);
14217         this.el.un("mouseover", this.handleMouseReturn);
14218         this.el.un("mouseout", this.handleMouseOut);
14219         Roo.get(document).un("mouseup", this.handleMouseUp);
14220         this.el.removeClass(this.pressClass);
14221         this.fireEvent("mouseup", this);
14222     }
14223 });/*
14224  * Based on:
14225  * Ext JS Library 1.1.1
14226  * Copyright(c) 2006-2007, Ext JS, LLC.
14227  *
14228  * Originally Released Under LGPL - original licence link has changed is not relivant.
14229  *
14230  * Fork - LGPL
14231  * <script type="text/javascript">
14232  */
14233
14234  
14235 /**
14236  * @class Roo.KeyNav
14237  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14238  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14239  * way to implement custom navigation schemes for any UI component.</p>
14240  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14241  * pageUp, pageDown, del, home, end.  Usage:</p>
14242  <pre><code>
14243 var nav = new Roo.KeyNav("my-element", {
14244     "left" : function(e){
14245         this.moveLeft(e.ctrlKey);
14246     },
14247     "right" : function(e){
14248         this.moveRight(e.ctrlKey);
14249     },
14250     "enter" : function(e){
14251         this.save();
14252     },
14253     scope : this
14254 });
14255 </code></pre>
14256  * @constructor
14257  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14258  * @param {Object} config The config
14259  */
14260 Roo.KeyNav = function(el, config){
14261     this.el = Roo.get(el);
14262     Roo.apply(this, config);
14263     if(!this.disabled){
14264         this.disabled = true;
14265         this.enable();
14266     }
14267 };
14268
14269 Roo.KeyNav.prototype = {
14270     /**
14271      * @cfg {Boolean} disabled
14272      * True to disable this KeyNav instance (defaults to false)
14273      */
14274     disabled : false,
14275     /**
14276      * @cfg {String} defaultEventAction
14277      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14278      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14279      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14280      */
14281     defaultEventAction: "stopEvent",
14282     /**
14283      * @cfg {Boolean} forceKeyDown
14284      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14285      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14286      * handle keydown instead of keypress.
14287      */
14288     forceKeyDown : false,
14289
14290     // private
14291     prepareEvent : function(e){
14292         var k = e.getKey();
14293         var h = this.keyToHandler[k];
14294         //if(h && this[h]){
14295         //    e.stopPropagation();
14296         //}
14297         if(Roo.isSafari && h && k >= 37 && k <= 40){
14298             e.stopEvent();
14299         }
14300     },
14301
14302     // private
14303     relay : function(e){
14304         var k = e.getKey();
14305         var h = this.keyToHandler[k];
14306         if(h && this[h]){
14307             if(this.doRelay(e, this[h], h) !== true){
14308                 e[this.defaultEventAction]();
14309             }
14310         }
14311     },
14312
14313     // private
14314     doRelay : function(e, h, hname){
14315         return h.call(this.scope || this, e);
14316     },
14317
14318     // possible handlers
14319     enter : false,
14320     left : false,
14321     right : false,
14322     up : false,
14323     down : false,
14324     tab : false,
14325     esc : false,
14326     pageUp : false,
14327     pageDown : false,
14328     del : false,
14329     home : false,
14330     end : false,
14331
14332     // quick lookup hash
14333     keyToHandler : {
14334         37 : "left",
14335         39 : "right",
14336         38 : "up",
14337         40 : "down",
14338         33 : "pageUp",
14339         34 : "pageDown",
14340         46 : "del",
14341         36 : "home",
14342         35 : "end",
14343         13 : "enter",
14344         27 : "esc",
14345         9  : "tab"
14346     },
14347
14348         /**
14349          * Enable this KeyNav
14350          */
14351         enable: function(){
14352                 if(this.disabled){
14353             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14354             // the EventObject will normalize Safari automatically
14355             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14356                 this.el.on("keydown", this.relay,  this);
14357             }else{
14358                 this.el.on("keydown", this.prepareEvent,  this);
14359                 this.el.on("keypress", this.relay,  this);
14360             }
14361                     this.disabled = false;
14362                 }
14363         },
14364
14365         /**
14366          * Disable this KeyNav
14367          */
14368         disable: function(){
14369                 if(!this.disabled){
14370                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14371                 this.el.un("keydown", this.relay);
14372             }else{
14373                 this.el.un("keydown", this.prepareEvent);
14374                 this.el.un("keypress", this.relay);
14375             }
14376                     this.disabled = true;
14377                 }
14378         }
14379 };/*
14380  * Based on:
14381  * Ext JS Library 1.1.1
14382  * Copyright(c) 2006-2007, Ext JS, LLC.
14383  *
14384  * Originally Released Under LGPL - original licence link has changed is not relivant.
14385  *
14386  * Fork - LGPL
14387  * <script type="text/javascript">
14388  */
14389
14390  
14391 /**
14392  * @class Roo.KeyMap
14393  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14394  * The constructor accepts the same config object as defined by {@link #addBinding}.
14395  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14396  * combination it will call the function with this signature (if the match is a multi-key
14397  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14398  * A KeyMap can also handle a string representation of keys.<br />
14399  * Usage:
14400  <pre><code>
14401 // map one key by key code
14402 var map = new Roo.KeyMap("my-element", {
14403     key: 13, // or Roo.EventObject.ENTER
14404     fn: myHandler,
14405     scope: myObject
14406 });
14407
14408 // map multiple keys to one action by string
14409 var map = new Roo.KeyMap("my-element", {
14410     key: "a\r\n\t",
14411     fn: myHandler,
14412     scope: myObject
14413 });
14414
14415 // map multiple keys to multiple actions by strings and array of codes
14416 var map = new Roo.KeyMap("my-element", [
14417     {
14418         key: [10,13],
14419         fn: function(){ alert("Return was pressed"); }
14420     }, {
14421         key: "abc",
14422         fn: function(){ alert('a, b or c was pressed'); }
14423     }, {
14424         key: "\t",
14425         ctrl:true,
14426         shift:true,
14427         fn: function(){ alert('Control + shift + tab was pressed.'); }
14428     }
14429 ]);
14430 </code></pre>
14431  * <b>Note: A KeyMap starts enabled</b>
14432  * @constructor
14433  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14434  * @param {Object} config The config (see {@link #addBinding})
14435  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14436  */
14437 Roo.KeyMap = function(el, config, eventName){
14438     this.el  = Roo.get(el);
14439     this.eventName = eventName || "keydown";
14440     this.bindings = [];
14441     if(config){
14442         this.addBinding(config);
14443     }
14444     this.enable();
14445 };
14446
14447 Roo.KeyMap.prototype = {
14448     /**
14449      * True to stop the event from bubbling and prevent the default browser action if the
14450      * key was handled by the KeyMap (defaults to false)
14451      * @type Boolean
14452      */
14453     stopEvent : false,
14454
14455     /**
14456      * Add a new binding to this KeyMap. The following config object properties are supported:
14457      * <pre>
14458 Property    Type             Description
14459 ----------  ---------------  ----------------------------------------------------------------------
14460 key         String/Array     A single keycode or an array of keycodes to handle
14461 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14462 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14463 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14464 fn          Function         The function to call when KeyMap finds the expected key combination
14465 scope       Object           The scope of the callback function
14466 </pre>
14467      *
14468      * Usage:
14469      * <pre><code>
14470 // Create a KeyMap
14471 var map = new Roo.KeyMap(document, {
14472     key: Roo.EventObject.ENTER,
14473     fn: handleKey,
14474     scope: this
14475 });
14476
14477 //Add a new binding to the existing KeyMap later
14478 map.addBinding({
14479     key: 'abc',
14480     shift: true,
14481     fn: handleKey,
14482     scope: this
14483 });
14484 </code></pre>
14485      * @param {Object/Array} config A single KeyMap config or an array of configs
14486      */
14487         addBinding : function(config){
14488         if(config instanceof Array){
14489             for(var i = 0, len = config.length; i < len; i++){
14490                 this.addBinding(config[i]);
14491             }
14492             return;
14493         }
14494         var keyCode = config.key,
14495             shift = config.shift, 
14496             ctrl = config.ctrl, 
14497             alt = config.alt,
14498             fn = config.fn,
14499             scope = config.scope;
14500         if(typeof keyCode == "string"){
14501             var ks = [];
14502             var keyString = keyCode.toUpperCase();
14503             for(var j = 0, len = keyString.length; j < len; j++){
14504                 ks.push(keyString.charCodeAt(j));
14505             }
14506             keyCode = ks;
14507         }
14508         var keyArray = keyCode instanceof Array;
14509         var handler = function(e){
14510             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14511                 var k = e.getKey();
14512                 if(keyArray){
14513                     for(var i = 0, len = keyCode.length; i < len; i++){
14514                         if(keyCode[i] == k){
14515                           if(this.stopEvent){
14516                               e.stopEvent();
14517                           }
14518                           fn.call(scope || window, k, e);
14519                           return;
14520                         }
14521                     }
14522                 }else{
14523                     if(k == keyCode){
14524                         if(this.stopEvent){
14525                            e.stopEvent();
14526                         }
14527                         fn.call(scope || window, k, e);
14528                     }
14529                 }
14530             }
14531         };
14532         this.bindings.push(handler);  
14533         },
14534
14535     /**
14536      * Shorthand for adding a single key listener
14537      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14538      * following options:
14539      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14540      * @param {Function} fn The function to call
14541      * @param {Object} scope (optional) The scope of the function
14542      */
14543     on : function(key, fn, scope){
14544         var keyCode, shift, ctrl, alt;
14545         if(typeof key == "object" && !(key instanceof Array)){
14546             keyCode = key.key;
14547             shift = key.shift;
14548             ctrl = key.ctrl;
14549             alt = key.alt;
14550         }else{
14551             keyCode = key;
14552         }
14553         this.addBinding({
14554             key: keyCode,
14555             shift: shift,
14556             ctrl: ctrl,
14557             alt: alt,
14558             fn: fn,
14559             scope: scope
14560         })
14561     },
14562
14563     // private
14564     handleKeyDown : function(e){
14565             if(this.enabled){ //just in case
14566             var b = this.bindings;
14567             for(var i = 0, len = b.length; i < len; i++){
14568                 b[i].call(this, e);
14569             }
14570             }
14571         },
14572         
14573         /**
14574          * Returns true if this KeyMap is enabled
14575          * @return {Boolean} 
14576          */
14577         isEnabled : function(){
14578             return this.enabled;  
14579         },
14580         
14581         /**
14582          * Enables this KeyMap
14583          */
14584         enable: function(){
14585                 if(!this.enabled){
14586                     this.el.on(this.eventName, this.handleKeyDown, this);
14587                     this.enabled = true;
14588                 }
14589         },
14590
14591         /**
14592          * Disable this KeyMap
14593          */
14594         disable: function(){
14595                 if(this.enabled){
14596                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14597                     this.enabled = false;
14598                 }
14599         }
14600 };/*
14601  * Based on:
14602  * Ext JS Library 1.1.1
14603  * Copyright(c) 2006-2007, Ext JS, LLC.
14604  *
14605  * Originally Released Under LGPL - original licence link has changed is not relivant.
14606  *
14607  * Fork - LGPL
14608  * <script type="text/javascript">
14609  */
14610
14611  
14612 /**
14613  * @class Roo.util.TextMetrics
14614  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14615  * wide, in pixels, a given block of text will be.
14616  * @singleton
14617  */
14618 Roo.util.TextMetrics = function(){
14619     var shared;
14620     return {
14621         /**
14622          * Measures the size of the specified text
14623          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14624          * that can affect the size of the rendered text
14625          * @param {String} text The text to measure
14626          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14627          * in order to accurately measure the text height
14628          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14629          */
14630         measure : function(el, text, fixedWidth){
14631             if(!shared){
14632                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14633             }
14634             shared.bind(el);
14635             shared.setFixedWidth(fixedWidth || 'auto');
14636             return shared.getSize(text);
14637         },
14638
14639         /**
14640          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14641          * the overhead of multiple calls to initialize the style properties on each measurement.
14642          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14643          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14644          * in order to accurately measure the text height
14645          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14646          */
14647         createInstance : function(el, fixedWidth){
14648             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14649         }
14650     };
14651 }();
14652
14653  
14654
14655 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14656     var ml = new Roo.Element(document.createElement('div'));
14657     document.body.appendChild(ml.dom);
14658     ml.position('absolute');
14659     ml.setLeftTop(-1000, -1000);
14660     ml.hide();
14661
14662     if(fixedWidth){
14663         ml.setWidth(fixedWidth);
14664     }
14665      
14666     var instance = {
14667         /**
14668          * Returns the size of the specified text based on the internal element's style and width properties
14669          * @memberOf Roo.util.TextMetrics.Instance#
14670          * @param {String} text The text to measure
14671          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14672          */
14673         getSize : function(text){
14674             ml.update(text);
14675             var s = ml.getSize();
14676             ml.update('');
14677             return s;
14678         },
14679
14680         /**
14681          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14682          * that can affect the size of the rendered text
14683          * @memberOf Roo.util.TextMetrics.Instance#
14684          * @param {String/HTMLElement} el The element, dom node or id
14685          */
14686         bind : function(el){
14687             ml.setStyle(
14688                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14689             );
14690         },
14691
14692         /**
14693          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14694          * to set a fixed width in order to accurately measure the text height.
14695          * @memberOf Roo.util.TextMetrics.Instance#
14696          * @param {Number} width The width to set on the element
14697          */
14698         setFixedWidth : function(width){
14699             ml.setWidth(width);
14700         },
14701
14702         /**
14703          * Returns the measured width of the specified text
14704          * @memberOf Roo.util.TextMetrics.Instance#
14705          * @param {String} text The text to measure
14706          * @return {Number} width The width in pixels
14707          */
14708         getWidth : function(text){
14709             ml.dom.style.width = 'auto';
14710             return this.getSize(text).width;
14711         },
14712
14713         /**
14714          * Returns the measured height of the specified text.  For multiline text, be sure to call
14715          * {@link #setFixedWidth} if necessary.
14716          * @memberOf Roo.util.TextMetrics.Instance#
14717          * @param {String} text The text to measure
14718          * @return {Number} height The height in pixels
14719          */
14720         getHeight : function(text){
14721             return this.getSize(text).height;
14722         }
14723     };
14724
14725     instance.bind(bindTo);
14726
14727     return instance;
14728 };
14729
14730 // backwards compat
14731 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14732  * Based on:
14733  * Ext JS Library 1.1.1
14734  * Copyright(c) 2006-2007, Ext JS, LLC.
14735  *
14736  * Originally Released Under LGPL - original licence link has changed is not relivant.
14737  *
14738  * Fork - LGPL
14739  * <script type="text/javascript">
14740  */
14741
14742 /**
14743  * @class Roo.state.Provider
14744  * Abstract base class for state provider implementations. This class provides methods
14745  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14746  * Provider interface.
14747  */
14748 Roo.state.Provider = function(){
14749     /**
14750      * @event statechange
14751      * Fires when a state change occurs.
14752      * @param {Provider} this This state provider
14753      * @param {String} key The state key which was changed
14754      * @param {String} value The encoded value for the state
14755      */
14756     this.addEvents({
14757         "statechange": true
14758     });
14759     this.state = {};
14760     Roo.state.Provider.superclass.constructor.call(this);
14761 };
14762 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14763     /**
14764      * Returns the current value for a key
14765      * @param {String} name The key name
14766      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14767      * @return {Mixed} The state data
14768      */
14769     get : function(name, defaultValue){
14770         return typeof this.state[name] == "undefined" ?
14771             defaultValue : this.state[name];
14772     },
14773     
14774     /**
14775      * Clears a value from the state
14776      * @param {String} name The key name
14777      */
14778     clear : function(name){
14779         delete this.state[name];
14780         this.fireEvent("statechange", this, name, null);
14781     },
14782     
14783     /**
14784      * Sets the value for a key
14785      * @param {String} name The key name
14786      * @param {Mixed} value The value to set
14787      */
14788     set : function(name, value){
14789         this.state[name] = value;
14790         this.fireEvent("statechange", this, name, value);
14791     },
14792     
14793     /**
14794      * Decodes a string previously encoded with {@link #encodeValue}.
14795      * @param {String} value The value to decode
14796      * @return {Mixed} The decoded value
14797      */
14798     decodeValue : function(cookie){
14799         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14800         var matches = re.exec(unescape(cookie));
14801         if(!matches || !matches[1]) return; // non state cookie
14802         var type = matches[1];
14803         var v = matches[2];
14804         switch(type){
14805             case "n":
14806                 return parseFloat(v);
14807             case "d":
14808                 return new Date(Date.parse(v));
14809             case "b":
14810                 return (v == "1");
14811             case "a":
14812                 var all = [];
14813                 var values = v.split("^");
14814                 for(var i = 0, len = values.length; i < len; i++){
14815                     all.push(this.decodeValue(values[i]));
14816                 }
14817                 return all;
14818            case "o":
14819                 var all = {};
14820                 var values = v.split("^");
14821                 for(var i = 0, len = values.length; i < len; i++){
14822                     var kv = values[i].split("=");
14823                     all[kv[0]] = this.decodeValue(kv[1]);
14824                 }
14825                 return all;
14826            default:
14827                 return v;
14828         }
14829     },
14830     
14831     /**
14832      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14833      * @param {Mixed} value The value to encode
14834      * @return {String} The encoded value
14835      */
14836     encodeValue : function(v){
14837         var enc;
14838         if(typeof v == "number"){
14839             enc = "n:" + v;
14840         }else if(typeof v == "boolean"){
14841             enc = "b:" + (v ? "1" : "0");
14842         }else if(v instanceof Date){
14843             enc = "d:" + v.toGMTString();
14844         }else if(v instanceof Array){
14845             var flat = "";
14846             for(var i = 0, len = v.length; i < len; i++){
14847                 flat += this.encodeValue(v[i]);
14848                 if(i != len-1) flat += "^";
14849             }
14850             enc = "a:" + flat;
14851         }else if(typeof v == "object"){
14852             var flat = "";
14853             for(var key in v){
14854                 if(typeof v[key] != "function"){
14855                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14856                 }
14857             }
14858             enc = "o:" + flat.substring(0, flat.length-1);
14859         }else{
14860             enc = "s:" + v;
14861         }
14862         return escape(enc);        
14863     }
14864 });
14865
14866 /*
14867  * Based on:
14868  * Ext JS Library 1.1.1
14869  * Copyright(c) 2006-2007, Ext JS, LLC.
14870  *
14871  * Originally Released Under LGPL - original licence link has changed is not relivant.
14872  *
14873  * Fork - LGPL
14874  * <script type="text/javascript">
14875  */
14876 /**
14877  * @class Roo.state.Manager
14878  * This is the global state manager. By default all components that are "state aware" check this class
14879  * for state information if you don't pass them a custom state provider. In order for this class
14880  * to be useful, it must be initialized with a provider when your application initializes.
14881  <pre><code>
14882 // in your initialization function
14883 init : function(){
14884    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14885    ...
14886    // supposed you have a {@link Roo.BorderLayout}
14887    var layout = new Roo.BorderLayout(...);
14888    layout.restoreState();
14889    // or a {Roo.BasicDialog}
14890    var dialog = new Roo.BasicDialog(...);
14891    dialog.restoreState();
14892  </code></pre>
14893  * @singleton
14894  */
14895 Roo.state.Manager = function(){
14896     var provider = new Roo.state.Provider();
14897     
14898     return {
14899         /**
14900          * Configures the default state provider for your application
14901          * @param {Provider} stateProvider The state provider to set
14902          */
14903         setProvider : function(stateProvider){
14904             provider = stateProvider;
14905         },
14906         
14907         /**
14908          * Returns the current value for a key
14909          * @param {String} name The key name
14910          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14911          * @return {Mixed} The state data
14912          */
14913         get : function(key, defaultValue){
14914             return provider.get(key, defaultValue);
14915         },
14916         
14917         /**
14918          * Sets the value for a key
14919          * @param {String} name The key name
14920          * @param {Mixed} value The state data
14921          */
14922          set : function(key, value){
14923             provider.set(key, value);
14924         },
14925         
14926         /**
14927          * Clears a value from the state
14928          * @param {String} name The key name
14929          */
14930         clear : function(key){
14931             provider.clear(key);
14932         },
14933         
14934         /**
14935          * Gets the currently configured state provider
14936          * @return {Provider} The state provider
14937          */
14938         getProvider : function(){
14939             return provider;
14940         }
14941     };
14942 }();
14943 /*
14944  * Based on:
14945  * Ext JS Library 1.1.1
14946  * Copyright(c) 2006-2007, Ext JS, LLC.
14947  *
14948  * Originally Released Under LGPL - original licence link has changed is not relivant.
14949  *
14950  * Fork - LGPL
14951  * <script type="text/javascript">
14952  */
14953 /**
14954  * @class Roo.state.CookieProvider
14955  * @extends Roo.state.Provider
14956  * The default Provider implementation which saves state via cookies.
14957  * <br />Usage:
14958  <pre><code>
14959    var cp = new Roo.state.CookieProvider({
14960        path: "/cgi-bin/",
14961        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14962        domain: "roojs.com"
14963    })
14964    Roo.state.Manager.setProvider(cp);
14965  </code></pre>
14966  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14967  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14968  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14969  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14970  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14971  * domain the page is running on including the 'www' like 'www.roojs.com')
14972  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14973  * @constructor
14974  * Create a new CookieProvider
14975  * @param {Object} config The configuration object
14976  */
14977 Roo.state.CookieProvider = function(config){
14978     Roo.state.CookieProvider.superclass.constructor.call(this);
14979     this.path = "/";
14980     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14981     this.domain = null;
14982     this.secure = false;
14983     Roo.apply(this, config);
14984     this.state = this.readCookies();
14985 };
14986
14987 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14988     // private
14989     set : function(name, value){
14990         if(typeof value == "undefined" || value === null){
14991             this.clear(name);
14992             return;
14993         }
14994         this.setCookie(name, value);
14995         Roo.state.CookieProvider.superclass.set.call(this, name, value);
14996     },
14997
14998     // private
14999     clear : function(name){
15000         this.clearCookie(name);
15001         Roo.state.CookieProvider.superclass.clear.call(this, name);
15002     },
15003
15004     // private
15005     readCookies : function(){
15006         var cookies = {};
15007         var c = document.cookie + ";";
15008         var re = /\s?(.*?)=(.*?);/g;
15009         var matches;
15010         while((matches = re.exec(c)) != null){
15011             var name = matches[1];
15012             var value = matches[2];
15013             if(name && name.substring(0,3) == "ys-"){
15014                 cookies[name.substr(3)] = this.decodeValue(value);
15015             }
15016         }
15017         return cookies;
15018     },
15019
15020     // private
15021     setCookie : function(name, value){
15022         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15023            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15024            ((this.path == null) ? "" : ("; path=" + this.path)) +
15025            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15026            ((this.secure == true) ? "; secure" : "");
15027     },
15028
15029     // private
15030     clearCookie : function(name){
15031         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15032            ((this.path == null) ? "" : ("; path=" + this.path)) +
15033            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15034            ((this.secure == true) ? "; secure" : "");
15035     }
15036 });/*
15037  * Based on:
15038  * Ext JS Library 1.1.1
15039  * Copyright(c) 2006-2007, Ext JS, LLC.
15040  *
15041  * Originally Released Under LGPL - original licence link has changed is not relivant.
15042  *
15043  * Fork - LGPL
15044  * <script type="text/javascript">
15045  */
15046  
15047
15048 /**
15049  * @class Roo.ComponentMgr
15050  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15051  * @singleton
15052  */
15053 Roo.ComponentMgr = function(){
15054     var all = new Roo.util.MixedCollection();
15055
15056     return {
15057         /**
15058          * Registers a component.
15059          * @param {Roo.Component} c The component
15060          */
15061         register : function(c){
15062             all.add(c);
15063         },
15064
15065         /**
15066          * Unregisters a component.
15067          * @param {Roo.Component} c The component
15068          */
15069         unregister : function(c){
15070             all.remove(c);
15071         },
15072
15073         /**
15074          * Returns a component by id
15075          * @param {String} id The component id
15076          */
15077         get : function(id){
15078             return all.get(id);
15079         },
15080
15081         /**
15082          * Registers a function that will be called when a specified component is added to ComponentMgr
15083          * @param {String} id The component id
15084          * @param {Funtction} fn The callback function
15085          * @param {Object} scope The scope of the callback
15086          */
15087         onAvailable : function(id, fn, scope){
15088             all.on("add", function(index, o){
15089                 if(o.id == id){
15090                     fn.call(scope || o, o);
15091                     all.un("add", fn, scope);
15092                 }
15093             });
15094         }
15095     };
15096 }();/*
15097  * Based on:
15098  * Ext JS Library 1.1.1
15099  * Copyright(c) 2006-2007, Ext JS, LLC.
15100  *
15101  * Originally Released Under LGPL - original licence link has changed is not relivant.
15102  *
15103  * Fork - LGPL
15104  * <script type="text/javascript">
15105  */
15106  
15107 /**
15108  * @class Roo.Component
15109  * @extends Roo.util.Observable
15110  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15111  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15112  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15113  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15114  * All visual components (widgets) that require rendering into a layout should subclass Component.
15115  * @constructor
15116  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15117  * 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
15118  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15119  */
15120 Roo.Component = function(config){
15121     config = config || {};
15122     if(config.tagName || config.dom || typeof config == "string"){ // element object
15123         config = {el: config, id: config.id || config};
15124     }
15125     this.initialConfig = config;
15126
15127     Roo.apply(this, config);
15128     this.addEvents({
15129         /**
15130          * @event disable
15131          * Fires after the component is disabled.
15132              * @param {Roo.Component} this
15133              */
15134         disable : true,
15135         /**
15136          * @event enable
15137          * Fires after the component is enabled.
15138              * @param {Roo.Component} this
15139              */
15140         enable : true,
15141         /**
15142          * @event beforeshow
15143          * Fires before the component is shown.  Return false to stop the show.
15144              * @param {Roo.Component} this
15145              */
15146         beforeshow : true,
15147         /**
15148          * @event show
15149          * Fires after the component is shown.
15150              * @param {Roo.Component} this
15151              */
15152         show : true,
15153         /**
15154          * @event beforehide
15155          * Fires before the component is hidden. Return false to stop the hide.
15156              * @param {Roo.Component} this
15157              */
15158         beforehide : true,
15159         /**
15160          * @event hide
15161          * Fires after the component is hidden.
15162              * @param {Roo.Component} this
15163              */
15164         hide : true,
15165         /**
15166          * @event beforerender
15167          * Fires before the component is rendered. Return false to stop the render.
15168              * @param {Roo.Component} this
15169              */
15170         beforerender : true,
15171         /**
15172          * @event render
15173          * Fires after the component is rendered.
15174              * @param {Roo.Component} this
15175              */
15176         render : true,
15177         /**
15178          * @event beforedestroy
15179          * Fires before the component is destroyed. Return false to stop the destroy.
15180              * @param {Roo.Component} this
15181              */
15182         beforedestroy : true,
15183         /**
15184          * @event destroy
15185          * Fires after the component is destroyed.
15186              * @param {Roo.Component} this
15187              */
15188         destroy : true
15189     });
15190     if(!this.id){
15191         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15192     }
15193     Roo.ComponentMgr.register(this);
15194     Roo.Component.superclass.constructor.call(this);
15195     this.initComponent();
15196     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15197         this.render(this.renderTo);
15198         delete this.renderTo;
15199     }
15200 };
15201
15202 /** @private */
15203 Roo.Component.AUTO_ID = 1000;
15204
15205 Roo.extend(Roo.Component, Roo.util.Observable, {
15206     /**
15207      * @scope Roo.Component.prototype
15208      * @type {Boolean}
15209      * true if this component is hidden. Read-only.
15210      */
15211     hidden : false,
15212     /**
15213      * @type {Boolean}
15214      * true if this component is disabled. Read-only.
15215      */
15216     disabled : false,
15217     /**
15218      * @type {Boolean}
15219      * true if this component has been rendered. Read-only.
15220      */
15221     rendered : false,
15222     
15223     /** @cfg {String} disableClass
15224      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15225      */
15226     disabledClass : "x-item-disabled",
15227         /** @cfg {Boolean} allowDomMove
15228          * Whether the component can move the Dom node when rendering (defaults to true).
15229          */
15230     allowDomMove : true,
15231     /** @cfg {String} hideMode (display|visibility)
15232      * How this component should hidden. Supported values are
15233      * "visibility" (css visibility), "offsets" (negative offset position) and
15234      * "display" (css display) - defaults to "display".
15235      */
15236     hideMode: 'display',
15237
15238     /** @private */
15239     ctype : "Roo.Component",
15240
15241     /**
15242      * @cfg {String} actionMode 
15243      * which property holds the element that used for  hide() / show() / disable() / enable()
15244      * default is 'el' 
15245      */
15246     actionMode : "el",
15247
15248     /** @private */
15249     getActionEl : function(){
15250         return this[this.actionMode];
15251     },
15252
15253     initComponent : Roo.emptyFn,
15254     /**
15255      * If this is a lazy rendering component, render it to its container element.
15256      * @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.
15257      */
15258     render : function(container, position){
15259         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15260             if(!container && this.el){
15261                 this.el = Roo.get(this.el);
15262                 container = this.el.dom.parentNode;
15263                 this.allowDomMove = false;
15264             }
15265             this.container = Roo.get(container);
15266             this.rendered = true;
15267             if(position !== undefined){
15268                 if(typeof position == 'number'){
15269                     position = this.container.dom.childNodes[position];
15270                 }else{
15271                     position = Roo.getDom(position);
15272                 }
15273             }
15274             this.onRender(this.container, position || null);
15275             if(this.cls){
15276                 this.el.addClass(this.cls);
15277                 delete this.cls;
15278             }
15279             if(this.style){
15280                 this.el.applyStyles(this.style);
15281                 delete this.style;
15282             }
15283             this.fireEvent("render", this);
15284             this.afterRender(this.container);
15285             if(this.hidden){
15286                 this.hide();
15287             }
15288             if(this.disabled){
15289                 this.disable();
15290             }
15291         }
15292         return this;
15293     },
15294
15295     /** @private */
15296     // default function is not really useful
15297     onRender : function(ct, position){
15298         if(this.el){
15299             this.el = Roo.get(this.el);
15300             if(this.allowDomMove !== false){
15301                 ct.dom.insertBefore(this.el.dom, position);
15302             }
15303         }
15304     },
15305
15306     /** @private */
15307     getAutoCreate : function(){
15308         var cfg = typeof this.autoCreate == "object" ?
15309                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15310         if(this.id && !cfg.id){
15311             cfg.id = this.id;
15312         }
15313         return cfg;
15314     },
15315
15316     /** @private */
15317     afterRender : Roo.emptyFn,
15318
15319     /**
15320      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15321      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15322      */
15323     destroy : function(){
15324         if(this.fireEvent("beforedestroy", this) !== false){
15325             this.purgeListeners();
15326             this.beforeDestroy();
15327             if(this.rendered){
15328                 this.el.removeAllListeners();
15329                 this.el.remove();
15330                 if(this.actionMode == "container"){
15331                     this.container.remove();
15332                 }
15333             }
15334             this.onDestroy();
15335             Roo.ComponentMgr.unregister(this);
15336             this.fireEvent("destroy", this);
15337         }
15338     },
15339
15340         /** @private */
15341     beforeDestroy : function(){
15342
15343     },
15344
15345         /** @private */
15346         onDestroy : function(){
15347
15348     },
15349
15350     /**
15351      * Returns the underlying {@link Roo.Element}.
15352      * @return {Roo.Element} The element
15353      */
15354     getEl : function(){
15355         return this.el;
15356     },
15357
15358     /**
15359      * Returns the id of this component.
15360      * @return {String}
15361      */
15362     getId : function(){
15363         return this.id;
15364     },
15365
15366     /**
15367      * Try to focus this component.
15368      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15369      * @return {Roo.Component} this
15370      */
15371     focus : function(selectText){
15372         if(this.rendered){
15373             this.el.focus();
15374             if(selectText === true){
15375                 this.el.dom.select();
15376             }
15377         }
15378         return this;
15379     },
15380
15381     /** @private */
15382     blur : function(){
15383         if(this.rendered){
15384             this.el.blur();
15385         }
15386         return this;
15387     },
15388
15389     /**
15390      * Disable this component.
15391      * @return {Roo.Component} this
15392      */
15393     disable : function(){
15394         if(this.rendered){
15395             this.onDisable();
15396         }
15397         this.disabled = true;
15398         this.fireEvent("disable", this);
15399         return this;
15400     },
15401
15402         // private
15403     onDisable : function(){
15404         this.getActionEl().addClass(this.disabledClass);
15405         this.el.dom.disabled = true;
15406     },
15407
15408     /**
15409      * Enable this component.
15410      * @return {Roo.Component} this
15411      */
15412     enable : function(){
15413         if(this.rendered){
15414             this.onEnable();
15415         }
15416         this.disabled = false;
15417         this.fireEvent("enable", this);
15418         return this;
15419     },
15420
15421         // private
15422     onEnable : function(){
15423         this.getActionEl().removeClass(this.disabledClass);
15424         this.el.dom.disabled = false;
15425     },
15426
15427     /**
15428      * Convenience function for setting disabled/enabled by boolean.
15429      * @param {Boolean} disabled
15430      */
15431     setDisabled : function(disabled){
15432         this[disabled ? "disable" : "enable"]();
15433     },
15434
15435     /**
15436      * Show this component.
15437      * @return {Roo.Component} this
15438      */
15439     show: function(){
15440         if(this.fireEvent("beforeshow", this) !== false){
15441             this.hidden = false;
15442             if(this.rendered){
15443                 this.onShow();
15444             }
15445             this.fireEvent("show", this);
15446         }
15447         return this;
15448     },
15449
15450     // private
15451     onShow : function(){
15452         var ae = this.getActionEl();
15453         if(this.hideMode == 'visibility'){
15454             ae.dom.style.visibility = "visible";
15455         }else if(this.hideMode == 'offsets'){
15456             ae.removeClass('x-hidden');
15457         }else{
15458             ae.dom.style.display = "";
15459         }
15460     },
15461
15462     /**
15463      * Hide this component.
15464      * @return {Roo.Component} this
15465      */
15466     hide: function(){
15467         if(this.fireEvent("beforehide", this) !== false){
15468             this.hidden = true;
15469             if(this.rendered){
15470                 this.onHide();
15471             }
15472             this.fireEvent("hide", this);
15473         }
15474         return this;
15475     },
15476
15477     // private
15478     onHide : function(){
15479         var ae = this.getActionEl();
15480         if(this.hideMode == 'visibility'){
15481             ae.dom.style.visibility = "hidden";
15482         }else if(this.hideMode == 'offsets'){
15483             ae.addClass('x-hidden');
15484         }else{
15485             ae.dom.style.display = "none";
15486         }
15487     },
15488
15489     /**
15490      * Convenience function to hide or show this component by boolean.
15491      * @param {Boolean} visible True to show, false to hide
15492      * @return {Roo.Component} this
15493      */
15494     setVisible: function(visible){
15495         if(visible) {
15496             this.show();
15497         }else{
15498             this.hide();
15499         }
15500         return this;
15501     },
15502
15503     /**
15504      * Returns true if this component is visible.
15505      */
15506     isVisible : function(){
15507         return this.getActionEl().isVisible();
15508     },
15509
15510     cloneConfig : function(overrides){
15511         overrides = overrides || {};
15512         var id = overrides.id || Roo.id();
15513         var cfg = Roo.applyIf(overrides, this.initialConfig);
15514         cfg.id = id; // prevent dup id
15515         return new this.constructor(cfg);
15516     }
15517 });/*
15518  * Based on:
15519  * Ext JS Library 1.1.1
15520  * Copyright(c) 2006-2007, Ext JS, LLC.
15521  *
15522  * Originally Released Under LGPL - original licence link has changed is not relivant.
15523  *
15524  * Fork - LGPL
15525  * <script type="text/javascript">
15526  */
15527
15528 /**
15529  * @class Roo.BoxComponent
15530  * @extends Roo.Component
15531  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15532  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15533  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15534  * layout containers.
15535  * @constructor
15536  * @param {Roo.Element/String/Object} config The configuration options.
15537  */
15538 Roo.BoxComponent = function(config){
15539     Roo.Component.call(this, config);
15540     this.addEvents({
15541         /**
15542          * @event resize
15543          * Fires after the component is resized.
15544              * @param {Roo.Component} this
15545              * @param {Number} adjWidth The box-adjusted width that was set
15546              * @param {Number} adjHeight The box-adjusted height that was set
15547              * @param {Number} rawWidth The width that was originally specified
15548              * @param {Number} rawHeight The height that was originally specified
15549              */
15550         resize : true,
15551         /**
15552          * @event move
15553          * Fires after the component is moved.
15554              * @param {Roo.Component} this
15555              * @param {Number} x The new x position
15556              * @param {Number} y The new y position
15557              */
15558         move : true
15559     });
15560 };
15561
15562 Roo.extend(Roo.BoxComponent, Roo.Component, {
15563     // private, set in afterRender to signify that the component has been rendered
15564     boxReady : false,
15565     // private, used to defer height settings to subclasses
15566     deferHeight: false,
15567     /** @cfg {Number} width
15568      * width (optional) size of component
15569      */
15570      /** @cfg {Number} height
15571      * height (optional) size of component
15572      */
15573      
15574     /**
15575      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15576      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15577      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15578      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15579      * @return {Roo.BoxComponent} this
15580      */
15581     setSize : function(w, h){
15582         // support for standard size objects
15583         if(typeof w == 'object'){
15584             h = w.height;
15585             w = w.width;
15586         }
15587         // not rendered
15588         if(!this.boxReady){
15589             this.width = w;
15590             this.height = h;
15591             return this;
15592         }
15593
15594         // prevent recalcs when not needed
15595         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15596             return this;
15597         }
15598         this.lastSize = {width: w, height: h};
15599
15600         var adj = this.adjustSize(w, h);
15601         var aw = adj.width, ah = adj.height;
15602         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15603             var rz = this.getResizeEl();
15604             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15605                 rz.setSize(aw, ah);
15606             }else if(!this.deferHeight && ah !== undefined){
15607                 rz.setHeight(ah);
15608             }else if(aw !== undefined){
15609                 rz.setWidth(aw);
15610             }
15611             this.onResize(aw, ah, w, h);
15612             this.fireEvent('resize', this, aw, ah, w, h);
15613         }
15614         return this;
15615     },
15616
15617     /**
15618      * Gets the current size of the component's underlying element.
15619      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15620      */
15621     getSize : function(){
15622         return this.el.getSize();
15623     },
15624
15625     /**
15626      * Gets the current XY position of the component's underlying element.
15627      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15628      * @return {Array} The XY position of the element (e.g., [100, 200])
15629      */
15630     getPosition : function(local){
15631         if(local === true){
15632             return [this.el.getLeft(true), this.el.getTop(true)];
15633         }
15634         return this.xy || this.el.getXY();
15635     },
15636
15637     /**
15638      * Gets the current box measurements of the component's underlying element.
15639      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15640      * @returns {Object} box An object in the format {x, y, width, height}
15641      */
15642     getBox : function(local){
15643         var s = this.el.getSize();
15644         if(local){
15645             s.x = this.el.getLeft(true);
15646             s.y = this.el.getTop(true);
15647         }else{
15648             var xy = this.xy || this.el.getXY();
15649             s.x = xy[0];
15650             s.y = xy[1];
15651         }
15652         return s;
15653     },
15654
15655     /**
15656      * Sets the current box measurements of the component's underlying element.
15657      * @param {Object} box An object in the format {x, y, width, height}
15658      * @returns {Roo.BoxComponent} this
15659      */
15660     updateBox : function(box){
15661         this.setSize(box.width, box.height);
15662         this.setPagePosition(box.x, box.y);
15663         return this;
15664     },
15665
15666     // protected
15667     getResizeEl : function(){
15668         return this.resizeEl || this.el;
15669     },
15670
15671     // protected
15672     getPositionEl : function(){
15673         return this.positionEl || this.el;
15674     },
15675
15676     /**
15677      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15678      * This method fires the move event.
15679      * @param {Number} left The new left
15680      * @param {Number} top The new top
15681      * @returns {Roo.BoxComponent} this
15682      */
15683     setPosition : function(x, y){
15684         this.x = x;
15685         this.y = y;
15686         if(!this.boxReady){
15687             return this;
15688         }
15689         var adj = this.adjustPosition(x, y);
15690         var ax = adj.x, ay = adj.y;
15691
15692         var el = this.getPositionEl();
15693         if(ax !== undefined || ay !== undefined){
15694             if(ax !== undefined && ay !== undefined){
15695                 el.setLeftTop(ax, ay);
15696             }else if(ax !== undefined){
15697                 el.setLeft(ax);
15698             }else if(ay !== undefined){
15699                 el.setTop(ay);
15700             }
15701             this.onPosition(ax, ay);
15702             this.fireEvent('move', this, ax, ay);
15703         }
15704         return this;
15705     },
15706
15707     /**
15708      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15709      * This method fires the move event.
15710      * @param {Number} x The new x position
15711      * @param {Number} y The new y position
15712      * @returns {Roo.BoxComponent} this
15713      */
15714     setPagePosition : function(x, y){
15715         this.pageX = x;
15716         this.pageY = y;
15717         if(!this.boxReady){
15718             return;
15719         }
15720         if(x === undefined || y === undefined){ // cannot translate undefined points
15721             return;
15722         }
15723         var p = this.el.translatePoints(x, y);
15724         this.setPosition(p.left, p.top);
15725         return this;
15726     },
15727
15728     // private
15729     onRender : function(ct, position){
15730         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15731         if(this.resizeEl){
15732             this.resizeEl = Roo.get(this.resizeEl);
15733         }
15734         if(this.positionEl){
15735             this.positionEl = Roo.get(this.positionEl);
15736         }
15737     },
15738
15739     // private
15740     afterRender : function(){
15741         Roo.BoxComponent.superclass.afterRender.call(this);
15742         this.boxReady = true;
15743         this.setSize(this.width, this.height);
15744         if(this.x || this.y){
15745             this.setPosition(this.x, this.y);
15746         }
15747         if(this.pageX || this.pageY){
15748             this.setPagePosition(this.pageX, this.pageY);
15749         }
15750     },
15751
15752     /**
15753      * Force the component's size to recalculate based on the underlying element's current height and width.
15754      * @returns {Roo.BoxComponent} this
15755      */
15756     syncSize : function(){
15757         delete this.lastSize;
15758         this.setSize(this.el.getWidth(), this.el.getHeight());
15759         return this;
15760     },
15761
15762     /**
15763      * Called after the component is resized, this method is empty by default but can be implemented by any
15764      * subclass that needs to perform custom logic after a resize occurs.
15765      * @param {Number} adjWidth The box-adjusted width that was set
15766      * @param {Number} adjHeight The box-adjusted height that was set
15767      * @param {Number} rawWidth The width that was originally specified
15768      * @param {Number} rawHeight The height that was originally specified
15769      */
15770     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15771
15772     },
15773
15774     /**
15775      * Called after the component is moved, this method is empty by default but can be implemented by any
15776      * subclass that needs to perform custom logic after a move occurs.
15777      * @param {Number} x The new x position
15778      * @param {Number} y The new y position
15779      */
15780     onPosition : function(x, y){
15781
15782     },
15783
15784     // private
15785     adjustSize : function(w, h){
15786         if(this.autoWidth){
15787             w = 'auto';
15788         }
15789         if(this.autoHeight){
15790             h = 'auto';
15791         }
15792         return {width : w, height: h};
15793     },
15794
15795     // private
15796     adjustPosition : function(x, y){
15797         return {x : x, y: y};
15798     }
15799 });/*
15800  * Original code for Roojs - LGPL
15801  * <script type="text/javascript">
15802  */
15803  
15804 /**
15805  * @class Roo.XComponent
15806  * A delayed Element creator...
15807  * Or a way to group chunks of interface together.
15808  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15809  *  used in conjunction with XComponent.build() it will create an instance of each element,
15810  *  then call addxtype() to build the User interface.
15811  * 
15812  * Mypart.xyx = new Roo.XComponent({
15813
15814     parent : 'Mypart.xyz', // empty == document.element.!!
15815     order : '001',
15816     name : 'xxxx'
15817     region : 'xxxx'
15818     disabled : function() {} 
15819      
15820     tree : function() { // return an tree of xtype declared components
15821         var MODULE = this;
15822         return 
15823         {
15824             xtype : 'NestedLayoutPanel',
15825             // technicall
15826         }
15827      ]
15828  *})
15829  *
15830  *
15831  * It can be used to build a big heiracy, with parent etc.
15832  * or you can just use this to render a single compoent to a dom element
15833  * MYPART.render(Roo.Element | String(id) | dom_element )
15834  *
15835  *
15836  * Usage patterns.
15837  *
15838  * Classic Roo
15839  *
15840  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15841  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15842  *
15843  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15844  *
15845  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15846  * - if mulitple topModules exist, the last one is defined as the top module.
15847  *
15848  * Embeded Roo
15849  * 
15850  * When the top level or multiple modules are to embedded into a existing HTML page,
15851  * the parent element can container '#id' of the element where the module will be drawn.
15852  *
15853  * Bootstrap Roo
15854  *
15855  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15856  * it relies more on a include mechanism, where sub modules are included into an outer page.
15857  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15858  * 
15859  * Bootstrap Roo Included elements
15860  *
15861  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15862  * hence confusing the component builder as it thinks there are multiple top level elements. 
15863  *
15864  * 
15865  * 
15866  * @extends Roo.util.Observable
15867  * @constructor
15868  * @param cfg {Object} configuration of component
15869  * 
15870  */
15871 Roo.XComponent = function(cfg) {
15872     Roo.apply(this, cfg);
15873     this.addEvents({ 
15874         /**
15875              * @event built
15876              * Fires when this the componnt is built
15877              * @param {Roo.XComponent} c the component
15878              */
15879         'built' : true
15880         
15881     });
15882     this.region = this.region || 'center'; // default..
15883     Roo.XComponent.register(this);
15884     this.modules = false;
15885     this.el = false; // where the layout goes..
15886     
15887     
15888 }
15889 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15890     /**
15891      * @property el
15892      * The created element (with Roo.factory())
15893      * @type {Roo.Layout}
15894      */
15895     el  : false,
15896     
15897     /**
15898      * @property el
15899      * for BC  - use el in new code
15900      * @type {Roo.Layout}
15901      */
15902     panel : false,
15903     
15904     /**
15905      * @property layout
15906      * for BC  - use el in new code
15907      * @type {Roo.Layout}
15908      */
15909     layout : false,
15910     
15911      /**
15912      * @cfg {Function|boolean} disabled
15913      * If this module is disabled by some rule, return true from the funtion
15914      */
15915     disabled : false,
15916     
15917     /**
15918      * @cfg {String} parent 
15919      * Name of parent element which it get xtype added to..
15920      */
15921     parent: false,
15922     
15923     /**
15924      * @cfg {String} order
15925      * Used to set the order in which elements are created (usefull for multiple tabs)
15926      */
15927     
15928     order : false,
15929     /**
15930      * @cfg {String} name
15931      * String to display while loading.
15932      */
15933     name : false,
15934     /**
15935      * @cfg {String} region
15936      * Region to render component to (defaults to center)
15937      */
15938     region : 'center',
15939     
15940     /**
15941      * @cfg {Array} items
15942      * A single item array - the first element is the root of the tree..
15943      * It's done this way to stay compatible with the Xtype system...
15944      */
15945     items : false,
15946     
15947     /**
15948      * @property _tree
15949      * The method that retuns the tree of parts that make up this compoennt 
15950      * @type {function}
15951      */
15952     _tree  : false,
15953     
15954      /**
15955      * render
15956      * render element to dom or tree
15957      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15958      */
15959     
15960     render : function(el)
15961     {
15962         
15963         el = el || false;
15964         var hp = this.parent ? 1 : 0;
15965         Roo.debug &&  Roo.log(this);
15966         
15967         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15968             // if parent is a '#.....' string, then let's use that..
15969             var ename = this.parent.substr(1);
15970             this.parent = false;
15971             Roo.debug && Roo.log(ename);
15972             switch (ename) {
15973                 case 'bootstrap-body' :
15974                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15975                         this.parent = { el :  new  Roo.bootstrap.Body() };
15976                         Roo.debug && Roo.log("setting el to doc body");
15977                          
15978                     } else {
15979                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15980                     }
15981                     break;
15982                 case 'bootstrap':
15983                     this.parent = { el : true};
15984                     // fall through
15985                 default:
15986                     el = Roo.get(ename);
15987                     break;
15988             }
15989                 
15990             
15991             if (!el && !this.parent) {
15992                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15993                 return;
15994             }
15995         }
15996         Roo.debug && Roo.log("EL:");
15997         Roo.debug && Roo.log(el);
15998         Roo.debug && Roo.log("this.parent.el:");
15999         Roo.debug && Roo.log(this.parent.el);
16000         
16001         var tree = this._tree ? this._tree() : this.tree();
16002
16003         // altertive root elements ??? - we need a better way to indicate these.
16004         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16005                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16006         
16007         if (!this.parent && is_alt) {
16008             //el = Roo.get(document.body);
16009             this.parent = { el : true };
16010         }
16011             
16012             
16013         
16014         if (!this.parent) {
16015             
16016             Roo.debug && Roo.log("no parent - creating one");
16017             
16018             el = el ? Roo.get(el) : false;      
16019             
16020             // it's a top level one..
16021             this.parent =  {
16022                 el : new Roo.BorderLayout(el || document.body, {
16023                 
16024                      center: {
16025                          titlebar: false,
16026                          autoScroll:false,
16027                          closeOnTab: true,
16028                          tabPosition: 'top',
16029                           //resizeTabs: true,
16030                          alwaysShowTabs: el && hp? false :  true,
16031                          hideTabs: el || !hp ? true :  false,
16032                          minTabWidth: 140
16033                      }
16034                  })
16035             }
16036         }
16037         
16038         if (!this.parent.el) {
16039                 // probably an old style ctor, which has been disabled.
16040                 return;
16041
16042         }
16043                 // The 'tree' method is  '_tree now' 
16044             
16045         tree.region = tree.region || this.region;
16046         
16047         if (this.parent.el === true) {
16048             // bootstrap... - body..
16049             this.parent.el = Roo.factory(tree);
16050         }
16051         
16052         this.el = this.parent.el.addxtype(tree);
16053         this.fireEvent('built', this);
16054         
16055         this.panel = this.el;
16056         this.layout = this.panel.layout;
16057         this.parentLayout = this.parent.layout  || false;  
16058          
16059     }
16060     
16061 });
16062
16063 Roo.apply(Roo.XComponent, {
16064     /**
16065      * @property  hideProgress
16066      * true to disable the building progress bar.. usefull on single page renders.
16067      * @type Boolean
16068      */
16069     hideProgress : false,
16070     /**
16071      * @property  buildCompleted
16072      * True when the builder has completed building the interface.
16073      * @type Boolean
16074      */
16075     buildCompleted : false,
16076      
16077     /**
16078      * @property  topModule
16079      * the upper most module - uses document.element as it's constructor.
16080      * @type Object
16081      */
16082      
16083     topModule  : false,
16084       
16085     /**
16086      * @property  modules
16087      * array of modules to be created by registration system.
16088      * @type {Array} of Roo.XComponent
16089      */
16090     
16091     modules : [],
16092     /**
16093      * @property  elmodules
16094      * array of modules to be created by which use #ID 
16095      * @type {Array} of Roo.XComponent
16096      */
16097      
16098     elmodules : [],
16099
16100      /**
16101      * @property  build_from_html
16102      * Build elements from html - used by bootstrap HTML stuff 
16103      *    - this is cleared after build is completed
16104      * @type {boolean} true  (default false)
16105      */
16106      
16107     build_from_html : false,
16108
16109     /**
16110      * Register components to be built later.
16111      *
16112      * This solves the following issues
16113      * - Building is not done on page load, but after an authentication process has occured.
16114      * - Interface elements are registered on page load
16115      * - Parent Interface elements may not be loaded before child, so this handles that..
16116      * 
16117      *
16118      * example:
16119      * 
16120      * MyApp.register({
16121           order : '000001',
16122           module : 'Pman.Tab.projectMgr',
16123           region : 'center',
16124           parent : 'Pman.layout',
16125           disabled : false,  // or use a function..
16126         })
16127      
16128      * * @param {Object} details about module
16129      */
16130     register : function(obj) {
16131                 
16132         Roo.XComponent.event.fireEvent('register', obj);
16133         switch(typeof(obj.disabled) ) {
16134                 
16135             case 'undefined':
16136                 break;
16137             
16138             case 'function':
16139                 if ( obj.disabled() ) {
16140                         return;
16141                 }
16142                 break;
16143             
16144             default:
16145                 if (obj.disabled) {
16146                         return;
16147                 }
16148                 break;
16149         }
16150                 
16151         this.modules.push(obj);
16152          
16153     },
16154     /**
16155      * convert a string to an object..
16156      * eg. 'AAA.BBB' -> finds AAA.BBB
16157
16158      */
16159     
16160     toObject : function(str)
16161     {
16162         if (!str || typeof(str) == 'object') {
16163             return str;
16164         }
16165         if (str.substring(0,1) == '#') {
16166             return str;
16167         }
16168
16169         var ar = str.split('.');
16170         var rt, o;
16171         rt = ar.shift();
16172             /** eval:var:o */
16173         try {
16174             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16175         } catch (e) {
16176             throw "Module not found : " + str;
16177         }
16178         
16179         if (o === false) {
16180             throw "Module not found : " + str;
16181         }
16182         Roo.each(ar, function(e) {
16183             if (typeof(o[e]) == 'undefined') {
16184                 throw "Module not found : " + str;
16185             }
16186             o = o[e];
16187         });
16188         
16189         return o;
16190         
16191     },
16192     
16193     
16194     /**
16195      * move modules into their correct place in the tree..
16196      * 
16197      */
16198     preBuild : function ()
16199     {
16200         var _t = this;
16201         Roo.each(this.modules , function (obj)
16202         {
16203             Roo.XComponent.event.fireEvent('beforebuild', obj);
16204             
16205             var opar = obj.parent;
16206             try { 
16207                 obj.parent = this.toObject(opar);
16208             } catch(e) {
16209                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16210                 return;
16211             }
16212             
16213             if (!obj.parent) {
16214                 Roo.debug && Roo.log("GOT top level module");
16215                 Roo.debug && Roo.log(obj);
16216                 obj.modules = new Roo.util.MixedCollection(false, 
16217                     function(o) { return o.order + '' }
16218                 );
16219                 this.topModule = obj;
16220                 return;
16221             }
16222                         // parent is a string (usually a dom element name..)
16223             if (typeof(obj.parent) == 'string') {
16224                 this.elmodules.push(obj);
16225                 return;
16226             }
16227             if (obj.parent.constructor != Roo.XComponent) {
16228                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16229             }
16230             if (!obj.parent.modules) {
16231                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16232                     function(o) { return o.order + '' }
16233                 );
16234             }
16235             if (obj.parent.disabled) {
16236                 obj.disabled = true;
16237             }
16238             obj.parent.modules.add(obj);
16239         }, this);
16240     },
16241     
16242      /**
16243      * make a list of modules to build.
16244      * @return {Array} list of modules. 
16245      */ 
16246     
16247     buildOrder : function()
16248     {
16249         var _this = this;
16250         var cmp = function(a,b) {   
16251             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16252         };
16253         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16254             throw "No top level modules to build";
16255         }
16256         
16257         // make a flat list in order of modules to build.
16258         var mods = this.topModule ? [ this.topModule ] : [];
16259                 
16260         
16261         // elmodules (is a list of DOM based modules )
16262         Roo.each(this.elmodules, function(e) {
16263             mods.push(e);
16264             if (!this.topModule &&
16265                 typeof(e.parent) == 'string' &&
16266                 e.parent.substring(0,1) == '#' &&
16267                 Roo.get(e.parent.substr(1))
16268                ) {
16269                 
16270                 _this.topModule = e;
16271             }
16272             
16273         });
16274
16275         
16276         // add modules to their parents..
16277         var addMod = function(m) {
16278             Roo.debug && Roo.log("build Order: add: " + m.name);
16279                 
16280             mods.push(m);
16281             if (m.modules && !m.disabled) {
16282                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16283                 m.modules.keySort('ASC',  cmp );
16284                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16285     
16286                 m.modules.each(addMod);
16287             } else {
16288                 Roo.debug && Roo.log("build Order: no child modules");
16289             }
16290             // not sure if this is used any more..
16291             if (m.finalize) {
16292                 m.finalize.name = m.name + " (clean up) ";
16293                 mods.push(m.finalize);
16294             }
16295             
16296         }
16297         if (this.topModule && this.topModule.modules) { 
16298             this.topModule.modules.keySort('ASC',  cmp );
16299             this.topModule.modules.each(addMod);
16300         } 
16301         return mods;
16302     },
16303     
16304      /**
16305      * Build the registered modules.
16306      * @param {Object} parent element.
16307      * @param {Function} optional method to call after module has been added.
16308      * 
16309      */ 
16310    
16311     build : function(opts) 
16312     {
16313         
16314         if (typeof(opts) != 'undefined') {
16315             Roo.apply(this,opts);
16316         }
16317         
16318         this.preBuild();
16319         var mods = this.buildOrder();
16320       
16321         //this.allmods = mods;
16322         //Roo.debug && Roo.log(mods);
16323         //return;
16324         if (!mods.length) { // should not happen
16325             throw "NO modules!!!";
16326         }
16327         
16328         
16329         var msg = "Building Interface...";
16330         // flash it up as modal - so we store the mask!?
16331         if (!this.hideProgress && Roo.MessageBox) {
16332             Roo.MessageBox.show({ title: 'loading' });
16333             Roo.MessageBox.show({
16334                title: "Please wait...",
16335                msg: msg,
16336                width:450,
16337                progress:true,
16338                closable:false,
16339                modal: false
16340               
16341             });
16342         }
16343         var total = mods.length;
16344         
16345         var _this = this;
16346         var progressRun = function() {
16347             if (!mods.length) {
16348                 Roo.debug && Roo.log('hide?');
16349                 if (!this.hideProgress && Roo.MessageBox) {
16350                     Roo.MessageBox.hide();
16351                 }
16352                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16353                 
16354                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16355                 
16356                 // THE END...
16357                 return false;   
16358             }
16359             
16360             var m = mods.shift();
16361             
16362             
16363             Roo.debug && Roo.log(m);
16364             // not sure if this is supported any more.. - modules that are are just function
16365             if (typeof(m) == 'function') { 
16366                 m.call(this);
16367                 return progressRun.defer(10, _this);
16368             } 
16369             
16370             
16371             msg = "Building Interface " + (total  - mods.length) + 
16372                     " of " + total + 
16373                     (m.name ? (' - ' + m.name) : '');
16374                         Roo.debug && Roo.log(msg);
16375             if (!this.hideProgress &&  Roo.MessageBox) { 
16376                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16377             }
16378             
16379          
16380             // is the module disabled?
16381             var disabled = (typeof(m.disabled) == 'function') ?
16382                 m.disabled.call(m.module.disabled) : m.disabled;    
16383             
16384             
16385             if (disabled) {
16386                 return progressRun(); // we do not update the display!
16387             }
16388             
16389             // now build 
16390             
16391                         
16392                         
16393             m.render();
16394             // it's 10 on top level, and 1 on others??? why...
16395             return progressRun.defer(10, _this);
16396              
16397         }
16398         progressRun.defer(1, _this);
16399      
16400         
16401         
16402     },
16403         
16404         
16405         /**
16406          * Event Object.
16407          *
16408          *
16409          */
16410         event: false, 
16411     /**
16412          * wrapper for event.on - aliased later..  
16413          * Typically use to register a event handler for register:
16414          *
16415          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16416          *
16417          */
16418     on : false
16419    
16420     
16421     
16422 });
16423
16424 Roo.XComponent.event = new Roo.util.Observable({
16425                 events : { 
16426                         /**
16427                          * @event register
16428                          * Fires when an Component is registered,
16429                          * set the disable property on the Component to stop registration.
16430                          * @param {Roo.XComponent} c the component being registerd.
16431                          * 
16432                          */
16433                         'register' : true,
16434             /**
16435                          * @event beforebuild
16436                          * Fires before each Component is built
16437                          * can be used to apply permissions.
16438                          * @param {Roo.XComponent} c the component being registerd.
16439                          * 
16440                          */
16441                         'beforebuild' : true,
16442                         /**
16443                          * @event buildcomplete
16444                          * Fires on the top level element when all elements have been built
16445                          * @param {Roo.XComponent} the top level component.
16446                          */
16447                         'buildcomplete' : true
16448                         
16449                 }
16450 });
16451
16452 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16453