Roo/Element.js
[roojs1] / roojs-core-debug.js
1 /*
2  * Based on:
3  * Ext JS Library 1.1.1
4  * Copyright(c) 2006-2007, Ext JS, LLC.
5  *
6  * Originally Released Under LGPL - original licence link has changed is not relivant.
7  *
8  * Fork - LGPL
9  * <script type="text/javascript">
10  */
11  
12
13
14
15
16 // for old browsers
17 window["undefined"] = window["undefined"];
18
19 /**
20  * @class Roo
21  * Roo core utilities and functions.
22  * @singleton
23  */
24 var Roo = {}; 
25 /**
26  * Copies all the properties of config to obj.
27  * @param {Object} obj The receiver of the properties
28  * @param {Object} config The source of the properties
29  * @param {Object} defaults A different object that will also be applied for default values
30  * @return {Object} returns obj
31  * @member Roo apply
32  */
33
34  
35 Roo.apply = function(o, c, defaults){
36     if(defaults){
37         // no "this" reference for friendly out of scope calls
38         Roo.apply(o, defaults);
39     }
40     if(o && c && typeof c == 'object'){
41         for(var p in c){
42             o[p] = c[p];
43         }
44     }
45     return o;
46 };
47
48
49 (function(){
50     var idSeed = 0;
51     var ua = navigator.userAgent.toLowerCase();
52
53     var isStrict = document.compatMode == "CSS1Compat",
54         isOpera = ua.indexOf("opera") > -1,
55         isSafari = (/webkit|khtml/).test(ua),
56         isFirefox = ua.indexOf("firefox") > -1,
57         isIE = ua.indexOf("msie") > -1,
58         isIE7 = ua.indexOf("msie 7") > -1,
59         isIE11 = /trident.*rv\:11\./.test(ua),
60         isGecko = !isSafari && ua.indexOf("gecko") > -1,
61         isBorderBox = isIE && !isStrict,
62         isWindows = (ua.indexOf("windows") != -1 || ua.indexOf("win32") != -1),
63         isMac = (ua.indexOf("macintosh") != -1 || ua.indexOf("mac os x") != -1),
64         isLinux = (ua.indexOf("linux") != -1),
65         isSecure = window.location.href.toLowerCase().indexOf("https") === 0,
66         isIOS = /iphone|ipad/.test(ua),
67         isTouch =  (function() {
68             try {  
69                 document.createEvent("TouchEvent");  
70                 return true;  
71             } catch (e) {  
72                 return false;  
73             } 
74             
75         })();
76     // remove css image flicker
77         if(isIE && !isIE7){
78         try{
79             document.execCommand("BackgroundImageCache", false, true);
80         }catch(e){}
81     }
82     
83     Roo.apply(Roo, {
84         /**
85          * True if the browser is in strict mode
86          * @type Boolean
87          */
88         isStrict : isStrict,
89         /**
90          * True if the page is running over SSL
91          * @type Boolean
92          */
93         isSecure : isSecure,
94         /**
95          * True when the document is fully initialized and ready for action
96          * @type Boolean
97          */
98         isReady : false,
99         /**
100          * Turn on debugging output (currently only the factory uses this)
101          * @type Boolean
102          */
103         
104         debug: false,
105
106         /**
107          * True to automatically uncache orphaned Roo.Elements periodically (defaults to true)
108          * @type Boolean
109          */
110         enableGarbageCollector : true,
111
112         /**
113          * True to automatically purge event listeners after uncaching an element (defaults to false).
114          * Note: this only happens if enableGarbageCollector is true.
115          * @type Boolean
116          */
117         enableListenerCollection:false,
118
119         /**
120          * URL to a blank file used by Roo when in secure mode for iframe src and onReady src to prevent
121          * the IE insecure content warning (defaults to javascript:false).
122          * @type String
123          */
124         SSL_SECURE_URL : "javascript:false",
125
126         /**
127          * URL to a 1x1 transparent gif image used by Roo to create inline icons with CSS background images. (Defaults to
128          * "http://Roojs.com/s.gif" and you should change this to a URL on your server).
129          * @type String
130          */
131         BLANK_IMAGE_URL : "http:/"+"/localhost/s.gif",
132
133         emptyFn : function(){},
134         
135         /**
136          * Copies all the properties of config to obj if they don't already exist.
137          * @param {Object} obj The receiver of the properties
138          * @param {Object} config The source of the properties
139          * @return {Object} returns obj
140          */
141         applyIf : function(o, c){
142             if(o && c){
143                 for(var p in c){
144                     if(typeof o[p] == "undefined"){ o[p] = c[p]; }
145                 }
146             }
147             return o;
148         },
149
150         /**
151          * Applies event listeners to elements by selectors when the document is ready.
152          * The event name is specified with an @ suffix.
153 <pre><code>
154 Roo.addBehaviors({
155    // add a listener for click on all anchors in element with id foo
156    '#foo a@click' : function(e, t){
157        // do something
158    },
159
160    // add the same listener to multiple selectors (separated by comma BEFORE the @)
161    '#foo a, #bar span.some-class@mouseover' : function(){
162        // do something
163    }
164 });
165 </code></pre>
166          * @param {Object} obj The list of behaviors to apply
167          */
168         addBehaviors : function(o){
169             if(!Roo.isReady){
170                 Roo.onReady(function(){
171                     Roo.addBehaviors(o);
172                 });
173                 return;
174             }
175             var cache = {}; // simple cache for applying multiple behaviors to same selector does query multiple times
176             for(var b in o){
177                 var parts = b.split('@');
178                 if(parts[1]){ // for Object prototype breakers
179                     var s = parts[0];
180                     if(!cache[s]){
181                         cache[s] = Roo.select(s);
182                     }
183                     cache[s].on(parts[1], o[b]);
184                 }
185             }
186             cache = null;
187         },
188
189         /**
190          * Generates unique ids. If the element already has an id, it is unchanged
191          * @param {String/HTMLElement/Element} el (optional) The element to generate an id for
192          * @param {String} prefix (optional) Id prefix (defaults "Roo-gen")
193          * @return {String} The generated Id.
194          */
195         id : function(el, prefix){
196             prefix = prefix || "roo-gen";
197             el = Roo.getDom(el);
198             var id = prefix + (++idSeed);
199             return el ? (el.id ? el.id : (el.id = id)) : id;
200         },
201          
202        
203         /**
204          * Extends one class with another class and optionally overrides members with the passed literal. This class
205          * also adds the function "override()" to the class that can be used to override
206          * members on an instance.
207          * @param {Object} subclass The class inheriting the functionality
208          * @param {Object} superclass The class being extended
209          * @param {Object} overrides (optional) A literal with members
210          * @method extend
211          */
212         extend : function(){
213             // inline overrides
214             var io = function(o){
215                 for(var m in o){
216                     this[m] = o[m];
217                 }
218             };
219             return function(sb, sp, overrides){
220                 if(typeof sp == 'object'){ // eg. prototype, rather than function constructor..
221                     overrides = sp;
222                     sp = sb;
223                     sb = function(){sp.apply(this, arguments);};
224                 }
225                 var F = function(){}, sbp, spp = sp.prototype;
226                 F.prototype = spp;
227                 sbp = sb.prototype = new F();
228                 sbp.constructor=sb;
229                 sb.superclass=spp;
230                 
231                 if(spp.constructor == Object.prototype.constructor){
232                     spp.constructor=sp;
233                    
234                 }
235                 
236                 sb.override = function(o){
237                     Roo.override(sb, o);
238                 };
239                 sbp.override = io;
240                 Roo.override(sb, overrides);
241                 return sb;
242             };
243         }(),
244
245         /**
246          * Adds a list of functions to the prototype of an existing class, overwriting any existing methods with the same name.
247          * Usage:<pre><code>
248 Roo.override(MyClass, {
249     newMethod1: function(){
250         // etc.
251     },
252     newMethod2: function(foo){
253         // etc.
254     }
255 });
256  </code></pre>
257          * @param {Object} origclass The class to override
258          * @param {Object} overrides The list of functions to add to origClass.  This should be specified as an object literal
259          * containing one or more methods.
260          * @method override
261          */
262         override : function(origclass, overrides){
263             if(overrides){
264                 var p = origclass.prototype;
265                 for(var method in overrides){
266                     p[method] = overrides[method];
267                 }
268             }
269         },
270         /**
271          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
272          * <pre><code>
273 Roo.namespace('Company', 'Company.data');
274 Company.Widget = function() { ... }
275 Company.data.CustomStore = function(config) { ... }
276 </code></pre>
277          * @param {String} namespace1
278          * @param {String} namespace2
279          * @param {String} etc
280          * @method namespace
281          */
282         namespace : function(){
283             var a=arguments, o=null, i, j, d, rt;
284             for (i=0; i<a.length; ++i) {
285                 d=a[i].split(".");
286                 rt = d[0];
287                 /** eval:var:o */
288                 eval('if (typeof ' + rt + ' == "undefined"){' + rt + ' = {};} o = ' + rt + ';');
289                 for (j=1; j<d.length; ++j) {
290                     o[d[j]]=o[d[j]] || {};
291                     o=o[d[j]];
292                 }
293             }
294         },
295         /**
296          * Creates namespaces to be used for scoping variables and classes so that they are not global.  Usage:
297          * <pre><code>
298 Roo.factory({ xns: Roo.data, xtype : 'Store', .....});
299 Roo.factory(conf, Roo.data);
300 </code></pre>
301          * @param {String} classname
302          * @param {String} namespace (optional)
303          * @method factory
304          */
305          
306         factory : function(c, ns)
307         {
308             // no xtype, no ns or c.xns - or forced off by c.xns
309             if (!c.xtype   || (!ns && !c.xns) ||  (c.xns === false)) { // not enough info...
310                 return c;
311             }
312             ns = c.xns ? c.xns : ns; // if c.xns is set, then use that..
313             if (c.constructor == ns[c.xtype]) {// already created...
314                 return c;
315             }
316             if (ns[c.xtype]) {
317                 if (Roo.debug) Roo.log("Roo.Factory(" + c.xtype + ")");
318                 var ret = new ns[c.xtype](c);
319                 ret.xns = false;
320                 return ret;
321             }
322             c.xns = false; // prevent recursion..
323             return c;
324         },
325          /**
326          * Logs to console if it can.
327          *
328          * @param {String|Object} string
329          * @method log
330          */
331         log : function(s)
332         {
333             if ((typeof(console) == 'undefined') || (typeof(console.log) == 'undefined')) {
334                 return; // alerT?
335             }
336             console.log(s);
337             
338         },
339         /**
340          * Takes an object and converts it to an encoded URL. e.g. Roo.urlEncode({foo: 1, bar: 2}); would return "foo=1&bar=2".  Optionally, property values can be arrays, instead of keys and the resulting string that's returned will contain a name/value pair for each array value.
341          * @param {Object} o
342          * @return {String}
343          */
344         urlEncode : function(o){
345             if(!o){
346                 return "";
347             }
348             var buf = [];
349             for(var key in o){
350                 var ov = o[key], k = Roo.encodeURIComponent(key);
351                 var type = typeof ov;
352                 if(type == 'undefined'){
353                     buf.push(k, "=&");
354                 }else if(type != "function" && type != "object"){
355                     buf.push(k, "=", Roo.encodeURIComponent(ov), "&");
356                 }else if(ov instanceof Array){
357                     if (ov.length) {
358                             for(var i = 0, len = ov.length; i < len; i++) {
359                                 buf.push(k, "=", Roo.encodeURIComponent(ov[i] === undefined ? '' : ov[i]), "&");
360                             }
361                         } else {
362                             buf.push(k, "=&");
363                         }
364                 }
365             }
366             buf.pop();
367             return buf.join("");
368         },
369          /**
370          * Safe version of encodeURIComponent
371          * @param {String} data 
372          * @return {String} 
373          */
374         
375         encodeURIComponent : function (data)
376         {
377             try {
378                 return encodeURIComponent(data);
379             } catch(e) {} // should be an uri encode error.
380             
381             if (data == '' || data == null){
382                return '';
383             }
384             // http://stackoverflow.com/questions/2596483/unicode-and-uri-encoding-decoding-and-escaping-in-javascript
385             function nibble_to_hex(nibble){
386                 var chars = '0123456789ABCDEF';
387                 return chars.charAt(nibble);
388             }
389             data = data.toString();
390             var buffer = '';
391             for(var i=0; i<data.length; i++){
392                 var c = data.charCodeAt(i);
393                 var bs = new Array();
394                 if (c > 0x10000){
395                         // 4 bytes
396                     bs[0] = 0xF0 | ((c & 0x1C0000) >>> 18);
397                     bs[1] = 0x80 | ((c & 0x3F000) >>> 12);
398                     bs[2] = 0x80 | ((c & 0xFC0) >>> 6);
399                     bs[3] = 0x80 | (c & 0x3F);
400                 }else if (c > 0x800){
401                          // 3 bytes
402                     bs[0] = 0xE0 | ((c & 0xF000) >>> 12);
403                     bs[1] = 0x80 | ((c & 0xFC0) >>> 6);
404                     bs[2] = 0x80 | (c & 0x3F);
405                 }else if (c > 0x80){
406                        // 2 bytes
407                     bs[0] = 0xC0 | ((c & 0x7C0) >>> 6);
408                     bs[1] = 0x80 | (c & 0x3F);
409                 }else{
410                         // 1 byte
411                     bs[0] = c;
412                 }
413                 for(var j=0; j<bs.length; j++){
414                     var b = bs[j];
415                     var hex = nibble_to_hex((b & 0xF0) >>> 4) 
416                             + nibble_to_hex(b &0x0F);
417                     buffer += '%'+hex;
418                }
419             }
420             return buffer;    
421              
422         },
423
424         /**
425          * Takes an encoded URL and and converts it to an object. e.g. Roo.urlDecode("foo=1&bar=2"); would return {foo: 1, bar: 2} or Roo.urlDecode("foo=1&bar=2&bar=3&bar=4", true); would return {foo: 1, bar: [2, 3, 4]}.
426          * @param {String} string
427          * @param {Boolean} overwrite (optional) Items of the same name will overwrite previous values instead of creating an an array (Defaults to false).
428          * @return {Object} A literal with members
429          */
430         urlDecode : function(string, overwrite){
431             if(!string || !string.length){
432                 return {};
433             }
434             var obj = {};
435             var pairs = string.split('&');
436             var pair, name, value;
437             for(var i = 0, len = pairs.length; i < len; i++){
438                 pair = pairs[i].split('=');
439                 name = decodeURIComponent(pair[0]);
440                 value = decodeURIComponent(pair[1]);
441                 if(overwrite !== true){
442                     if(typeof obj[name] == "undefined"){
443                         obj[name] = value;
444                     }else if(typeof obj[name] == "string"){
445                         obj[name] = [obj[name]];
446                         obj[name].push(value);
447                     }else{
448                         obj[name].push(value);
449                     }
450                 }else{
451                     obj[name] = value;
452                 }
453             }
454             return obj;
455         },
456
457         /**
458          * Iterates an array calling the passed function with each item, stopping if your function returns false. If the
459          * passed array is not really an array, your function is called once with it.
460          * The supplied function is called with (Object item, Number index, Array allItems).
461          * @param {Array/NodeList/Mixed} array
462          * @param {Function} fn
463          * @param {Object} scope
464          */
465         each : function(array, fn, scope){
466             if(typeof array.length == "undefined" || typeof array == "string"){
467                 array = [array];
468             }
469             for(var i = 0, len = array.length; i < len; i++){
470                 if(fn.call(scope || array[i], array[i], i, array) === false){ return i; };
471             }
472         },
473
474         // deprecated
475         combine : function(){
476             var as = arguments, l = as.length, r = [];
477             for(var i = 0; i < l; i++){
478                 var a = as[i];
479                 if(a instanceof Array){
480                     r = r.concat(a);
481                 }else if(a.length !== undefined && !a.substr){
482                     r = r.concat(Array.prototype.slice.call(a, 0));
483                 }else{
484                     r.push(a);
485                 }
486             }
487             return r;
488         },
489
490         /**
491          * Escapes the passed string for use in a regular expression
492          * @param {String} str
493          * @return {String}
494          */
495         escapeRe : function(s) {
496             return s.replace(/([.*+?^${}()|[\]\/\\])/g, "\\$1");
497         },
498
499         // internal
500         callback : function(cb, scope, args, delay){
501             if(typeof cb == "function"){
502                 if(delay){
503                     cb.defer(delay, scope, args || []);
504                 }else{
505                     cb.apply(scope, args || []);
506                 }
507             }
508         },
509
510         /**
511          * Return the dom node for the passed string (id), dom node, or Roo.Element
512          * @param {String/HTMLElement/Roo.Element} el
513          * @return HTMLElement
514          */
515         getDom : function(el){
516             if(!el){
517                 return null;
518             }
519             return el.dom ? el.dom : (typeof el == 'string' ? document.getElementById(el) : el);
520         },
521
522         /**
523         * Shorthand for {@link Roo.ComponentMgr#get}
524         * @param {String} id
525         * @return Roo.Component
526         */
527         getCmp : function(id){
528             return Roo.ComponentMgr.get(id);
529         },
530          
531         num : function(v, defaultValue){
532             if(typeof v != 'number'){
533                 return defaultValue;
534             }
535             return v;
536         },
537
538         destroy : function(){
539             for(var i = 0, a = arguments, len = a.length; i < len; i++) {
540                 var as = a[i];
541                 if(as){
542                     if(as.dom){
543                         as.removeAllListeners();
544                         as.remove();
545                         continue;
546                     }
547                     if(typeof as.purgeListeners == 'function'){
548                         as.purgeListeners();
549                     }
550                     if(typeof as.destroy == 'function'){
551                         as.destroy();
552                     }
553                 }
554             }
555         },
556
557         // inpired by a similar function in mootools library
558         /**
559          * Returns the type of object that is passed in. If the object passed in is null or undefined it
560          * return false otherwise it returns one of the following values:<ul>
561          * <li><b>string</b>: If the object passed is a string</li>
562          * <li><b>number</b>: If the object passed is a number</li>
563          * <li><b>boolean</b>: If the object passed is a boolean value</li>
564          * <li><b>function</b>: If the object passed is a function reference</li>
565          * <li><b>object</b>: If the object passed is an object</li>
566          * <li><b>array</b>: If the object passed is an array</li>
567          * <li><b>regexp</b>: If the object passed is a regular expression</li>
568          * <li><b>element</b>: If the object passed is a DOM Element</li>
569          * <li><b>nodelist</b>: If the object passed is a DOM NodeList</li>
570          * <li><b>textnode</b>: If the object passed is a DOM text node and contains something other than whitespace</li>
571          * <li><b>whitespace</b>: If the object passed is a DOM text node and contains only whitespace</li>
572          * @param {Mixed} object
573          * @return {String}
574          */
575         type : function(o){
576             if(o === undefined || o === null){
577                 return false;
578             }
579             if(o.htmlElement){
580                 return 'element';
581             }
582             var t = typeof o;
583             if(t == 'object' && o.nodeName) {
584                 switch(o.nodeType) {
585                     case 1: return 'element';
586                     case 3: return (/\S/).test(o.nodeValue) ? 'textnode' : 'whitespace';
587                 }
588             }
589             if(t == 'object' || t == 'function') {
590                 switch(o.constructor) {
591                     case Array: return 'array';
592                     case RegExp: return 'regexp';
593                 }
594                 if(typeof o.length == 'number' && typeof o.item == 'function') {
595                     return 'nodelist';
596                 }
597             }
598             return t;
599         },
600
601         /**
602          * Returns true if the passed value is null, undefined or an empty string (optional).
603          * @param {Mixed} value The value to test
604          * @param {Boolean} allowBlank (optional) Pass true if an empty string is not considered empty
605          * @return {Boolean}
606          */
607         isEmpty : function(v, allowBlank){
608             return v === null || v === undefined || (!allowBlank ? v === '' : false);
609         },
610         
611         /** @type Boolean */
612         isOpera : isOpera,
613         /** @type Boolean */
614         isSafari : isSafari,
615         /** @type Boolean */
616         isFirefox : isFirefox,
617         /** @type Boolean */
618         isIE : isIE,
619         /** @type Boolean */
620         isIE7 : isIE7,
621         /** @type Boolean */
622         isIE11 : isIE11,
623         /** @type Boolean */
624         isGecko : isGecko,
625         /** @type Boolean */
626         isBorderBox : isBorderBox,
627         /** @type Boolean */
628         isWindows : isWindows,
629         /** @type Boolean */
630         isLinux : isLinux,
631         /** @type Boolean */
632         isMac : isMac,
633         /** @type Boolean */
634         isIOS : isIOS,
635         /** @type Boolean */
636         isTouch : isTouch,
637
638         /**
639          * By default, Ext intelligently decides whether floating elements should be shimmed. If you are using flash,
640          * you may want to set this to true.
641          * @type Boolean
642          */
643         useShims : ((isIE && !isIE7) || (isGecko && isMac)),
644         
645         
646                 
647         /**
648          * Selects a single element as a Roo Element
649          * This is about as close as you can get to jQuery's $('do crazy stuff')
650          * @param {String} selector The selector/xpath query
651          * @param {Node} root (optional) The start of the query (defaults to document).
652          * @return {Roo.Element}
653          */
654         selectNode : function(selector, root) 
655         {
656             var node = Roo.DomQuery.selectNode(selector,root);
657             return node ? Roo.get(node) : new Roo.Element(false);
658         }
659         
660     });
661
662
663 })();
664
665 Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data",
666                 "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout",
667                 "Roo.app", "Roo.ux",
668                 "Roo.bootstrap",
669                 "Roo.bootstrap.dash");
670 /*
671  * Based on:
672  * Ext JS Library 1.1.1
673  * Copyright(c) 2006-2007, Ext JS, LLC.
674  *
675  * Originally Released Under LGPL - original licence link has changed is not relivant.
676  *
677  * Fork - LGPL
678  * <script type="text/javascript">
679  */
680
681 (function() {    
682     // wrappedn so fnCleanup is not in global scope...
683     if(Roo.isIE) {
684         function fnCleanUp() {
685             var p = Function.prototype;
686             delete p.createSequence;
687             delete p.defer;
688             delete p.createDelegate;
689             delete p.createCallback;
690             delete p.createInterceptor;
691
692             window.detachEvent("onunload", fnCleanUp);
693         }
694         window.attachEvent("onunload", fnCleanUp);
695     }
696 })();
697
698
699 /**
700  * @class Function
701  * These functions are available on every Function object (any JavaScript function).
702  */
703 Roo.apply(Function.prototype, {
704      /**
705      * Creates a callback that passes arguments[0], arguments[1], arguments[2], ...
706      * Call directly on any function. Example: <code>myFunction.createCallback(myarg, myarg2)</code>
707      * Will create a function that is bound to those 2 args.
708      * @return {Function} The new function
709     */
710     createCallback : function(/*args...*/){
711         // make args available, in function below
712         var args = arguments;
713         var method = this;
714         return function() {
715             return method.apply(window, args);
716         };
717     },
718
719     /**
720      * Creates a delegate (callback) that sets the scope to obj.
721      * Call directly on any function. Example: <code>this.myFunction.createDelegate(this)</code>
722      * Will create a function that is automatically scoped to this.
723      * @param {Object} obj (optional) The object for which the scope is set
724      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
725      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
726      *                                             if a number the args are inserted at the specified position
727      * @return {Function} The new function
728      */
729     createDelegate : function(obj, args, appendArgs){
730         var method = this;
731         return function() {
732             var callArgs = args || arguments;
733             if(appendArgs === true){
734                 callArgs = Array.prototype.slice.call(arguments, 0);
735                 callArgs = callArgs.concat(args);
736             }else if(typeof appendArgs == "number"){
737                 callArgs = Array.prototype.slice.call(arguments, 0); // copy arguments first
738                 var applyArgs = [appendArgs, 0].concat(args); // create method call params
739                 Array.prototype.splice.apply(callArgs, applyArgs); // splice them in
740             }
741             return method.apply(obj || window, callArgs);
742         };
743     },
744
745     /**
746      * Calls this function after the number of millseconds specified.
747      * @param {Number} millis The number of milliseconds for the setTimeout call (if 0 the function is executed immediately)
748      * @param {Object} obj (optional) The object for which the scope is set
749      * @param {Array} args (optional) Overrides arguments for the call. (Defaults to the arguments passed by the caller)
750      * @param {Boolean/Number} appendArgs (optional) if True args are appended to call args instead of overriding,
751      *                                             if a number the args are inserted at the specified position
752      * @return {Number} The timeout id that can be used with clearTimeout
753      */
754     defer : function(millis, obj, args, appendArgs){
755         var fn = this.createDelegate(obj, args, appendArgs);
756         if(millis){
757             return setTimeout(fn, millis);
758         }
759         fn();
760         return 0;
761     },
762     /**
763      * Create a combined function call sequence of the original function + the passed function.
764      * The resulting function returns the results of the original function.
765      * The passed fcn is called with the parameters of the original function
766      * @param {Function} fcn The function to sequence
767      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
768      * @return {Function} The new function
769      */
770     createSequence : function(fcn, scope){
771         if(typeof fcn != "function"){
772             return this;
773         }
774         var method = this;
775         return function() {
776             var retval = method.apply(this || window, arguments);
777             fcn.apply(scope || this || window, arguments);
778             return retval;
779         };
780     },
781
782     /**
783      * Creates an interceptor function. The passed fcn is called before the original one. If it returns false, the original one is not called.
784      * The resulting function returns the results of the original function.
785      * The passed fcn is called with the parameters of the original function.
786      * @addon
787      * @param {Function} fcn The function to call before the original
788      * @param {Object} scope (optional) The scope of the passed fcn (Defaults to scope of original function or window)
789      * @return {Function} The new function
790      */
791     createInterceptor : function(fcn, scope){
792         if(typeof fcn != "function"){
793             return this;
794         }
795         var method = this;
796         return function() {
797             fcn.target = this;
798             fcn.method = method;
799             if(fcn.apply(scope || this || window, arguments) === false){
800                 return;
801             }
802             return method.apply(this || window, arguments);
803         };
804     }
805 });
806 /*
807  * Based on:
808  * Ext JS Library 1.1.1
809  * Copyright(c) 2006-2007, Ext JS, LLC.
810  *
811  * Originally Released Under LGPL - original licence link has changed is not relivant.
812  *
813  * Fork - LGPL
814  * <script type="text/javascript">
815  */
816
817 Roo.applyIf(String, {
818     
819     /** @scope String */
820     
821     /**
822      * Escapes the passed string for ' and \
823      * @param {String} string The string to escape
824      * @return {String} The escaped string
825      * @static
826      */
827     escape : function(string) {
828         return string.replace(/('|\\)/g, "\\$1");
829     },
830
831     /**
832      * Pads the left side of a string with a specified character.  This is especially useful
833      * for normalizing number and date strings.  Example usage:
834      * <pre><code>
835 var s = String.leftPad('123', 5, '0');
836 // s now contains the string: '00123'
837 </code></pre>
838      * @param {String} string The original string
839      * @param {Number} size The total length of the output string
840      * @param {String} char (optional) The character with which to pad the original string (defaults to empty string " ")
841      * @return {String} The padded string
842      * @static
843      */
844     leftPad : function (val, size, ch) {
845         var result = new String(val);
846         if(ch === null || ch === undefined || ch === '') {
847             ch = " ";
848         }
849         while (result.length < size) {
850             result = ch + result;
851         }
852         return result;
853     },
854
855     /**
856      * Allows you to define a tokenized string and pass an arbitrary number of arguments to replace the tokens.  Each
857      * token must be unique, and must increment in the format {0}, {1}, etc.  Example usage:
858      * <pre><code>
859 var cls = 'my-class', text = 'Some text';
860 var s = String.format('<div class="{0}">{1}</div>', cls, text);
861 // s now contains the string: '<div class="my-class">Some text</div>'
862 </code></pre>
863      * @param {String} string The tokenized string to be formatted
864      * @param {String} value1 The value to replace token {0}
865      * @param {String} value2 Etc...
866      * @return {String} The formatted string
867      * @static
868      */
869     format : function(format){
870         var args = Array.prototype.slice.call(arguments, 1);
871         return format.replace(/\{(\d+)\}/g, function(m, i){
872             return Roo.util.Format.htmlEncode(args[i]);
873         });
874     }
875 });
876
877 /**
878  * Utility function that allows you to easily switch a string between two alternating values.  The passed value
879  * is compared to the current string, and if they are equal, the other value that was passed in is returned.  If
880  * they are already different, the first value passed in is returned.  Note that this method returns the new value
881  * but does not change the current string.
882  * <pre><code>
883 // alternate sort directions
884 sort = sort.toggle('ASC', 'DESC');
885
886 // instead of conditional logic:
887 sort = (sort == 'ASC' ? 'DESC' : 'ASC');
888 </code></pre>
889  * @param {String} value The value to compare to the current string
890  * @param {String} other The new value to use if the string already equals the first value passed in
891  * @return {String} The new value
892  */
893  
894 String.prototype.toggle = function(value, other){
895     return this == value ? other : value;
896 };/*
897  * Based on:
898  * Ext JS Library 1.1.1
899  * Copyright(c) 2006-2007, Ext JS, LLC.
900  *
901  * Originally Released Under LGPL - original licence link has changed is not relivant.
902  *
903  * Fork - LGPL
904  * <script type="text/javascript">
905  */
906
907  /**
908  * @class Number
909  */
910 Roo.applyIf(Number.prototype, {
911     /**
912      * Checks whether or not the current number is within a desired range.  If the number is already within the
913      * range it is returned, otherwise the min or max value is returned depending on which side of the range is
914      * exceeded.  Note that this method returns the constrained value but does not change the current number.
915      * @param {Number} min The minimum number in the range
916      * @param {Number} max The maximum number in the range
917      * @return {Number} The constrained value if outside the range, otherwise the current value
918      */
919     constrain : function(min, max){
920         return Math.min(Math.max(this, min), max);
921     }
922 });/*
923  * Based on:
924  * Ext JS Library 1.1.1
925  * Copyright(c) 2006-2007, Ext JS, LLC.
926  *
927  * Originally Released Under LGPL - original licence link has changed is not relivant.
928  *
929  * Fork - LGPL
930  * <script type="text/javascript">
931  */
932  /**
933  * @class Array
934  */
935 Roo.applyIf(Array.prototype, {
936     /**
937      * 
938      * Checks whether or not the specified object exists in the array.
939      * @param {Object} o The object to check for
940      * @return {Number} The index of o in the array (or -1 if it is not found)
941      */
942     indexOf : function(o){
943        for (var i = 0, len = this.length; i < len; i++){
944               if(this[i] == o) return i;
945        }
946            return -1;
947     },
948
949     /**
950      * Removes the specified object from the array.  If the object is not found nothing happens.
951      * @param {Object} o The object to remove
952      */
953     remove : function(o){
954        var index = this.indexOf(o);
955        if(index != -1){
956            this.splice(index, 1);
957        }
958     },
959     /**
960      * Map (JS 1.6 compatibility)
961      * @param {Function} function  to call
962      */
963     map : function(fun )
964     {
965         var len = this.length >>> 0;
966         if (typeof fun != "function")
967             throw new TypeError();
968
969         var res = new Array(len);
970         var thisp = arguments[1];
971         for (var i = 0; i < len; i++)
972         {
973             if (i in this)
974                 res[i] = fun.call(thisp, this[i], i, this);
975         }
976
977         return res;
978     }
979     
980 });
981
982
983  /*
984  * Based on:
985  * Ext JS Library 1.1.1
986  * Copyright(c) 2006-2007, Ext JS, LLC.
987  *
988  * Originally Released Under LGPL - original licence link has changed is not relivant.
989  *
990  * Fork - LGPL
991  * <script type="text/javascript">
992  */
993
994 /**
995  * @class Date
996  *
997  * The date parsing and format syntax is a subset of
998  * <a href="http://www.php.net/date">PHP's date() function</a>, and the formats that are
999  * supported will provide results equivalent to their PHP versions.
1000  *
1001  * Following is the list of all currently supported formats:
1002  *<pre>
1003 Sample date:
1004 'Wed Jan 10 2007 15:05:01 GMT-0600 (Central Standard Time)'
1005
1006 Format  Output      Description
1007 ------  ----------  --------------------------------------------------------------
1008   d      10         Day of the month, 2 digits with leading zeros
1009   D      Wed        A textual representation of a day, three letters
1010   j      10         Day of the month without leading zeros
1011   l      Wednesday  A full textual representation of the day of the week
1012   S      th         English ordinal day of month suffix, 2 chars (use with j)
1013   w      3          Numeric representation of the day of the week
1014   z      9          The julian date, or day of the year (0-365)
1015   W      01         ISO-8601 2-digit week number of year, weeks starting on Monday (00-52)
1016   F      January    A full textual representation of the month
1017   m      01         Numeric representation of a month, with leading zeros
1018   M      Jan        Month name abbreviation, three letters
1019   n      1          Numeric representation of a month, without leading zeros
1020   t      31         Number of days in the given month
1021   L      0          Whether it's a leap year (1 if it is a leap year, else 0)
1022   Y      2007       A full numeric representation of a year, 4 digits
1023   y      07         A two digit representation of a year
1024   a      pm         Lowercase Ante meridiem and Post meridiem
1025   A      PM         Uppercase Ante meridiem and Post meridiem
1026   g      3          12-hour format of an hour without leading zeros
1027   G      15         24-hour format of an hour without leading zeros
1028   h      03         12-hour format of an hour with leading zeros
1029   H      15         24-hour format of an hour with leading zeros
1030   i      05         Minutes with leading zeros
1031   s      01         Seconds, with leading zeros
1032   O      -0600      Difference to Greenwich time (GMT) in hours (Allows +08, without minutes)
1033   P      -06:00     Difference to Greenwich time (GMT) with colon between hours and minutes
1034   T      CST        Timezone setting of the machine running the code
1035   Z      -21600     Timezone offset in seconds (negative if west of UTC, positive if east)
1036 </pre>
1037  *
1038  * Example usage (note that you must escape format specifiers with '\\' to render them as character literals):
1039  * <pre><code>
1040 var dt = new Date('1/10/2007 03:05:01 PM GMT-0600');
1041 document.write(dt.format('Y-m-d'));                         //2007-01-10
1042 document.write(dt.format('F j, Y, g:i a'));                 //January 10, 2007, 3:05 pm
1043 document.write(dt.format('l, \\t\\he dS of F Y h:i:s A'));  //Wednesday, the 10th of January 2007 03:05:01 PM
1044  </code></pre>
1045  *
1046  * Here are some standard date/time patterns that you might find helpful.  They
1047  * are not part of the source of Date.js, but to use them you can simply copy this
1048  * block of code into any script that is included after Date.js and they will also become
1049  * globally available on the Date object.  Feel free to add or remove patterns as needed in your code.
1050  * <pre><code>
1051 Date.patterns = {
1052     ISO8601Long:"Y-m-d H:i:s",
1053     ISO8601Short:"Y-m-d",
1054     ShortDate: "n/j/Y",
1055     LongDate: "l, F d, Y",
1056     FullDateTime: "l, F d, Y g:i:s A",
1057     MonthDay: "F d",
1058     ShortTime: "g:i A",
1059     LongTime: "g:i:s A",
1060     SortableDateTime: "Y-m-d\\TH:i:s",
1061     UniversalSortableDateTime: "Y-m-d H:i:sO",
1062     YearMonth: "F, Y"
1063 };
1064 </code></pre>
1065  *
1066  * Example usage:
1067  * <pre><code>
1068 var dt = new Date();
1069 document.write(dt.format(Date.patterns.ShortDate));
1070  </code></pre>
1071  */
1072
1073 /*
1074  * Most of the date-formatting functions below are the excellent work of Baron Schwartz.
1075  * They generate precompiled functions from date formats instead of parsing and
1076  * processing the pattern every time you format a date.  These functions are available
1077  * on every Date object (any javascript function).
1078  *
1079  * The original article and download are here:
1080  * http://www.xaprb.com/blog/2005/12/12/javascript-closures-for-runtime-efficiency/
1081  *
1082  */
1083  
1084  
1085  // was in core
1086 /**
1087  Returns the number of milliseconds between this date and date
1088  @param {Date} date (optional) Defaults to now
1089  @return {Number} The diff in milliseconds
1090  @member Date getElapsed
1091  */
1092 Date.prototype.getElapsed = function(date) {
1093         return Math.abs((date || new Date()).getTime()-this.getTime());
1094 };
1095 // was in date file..
1096
1097
1098 // private
1099 Date.parseFunctions = {count:0};
1100 // private
1101 Date.parseRegexes = [];
1102 // private
1103 Date.formatFunctions = {count:0};
1104
1105 // private
1106 Date.prototype.dateFormat = function(format) {
1107     if (Date.formatFunctions[format] == null) {
1108         Date.createNewFormat(format);
1109     }
1110     var func = Date.formatFunctions[format];
1111     return this[func]();
1112 };
1113
1114
1115 /**
1116  * Formats a date given the supplied format string
1117  * @param {String} format The format string
1118  * @return {String} The formatted date
1119  * @method
1120  */
1121 Date.prototype.format = Date.prototype.dateFormat;
1122
1123 // private
1124 Date.createNewFormat = function(format) {
1125     var funcName = "format" + Date.formatFunctions.count++;
1126     Date.formatFunctions[format] = funcName;
1127     var code = "Date.prototype." + funcName + " = function(){return ";
1128     var special = false;
1129     var ch = '';
1130     for (var i = 0; i < format.length; ++i) {
1131         ch = format.charAt(i);
1132         if (!special && ch == "\\") {
1133             special = true;
1134         }
1135         else if (special) {
1136             special = false;
1137             code += "'" + String.escape(ch) + "' + ";
1138         }
1139         else {
1140             code += Date.getFormatCode(ch);
1141         }
1142     }
1143     /** eval:var:zzzzzzzzzzzzz */
1144     eval(code.substring(0, code.length - 3) + ";}");
1145 };
1146
1147 // private
1148 Date.getFormatCode = function(character) {
1149     switch (character) {
1150     case "d":
1151         return "String.leftPad(this.getDate(), 2, '0') + ";
1152     case "D":
1153         return "Date.dayNames[this.getDay()].substring(0, 3) + ";
1154     case "j":
1155         return "this.getDate() + ";
1156     case "l":
1157         return "Date.dayNames[this.getDay()] + ";
1158     case "S":
1159         return "this.getSuffix() + ";
1160     case "w":
1161         return "this.getDay() + ";
1162     case "z":
1163         return "this.getDayOfYear() + ";
1164     case "W":
1165         return "this.getWeekOfYear() + ";
1166     case "F":
1167         return "Date.monthNames[this.getMonth()] + ";
1168     case "m":
1169         return "String.leftPad(this.getMonth() + 1, 2, '0') + ";
1170     case "M":
1171         return "Date.monthNames[this.getMonth()].substring(0, 3) + ";
1172     case "n":
1173         return "(this.getMonth() + 1) + ";
1174     case "t":
1175         return "this.getDaysInMonth() + ";
1176     case "L":
1177         return "(this.isLeapYear() ? 1 : 0) + ";
1178     case "Y":
1179         return "this.getFullYear() + ";
1180     case "y":
1181         return "('' + this.getFullYear()).substring(2, 4) + ";
1182     case "a":
1183         return "(this.getHours() < 12 ? 'am' : 'pm') + ";
1184     case "A":
1185         return "(this.getHours() < 12 ? 'AM' : 'PM') + ";
1186     case "g":
1187         return "((this.getHours() % 12) ? this.getHours() % 12 : 12) + ";
1188     case "G":
1189         return "this.getHours() + ";
1190     case "h":
1191         return "String.leftPad((this.getHours() % 12) ? this.getHours() % 12 : 12, 2, '0') + ";
1192     case "H":
1193         return "String.leftPad(this.getHours(), 2, '0') + ";
1194     case "i":
1195         return "String.leftPad(this.getMinutes(), 2, '0') + ";
1196     case "s":
1197         return "String.leftPad(this.getSeconds(), 2, '0') + ";
1198     case "O":
1199         return "this.getGMTOffset() + ";
1200     case "P":
1201         return "this.getGMTColonOffset() + ";
1202     case "T":
1203         return "this.getTimezone() + ";
1204     case "Z":
1205         return "(this.getTimezoneOffset() * -60) + ";
1206     default:
1207         return "'" + String.escape(character) + "' + ";
1208     }
1209 };
1210
1211 /**
1212  * Parses the passed string using the specified format. Note that this function expects dates in normal calendar
1213  * format, meaning that months are 1-based (1 = January) and not zero-based like in JavaScript dates.  Any part of
1214  * the date format that is not specified will default to the current date value for that part.  Time parts can also
1215  * be specified, but default to 0.  Keep in mind that the input date string must precisely match the specified format
1216  * string or the parse operation will fail.
1217  * Example Usage:
1218 <pre><code>
1219 //dt = Fri May 25 2007 (current date)
1220 var dt = new Date();
1221
1222 //dt = Thu May 25 2006 (today's month/day in 2006)
1223 dt = Date.parseDate("2006", "Y");
1224
1225 //dt = Sun Jan 15 2006 (all date parts specified)
1226 dt = Date.parseDate("2006-1-15", "Y-m-d");
1227
1228 //dt = Sun Jan 15 2006 15:20:01 GMT-0600 (CST)
1229 dt = Date.parseDate("2006-1-15 3:20:01 PM", "Y-m-d h:i:s A" );
1230 </code></pre>
1231  * @param {String} input The unparsed date as a string
1232  * @param {String} format The format the date is in
1233  * @return {Date} The parsed date
1234  * @static
1235  */
1236 Date.parseDate = function(input, format) {
1237     if (Date.parseFunctions[format] == null) {
1238         Date.createParser(format);
1239     }
1240     var func = Date.parseFunctions[format];
1241     return Date[func](input);
1242 };
1243 /**
1244  * @private
1245  */
1246
1247 Date.createParser = function(format) {
1248     var funcName = "parse" + Date.parseFunctions.count++;
1249     var regexNum = Date.parseRegexes.length;
1250     var currentGroup = 1;
1251     Date.parseFunctions[format] = funcName;
1252
1253     var code = "Date." + funcName + " = function(input){\n"
1254         + "var y = -1, m = -1, d = -1, h = -1, i = -1, s = -1, o, z, v;\n"
1255         + "var d = new Date();\n"
1256         + "y = d.getFullYear();\n"
1257         + "m = d.getMonth();\n"
1258         + "d = d.getDate();\n"
1259         + "if (typeof(input) !== 'string') { input = input.toString(); }\n"
1260         + "var results = input.match(Date.parseRegexes[" + regexNum + "]);\n"
1261         + "if (results && results.length > 0) {";
1262     var regex = "";
1263
1264     var special = false;
1265     var ch = '';
1266     for (var i = 0; i < format.length; ++i) {
1267         ch = format.charAt(i);
1268         if (!special && ch == "\\") {
1269             special = true;
1270         }
1271         else if (special) {
1272             special = false;
1273             regex += String.escape(ch);
1274         }
1275         else {
1276             var obj = Date.formatCodeToRegex(ch, currentGroup);
1277             currentGroup += obj.g;
1278             regex += obj.s;
1279             if (obj.g && obj.c) {
1280                 code += obj.c;
1281             }
1282         }
1283     }
1284
1285     code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n"
1286         + "{v = new Date(y, m, d, h, i, s);}\n"
1287         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n"
1288         + "{v = new Date(y, m, d, h, i);}\n"
1289         + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n"
1290         + "{v = new Date(y, m, d, h);}\n"
1291         + "else if (y >= 0 && m >= 0 && d > 0)\n"
1292         + "{v = new Date(y, m, d);}\n"
1293         + "else if (y >= 0 && m >= 0)\n"
1294         + "{v = new Date(y, m);}\n"
1295         + "else if (y >= 0)\n"
1296         + "{v = new Date(y);}\n"
1297         + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset
1298         + "    ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset
1299         + "        v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset
1300         + ";}";
1301
1302     Date.parseRegexes[regexNum] = new RegExp("^" + regex + "$");
1303     /** eval:var:zzzzzzzzzzzzz */
1304     eval(code);
1305 };
1306
1307 // private
1308 Date.formatCodeToRegex = function(character, currentGroup) {
1309     switch (character) {
1310     case "D":
1311         return {g:0,
1312         c:null,
1313         s:"(?:Sun|Mon|Tue|Wed|Thu|Fri|Sat)"};
1314     case "j":
1315         return {g:1,
1316             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1317             s:"(\\d{1,2})"}; // day of month without leading zeroes
1318     case "d":
1319         return {g:1,
1320             c:"d = parseInt(results[" + currentGroup + "], 10);\n",
1321             s:"(\\d{2})"}; // day of month with leading zeroes
1322     case "l":
1323         return {g:0,
1324             c:null,
1325             s:"(?:" + Date.dayNames.join("|") + ")"};
1326     case "S":
1327         return {g:0,
1328             c:null,
1329             s:"(?:st|nd|rd|th)"};
1330     case "w":
1331         return {g:0,
1332             c:null,
1333             s:"\\d"};
1334     case "z":
1335         return {g:0,
1336             c:null,
1337             s:"(?:\\d{1,3})"};
1338     case "W":
1339         return {g:0,
1340             c:null,
1341             s:"(?:\\d{2})"};
1342     case "F":
1343         return {g:1,
1344             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "].substring(0, 3)], 10);\n",
1345             s:"(" + Date.monthNames.join("|") + ")"};
1346     case "M":
1347         return {g:1,
1348             c:"m = parseInt(Date.monthNumbers[results[" + currentGroup + "]], 10);\n",
1349             s:"(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)"};
1350     case "n":
1351         return {g:1,
1352             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1353             s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros
1354     case "m":
1355         return {g:1,
1356             c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n",
1357             s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros
1358     case "t":
1359         return {g:0,
1360             c:null,
1361             s:"\\d{1,2}"};
1362     case "L":
1363         return {g:0,
1364             c:null,
1365             s:"(?:1|0)"};
1366     case "Y":
1367         return {g:1,
1368             c:"y = parseInt(results[" + currentGroup + "], 10);\n",
1369             s:"(\\d{4})"};
1370     case "y":
1371         return {g:1,
1372             c:"var ty = parseInt(results[" + currentGroup + "], 10);\n"
1373                 + "y = ty > Date.y2kYear ? 1900 + ty : 2000 + ty;\n",
1374             s:"(\\d{1,2})"};
1375     case "a":
1376         return {g:1,
1377             c:"if (results[" + currentGroup + "] == 'am') {\n"
1378                 + "if (h == 12) { h = 0; }\n"
1379                 + "} else { if (h < 12) { h += 12; }}",
1380             s:"(am|pm)"};
1381     case "A":
1382         return {g:1,
1383             c:"if (results[" + currentGroup + "] == 'AM') {\n"
1384                 + "if (h == 12) { h = 0; }\n"
1385                 + "} else { if (h < 12) { h += 12; }}",
1386             s:"(AM|PM)"};
1387     case "g":
1388     case "G":
1389         return {g:1,
1390             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1391             s:"(\\d{1,2})"}; // 12/24-hr format  format of an hour without leading zeroes
1392     case "h":
1393     case "H":
1394         return {g:1,
1395             c:"h = parseInt(results[" + currentGroup + "], 10);\n",
1396             s:"(\\d{2})"}; //  12/24-hr format  format of an hour with leading zeroes
1397     case "i":
1398         return {g:1,
1399             c:"i = parseInt(results[" + currentGroup + "], 10);\n",
1400             s:"(\\d{2})"};
1401     case "s":
1402         return {g:1,
1403             c:"s = parseInt(results[" + currentGroup + "], 10);\n",
1404             s:"(\\d{2})"};
1405     case "O":
1406         return {g:1,
1407             c:[
1408                 "o = results[", currentGroup, "];\n",
1409                 "var sn = o.substring(0,1);\n", // get + / - sign
1410                 "var hr = o.substring(1,3)*1 + Math.floor(o.substring(3,5) / 60);\n", // get hours (performs minutes-to-hour conversion also)
1411                 "var mn = o.substring(3,5) % 60;\n", // get minutes
1412                 "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n", // -12hrs <= GMT offset <= 14hrs
1413                 "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1414             ].join(""),
1415             s:"([+\-]\\d{2,4})"};
1416     
1417     
1418     case "P":
1419         return {g:1,
1420                 c:[
1421                    "o = results[", currentGroup, "];\n",
1422                    "var sn = o.substring(0,1);\n",
1423                    "var hr = o.substring(1,3)*1 + Math.floor(o.substring(4,6) / 60);\n",
1424                    "var mn = o.substring(4,6) % 60;\n",
1425                    "o = ((-12 <= (hr*60 + mn)/60) && ((hr*60 + mn)/60 <= 14))?\n",
1426                         "    (sn + String.leftPad(hr, 2, 0) + String.leftPad(mn, 2, 0)) : null;\n"
1427             ].join(""),
1428             s:"([+\-]\\d{4})"};
1429     case "T":
1430         return {g:0,
1431             c:null,
1432             s:"[A-Z]{1,4}"}; // timezone abbrev. may be between 1 - 4 chars
1433     case "Z":
1434         return {g:1,
1435             c:"z = results[" + currentGroup + "];\n" // -43200 <= UTC offset <= 50400
1436                   + "z = (-43200 <= z*1 && z*1 <= 50400)? z : null;\n",
1437             s:"([+\-]?\\d{1,5})"}; // leading '+' sign is optional for UTC offset
1438     default:
1439         return {g:0,
1440             c:null,
1441             s:String.escape(character)};
1442     }
1443 };
1444
1445 /**
1446  * Get the timezone abbreviation of the current date (equivalent to the format specifier 'T').
1447  * @return {String} The abbreviated timezone name (e.g. 'CST')
1448  */
1449 Date.prototype.getTimezone = function() {
1450     return this.toString().replace(/^.*? ([A-Z]{1,4})[\-+][0-9]{4} .*$/, "$1");
1451 };
1452
1453 /**
1454  * Get the offset from GMT of the current date (equivalent to the format specifier 'O').
1455  * @return {String} The 4-character offset string prefixed with + or - (e.g. '-0600')
1456  */
1457 Date.prototype.getGMTOffset = function() {
1458     return (this.getTimezoneOffset() > 0 ? "-" : "+")
1459         + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1460         + String.leftPad(this.getTimezoneOffset() % 60, 2, "0");
1461 };
1462
1463 /**
1464  * Get the offset from GMT of the current date (equivalent to the format specifier 'P').
1465  * @return {String} 2-characters representing hours and 2-characters representing minutes
1466  * seperated by a colon and prefixed with + or - (e.g. '-06:00')
1467  */
1468 Date.prototype.getGMTColonOffset = function() {
1469         return (this.getTimezoneOffset() > 0 ? "-" : "+")
1470                 + String.leftPad(Math.abs(Math.floor(this.getTimezoneOffset() / 60)), 2, "0")
1471                 + ":"
1472                 + String.leftPad(this.getTimezoneOffset() %60, 2, "0");
1473 }
1474
1475 /**
1476  * Get the numeric day number of the year, adjusted for leap year.
1477  * @return {Number} 0 through 364 (365 in leap years)
1478  */
1479 Date.prototype.getDayOfYear = function() {
1480     var num = 0;
1481     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1482     for (var i = 0; i < this.getMonth(); ++i) {
1483         num += Date.daysInMonth[i];
1484     }
1485     return num + this.getDate() - 1;
1486 };
1487
1488 /**
1489  * Get the string representation of the numeric week number of the year
1490  * (equivalent to the format specifier 'W').
1491  * @return {String} '00' through '52'
1492  */
1493 Date.prototype.getWeekOfYear = function() {
1494     // Skip to Thursday of this week
1495     var now = this.getDayOfYear() + (4 - this.getDay());
1496     // Find the first Thursday of the year
1497     var jan1 = new Date(this.getFullYear(), 0, 1);
1498     var then = (7 - jan1.getDay() + 4);
1499     return String.leftPad(((now - then) / 7) + 1, 2, "0");
1500 };
1501
1502 /**
1503  * Whether or not the current date is in a leap year.
1504  * @return {Boolean} True if the current date is in a leap year, else false
1505  */
1506 Date.prototype.isLeapYear = function() {
1507     var year = this.getFullYear();
1508     return ((year & 3) == 0 && (year % 100 || (year % 400 == 0 && year)));
1509 };
1510
1511 /**
1512  * Get the first day of the current month, adjusted for leap year.  The returned value
1513  * is the numeric day index within the week (0-6) which can be used in conjunction with
1514  * the {@link #monthNames} array to retrieve the textual day name.
1515  * Example:
1516  *<pre><code>
1517 var dt = new Date('1/10/2007');
1518 document.write(Date.dayNames[dt.getFirstDayOfMonth()]); //output: 'Monday'
1519 </code></pre>
1520  * @return {Number} The day number (0-6)
1521  */
1522 Date.prototype.getFirstDayOfMonth = function() {
1523     var day = (this.getDay() - (this.getDate() - 1)) % 7;
1524     return (day < 0) ? (day + 7) : day;
1525 };
1526
1527 /**
1528  * Get the last day of the current month, adjusted for leap year.  The returned value
1529  * is the numeric day index within the week (0-6) which can be used in conjunction with
1530  * the {@link #monthNames} array to retrieve the textual day name.
1531  * Example:
1532  *<pre><code>
1533 var dt = new Date('1/10/2007');
1534 document.write(Date.dayNames[dt.getLastDayOfMonth()]); //output: 'Wednesday'
1535 </code></pre>
1536  * @return {Number} The day number (0-6)
1537  */
1538 Date.prototype.getLastDayOfMonth = function() {
1539     var day = (this.getDay() + (Date.daysInMonth[this.getMonth()] - this.getDate())) % 7;
1540     return (day < 0) ? (day + 7) : day;
1541 };
1542
1543
1544 /**
1545  * Get the first date of this date's month
1546  * @return {Date}
1547  */
1548 Date.prototype.getFirstDateOfMonth = function() {
1549     return new Date(this.getFullYear(), this.getMonth(), 1);
1550 };
1551
1552 /**
1553  * Get the last date of this date's month
1554  * @return {Date}
1555  */
1556 Date.prototype.getLastDateOfMonth = function() {
1557     return new Date(this.getFullYear(), this.getMonth(), this.getDaysInMonth());
1558 };
1559 /**
1560  * Get the number of days in the current month, adjusted for leap year.
1561  * @return {Number} The number of days in the month
1562  */
1563 Date.prototype.getDaysInMonth = function() {
1564     Date.daysInMonth[1] = this.isLeapYear() ? 29 : 28;
1565     return Date.daysInMonth[this.getMonth()];
1566 };
1567
1568 /**
1569  * Get the English ordinal suffix of the current day (equivalent to the format specifier 'S').
1570  * @return {String} 'st, 'nd', 'rd' or 'th'
1571  */
1572 Date.prototype.getSuffix = function() {
1573     switch (this.getDate()) {
1574         case 1:
1575         case 21:
1576         case 31:
1577             return "st";
1578         case 2:
1579         case 22:
1580             return "nd";
1581         case 3:
1582         case 23:
1583             return "rd";
1584         default:
1585             return "th";
1586     }
1587 };
1588
1589 // private
1590 Date.daysInMonth = [31,28,31,30,31,30,31,31,30,31,30,31];
1591
1592 /**
1593  * An array of textual month names.
1594  * Override these values for international dates, for example...
1595  * Date.monthNames = ['JanInYourLang', 'FebInYourLang', ...];
1596  * @type Array
1597  * @static
1598  */
1599 Date.monthNames =
1600    ["January",
1601     "February",
1602     "March",
1603     "April",
1604     "May",
1605     "June",
1606     "July",
1607     "August",
1608     "September",
1609     "October",
1610     "November",
1611     "December"];
1612
1613 /**
1614  * An array of textual day names.
1615  * Override these values for international dates, for example...
1616  * Date.dayNames = ['SundayInYourLang', 'MondayInYourLang', ...];
1617  * @type Array
1618  * @static
1619  */
1620 Date.dayNames =
1621    ["Sunday",
1622     "Monday",
1623     "Tuesday",
1624     "Wednesday",
1625     "Thursday",
1626     "Friday",
1627     "Saturday"];
1628
1629 // private
1630 Date.y2kYear = 50;
1631 // private
1632 Date.monthNumbers = {
1633     Jan:0,
1634     Feb:1,
1635     Mar:2,
1636     Apr:3,
1637     May:4,
1638     Jun:5,
1639     Jul:6,
1640     Aug:7,
1641     Sep:8,
1642     Oct:9,
1643     Nov:10,
1644     Dec:11};
1645
1646 /**
1647  * Creates and returns a new Date instance with the exact same date value as the called instance.
1648  * Dates are copied and passed by reference, so if a copied date variable is modified later, the original
1649  * variable will also be changed.  When the intention is to create a new variable that will not
1650  * modify the original instance, you should create a clone.
1651  *
1652  * Example of correctly cloning a date:
1653  * <pre><code>
1654 //wrong way:
1655 var orig = new Date('10/1/2006');
1656 var copy = orig;
1657 copy.setDate(5);
1658 document.write(orig);  //returns 'Thu Oct 05 2006'!
1659
1660 //correct way:
1661 var orig = new Date('10/1/2006');
1662 var copy = orig.clone();
1663 copy.setDate(5);
1664 document.write(orig);  //returns 'Thu Oct 01 2006'
1665 </code></pre>
1666  * @return {Date} The new Date instance
1667  */
1668 Date.prototype.clone = function() {
1669         return new Date(this.getTime());
1670 };
1671
1672 /**
1673  * Clears any time information from this date
1674  @param {Boolean} clone true to create a clone of this date, clear the time and return it
1675  @return {Date} this or the clone
1676  */
1677 Date.prototype.clearTime = function(clone){
1678     if(clone){
1679         return this.clone().clearTime();
1680     }
1681     this.setHours(0);
1682     this.setMinutes(0);
1683     this.setSeconds(0);
1684     this.setMilliseconds(0);
1685     return this;
1686 };
1687
1688 // private
1689 // safari setMonth is broken
1690 if(Roo.isSafari){
1691     Date.brokenSetMonth = Date.prototype.setMonth;
1692         Date.prototype.setMonth = function(num){
1693                 if(num <= -1){
1694                         var n = Math.ceil(-num);
1695                         var back_year = Math.ceil(n/12);
1696                         var month = (n % 12) ? 12 - n % 12 : 0 ;
1697                         this.setFullYear(this.getFullYear() - back_year);
1698                         return Date.brokenSetMonth.call(this, month);
1699                 } else {
1700                         return Date.brokenSetMonth.apply(this, arguments);
1701                 }
1702         };
1703 }
1704
1705 /** Date interval constant 
1706 * @static 
1707 * @type String */
1708 Date.MILLI = "ms";
1709 /** Date interval constant 
1710 * @static 
1711 * @type String */
1712 Date.SECOND = "s";
1713 /** Date interval constant 
1714 * @static 
1715 * @type String */
1716 Date.MINUTE = "mi";
1717 /** Date interval constant 
1718 * @static 
1719 * @type String */
1720 Date.HOUR = "h";
1721 /** Date interval constant 
1722 * @static 
1723 * @type String */
1724 Date.DAY = "d";
1725 /** Date interval constant 
1726 * @static 
1727 * @type String */
1728 Date.MONTH = "mo";
1729 /** Date interval constant 
1730 * @static 
1731 * @type String */
1732 Date.YEAR = "y";
1733
1734 /**
1735  * Provides a convenient method of performing basic date arithmetic.  This method
1736  * does not modify the Date instance being called - it creates and returns
1737  * a new Date instance containing the resulting date value.
1738  *
1739  * Examples:
1740  * <pre><code>
1741 //Basic usage:
1742 var dt = new Date('10/29/2006').add(Date.DAY, 5);
1743 document.write(dt); //returns 'Fri Oct 06 2006 00:00:00'
1744
1745 //Negative values will subtract correctly:
1746 var dt2 = new Date('10/1/2006').add(Date.DAY, -5);
1747 document.write(dt2); //returns 'Tue Sep 26 2006 00:00:00'
1748
1749 //You can even chain several calls together in one line!
1750 var dt3 = new Date('10/1/2006').add(Date.DAY, 5).add(Date.HOUR, 8).add(Date.MINUTE, -30);
1751 document.write(dt3); //returns 'Fri Oct 06 2006 07:30:00'
1752  </code></pre>
1753  *
1754  * @param {String} interval   A valid date interval enum value
1755  * @param {Number} value      The amount to add to the current date
1756  * @return {Date} The new Date instance
1757  */
1758 Date.prototype.add = function(interval, value){
1759   var d = this.clone();
1760   if (!interval || value === 0) return d;
1761   switch(interval.toLowerCase()){
1762     case Date.MILLI:
1763       d.setMilliseconds(this.getMilliseconds() + value);
1764       break;
1765     case Date.SECOND:
1766       d.setSeconds(this.getSeconds() + value);
1767       break;
1768     case Date.MINUTE:
1769       d.setMinutes(this.getMinutes() + value);
1770       break;
1771     case Date.HOUR:
1772       d.setHours(this.getHours() + value);
1773       break;
1774     case Date.DAY:
1775       d.setDate(this.getDate() + value);
1776       break;
1777     case Date.MONTH:
1778       var day = this.getDate();
1779       if(day > 28){
1780           day = Math.min(day, this.getFirstDateOfMonth().add('mo', value).getLastDateOfMonth().getDate());
1781       }
1782       d.setDate(day);
1783       d.setMonth(this.getMonth() + value);
1784       break;
1785     case Date.YEAR:
1786       d.setFullYear(this.getFullYear() + value);
1787       break;
1788   }
1789   return d;
1790 };
1791 /*
1792  * Based on:
1793  * Ext JS Library 1.1.1
1794  * Copyright(c) 2006-2007, Ext JS, LLC.
1795  *
1796  * Originally Released Under LGPL - original licence link has changed is not relivant.
1797  *
1798  * Fork - LGPL
1799  * <script type="text/javascript">
1800  */
1801
1802 /**
1803  * @class Roo.lib.Dom
1804  * @static
1805  * 
1806  * Dom utils (from YIU afaik)
1807  * 
1808  **/
1809 Roo.lib.Dom = {
1810     /**
1811      * Get the view width
1812      * @param {Boolean} full True will get the full document, otherwise it's the view width
1813      * @return {Number} The width
1814      */
1815      
1816     getViewWidth : function(full) {
1817         return full ? this.getDocumentWidth() : this.getViewportWidth();
1818     },
1819     /**
1820      * Get the view height
1821      * @param {Boolean} full True will get the full document, otherwise it's the view height
1822      * @return {Number} The height
1823      */
1824     getViewHeight : function(full) {
1825         return full ? this.getDocumentHeight() : this.getViewportHeight();
1826     },
1827
1828     getDocumentHeight: function() {
1829         var scrollHeight = (document.compatMode != "CSS1Compat") ? document.body.scrollHeight : document.documentElement.scrollHeight;
1830         return Math.max(scrollHeight, this.getViewportHeight());
1831     },
1832
1833     getDocumentWidth: function() {
1834         var scrollWidth = (document.compatMode != "CSS1Compat") ? document.body.scrollWidth : document.documentElement.scrollWidth;
1835         return Math.max(scrollWidth, this.getViewportWidth());
1836     },
1837
1838     getViewportHeight: function() {
1839         var height = self.innerHeight;
1840         var mode = document.compatMode;
1841
1842         if ((mode || Roo.isIE) && !Roo.isOpera) {
1843             height = (mode == "CSS1Compat") ?
1844                      document.documentElement.clientHeight :
1845                      document.body.clientHeight;
1846         }
1847
1848         return height;
1849     },
1850
1851     getViewportWidth: function() {
1852         var width = self.innerWidth;
1853         var mode = document.compatMode;
1854
1855         if (mode || Roo.isIE) {
1856             width = (mode == "CSS1Compat") ?
1857                     document.documentElement.clientWidth :
1858                     document.body.clientWidth;
1859         }
1860         return width;
1861     },
1862
1863     isAncestor : function(p, c) {
1864         p = Roo.getDom(p);
1865         c = Roo.getDom(c);
1866         if (!p || !c) {
1867             return false;
1868         }
1869
1870         if (p.contains && !Roo.isSafari) {
1871             return p.contains(c);
1872         } else if (p.compareDocumentPosition) {
1873             return !!(p.compareDocumentPosition(c) & 16);
1874         } else {
1875             var parent = c.parentNode;
1876             while (parent) {
1877                 if (parent == p) {
1878                     return true;
1879                 }
1880                 else if (!parent.tagName || parent.tagName.toUpperCase() == "HTML") {
1881                     return false;
1882                 }
1883                 parent = parent.parentNode;
1884             }
1885             return false;
1886         }
1887     },
1888
1889     getRegion : function(el) {
1890         return Roo.lib.Region.getRegion(el);
1891     },
1892
1893     getY : function(el) {
1894         return this.getXY(el)[1];
1895     },
1896
1897     getX : function(el) {
1898         return this.getXY(el)[0];
1899     },
1900
1901     getXY : function(el) {
1902         var p, pe, b, scroll, bd = document.body;
1903         el = Roo.getDom(el);
1904         var fly = Roo.lib.AnimBase.fly;
1905         if (el.getBoundingClientRect) {
1906             b = el.getBoundingClientRect();
1907             scroll = fly(document).getScroll();
1908             return [b.left + scroll.left, b.top + scroll.top];
1909         }
1910         var x = 0, y = 0;
1911
1912         p = el;
1913
1914         var hasAbsolute = fly(el).getStyle("position") == "absolute";
1915
1916         while (p) {
1917
1918             x += p.offsetLeft;
1919             y += p.offsetTop;
1920
1921             if (!hasAbsolute && fly(p).getStyle("position") == "absolute") {
1922                 hasAbsolute = true;
1923             }
1924
1925             if (Roo.isGecko) {
1926                 pe = fly(p);
1927
1928                 var bt = parseInt(pe.getStyle("borderTopWidth"), 10) || 0;
1929                 var bl = parseInt(pe.getStyle("borderLeftWidth"), 10) || 0;
1930
1931
1932                 x += bl;
1933                 y += bt;
1934
1935
1936                 if (p != el && pe.getStyle('overflow') != 'visible') {
1937                     x += bl;
1938                     y += bt;
1939                 }
1940             }
1941             p = p.offsetParent;
1942         }
1943
1944         if (Roo.isSafari && hasAbsolute) {
1945             x -= bd.offsetLeft;
1946             y -= bd.offsetTop;
1947         }
1948
1949         if (Roo.isGecko && !hasAbsolute) {
1950             var dbd = fly(bd);
1951             x += parseInt(dbd.getStyle("borderLeftWidth"), 10) || 0;
1952             y += parseInt(dbd.getStyle("borderTopWidth"), 10) || 0;
1953         }
1954
1955         p = el.parentNode;
1956         while (p && p != bd) {
1957             if (!Roo.isOpera || (p.tagName != 'TR' && fly(p).getStyle("display") != "inline")) {
1958                 x -= p.scrollLeft;
1959                 y -= p.scrollTop;
1960             }
1961             p = p.parentNode;
1962         }
1963         return [x, y];
1964     },
1965  
1966   
1967
1968
1969     setXY : function(el, xy) {
1970         el = Roo.fly(el, '_setXY');
1971         el.position();
1972         var pts = el.translatePoints(xy);
1973         if (xy[0] !== false) {
1974             el.dom.style.left = pts.left + "px";
1975         }
1976         if (xy[1] !== false) {
1977             el.dom.style.top = pts.top + "px";
1978         }
1979     },
1980
1981     setX : function(el, x) {
1982         this.setXY(el, [x, false]);
1983     },
1984
1985     setY : function(el, y) {
1986         this.setXY(el, [false, y]);
1987     }
1988 };
1989 /*
1990  * Portions of this file are based on pieces of Yahoo User Interface Library
1991  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
1992  * YUI licensed under the BSD License:
1993  * http://developer.yahoo.net/yui/license.txt
1994  * <script type="text/javascript">
1995  *
1996  */
1997
1998 Roo.lib.Event = function() {
1999     var loadComplete = false;
2000     var listeners = [];
2001     var unloadListeners = [];
2002     var retryCount = 0;
2003     var onAvailStack = [];
2004     var counter = 0;
2005     var lastError = null;
2006
2007     return {
2008         POLL_RETRYS: 200,
2009         POLL_INTERVAL: 20,
2010         EL: 0,
2011         TYPE: 1,
2012         FN: 2,
2013         WFN: 3,
2014         OBJ: 3,
2015         ADJ_SCOPE: 4,
2016         _interval: null,
2017
2018         startInterval: function() {
2019             if (!this._interval) {
2020                 var self = this;
2021                 var callback = function() {
2022                     self._tryPreloadAttach();
2023                 };
2024                 this._interval = setInterval(callback, this.POLL_INTERVAL);
2025
2026             }
2027         },
2028
2029         onAvailable: function(p_id, p_fn, p_obj, p_override) {
2030             onAvailStack.push({ id:         p_id,
2031                 fn:         p_fn,
2032                 obj:        p_obj,
2033                 override:   p_override,
2034                 checkReady: false    });
2035
2036             retryCount = this.POLL_RETRYS;
2037             this.startInterval();
2038         },
2039
2040
2041         addListener: function(el, eventName, fn) {
2042             el = Roo.getDom(el);
2043             if (!el || !fn) {
2044                 return false;
2045             }
2046
2047             if ("unload" == eventName) {
2048                 unloadListeners[unloadListeners.length] =
2049                 [el, eventName, fn];
2050                 return true;
2051             }
2052
2053             var wrappedFn = function(e) {
2054                 return fn(Roo.lib.Event.getEvent(e));
2055             };
2056
2057             var li = [el, eventName, fn, wrappedFn];
2058
2059             var index = listeners.length;
2060             listeners[index] = li;
2061
2062             this.doAdd(el, eventName, wrappedFn, false);
2063             return true;
2064
2065         },
2066
2067
2068         removeListener: function(el, eventName, fn) {
2069             var i, len;
2070
2071             el = Roo.getDom(el);
2072
2073             if(!fn) {
2074                 return this.purgeElement(el, false, eventName);
2075             }
2076
2077
2078             if ("unload" == eventName) {
2079
2080                 for (i = 0,len = unloadListeners.length; i < len; i++) {
2081                     var li = unloadListeners[i];
2082                     if (li &&
2083                         li[0] == el &&
2084                         li[1] == eventName &&
2085                         li[2] == fn) {
2086                         unloadListeners.splice(i, 1);
2087                         return true;
2088                     }
2089                 }
2090
2091                 return false;
2092             }
2093
2094             var cacheItem = null;
2095
2096
2097             var index = arguments[3];
2098
2099             if ("undefined" == typeof index) {
2100                 index = this._getCacheIndex(el, eventName, fn);
2101             }
2102
2103             if (index >= 0) {
2104                 cacheItem = listeners[index];
2105             }
2106
2107             if (!el || !cacheItem) {
2108                 return false;
2109             }
2110
2111             this.doRemove(el, eventName, cacheItem[this.WFN], false);
2112
2113             delete listeners[index][this.WFN];
2114             delete listeners[index][this.FN];
2115             listeners.splice(index, 1);
2116
2117             return true;
2118
2119         },
2120
2121
2122         getTarget: function(ev, resolveTextNode) {
2123             ev = ev.browserEvent || ev;
2124             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2125             var t = ev.target || ev.srcElement;
2126             return this.resolveTextNode(t);
2127         },
2128
2129
2130         resolveTextNode: function(node) {
2131             if (Roo.isSafari && node && 3 == node.nodeType) {
2132                 return node.parentNode;
2133             } else {
2134                 return node;
2135             }
2136         },
2137
2138
2139         getPageX: function(ev) {
2140             ev = ev.browserEvent || ev;
2141             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2142             var x = ev.pageX;
2143             if (!x && 0 !== x) {
2144                 x = ev.clientX || 0;
2145
2146                 if (Roo.isIE) {
2147                     x += this.getScroll()[1];
2148                 }
2149             }
2150
2151             return x;
2152         },
2153
2154
2155         getPageY: function(ev) {
2156             ev = ev.browserEvent || ev;
2157             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2158             var y = ev.pageY;
2159             if (!y && 0 !== y) {
2160                 y = ev.clientY || 0;
2161
2162                 if (Roo.isIE) {
2163                     y += this.getScroll()[0];
2164                 }
2165             }
2166
2167
2168             return y;
2169         },
2170
2171
2172         getXY: function(ev) {
2173             ev = ev.browserEvent || ev;
2174             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2175             return [this.getPageX(ev), this.getPageY(ev)];
2176         },
2177
2178
2179         getRelatedTarget: function(ev) {
2180             ev = ev.browserEvent || ev;
2181             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2182             var t = ev.relatedTarget;
2183             if (!t) {
2184                 if (ev.type == "mouseout") {
2185                     t = ev.toElement;
2186                 } else if (ev.type == "mouseover") {
2187                     t = ev.fromElement;
2188                 }
2189             }
2190
2191             return this.resolveTextNode(t);
2192         },
2193
2194
2195         getTime: function(ev) {
2196             ev = ev.browserEvent || ev;
2197             ev = ev.touches ? (ev.touches[0] || ev.changedTouches[0] || ev )  : ev;
2198             if (!ev.time) {
2199                 var t = new Date().getTime();
2200                 try {
2201                     ev.time = t;
2202                 } catch(ex) {
2203                     this.lastError = ex;
2204                     return t;
2205                 }
2206             }
2207
2208             return ev.time;
2209         },
2210
2211
2212         stopEvent: function(ev) {
2213             this.stopPropagation(ev);
2214             this.preventDefault(ev);
2215         },
2216
2217
2218         stopPropagation: function(ev) {
2219             ev = ev.browserEvent || ev;
2220             if (ev.stopPropagation) {
2221                 ev.stopPropagation();
2222             } else {
2223                 ev.cancelBubble = true;
2224             }
2225         },
2226
2227
2228         preventDefault: function(ev) {
2229             ev = ev.browserEvent || ev;
2230             if(ev.preventDefault) {
2231                 ev.preventDefault();
2232             } else {
2233                 ev.returnValue = false;
2234             }
2235         },
2236
2237
2238         getEvent: function(e) {
2239             var ev = e || window.event;
2240             if (!ev) {
2241                 var c = this.getEvent.caller;
2242                 while (c) {
2243                     ev = c.arguments[0];
2244                     if (ev && Event == ev.constructor) {
2245                         break;
2246                     }
2247                     c = c.caller;
2248                 }
2249             }
2250             return ev;
2251         },
2252
2253
2254         getCharCode: function(ev) {
2255             ev = ev.browserEvent || ev;
2256             return ev.charCode || ev.keyCode || 0;
2257         },
2258
2259
2260         _getCacheIndex: function(el, eventName, fn) {
2261             for (var i = 0,len = listeners.length; i < len; ++i) {
2262                 var li = listeners[i];
2263                 if (li &&
2264                     li[this.FN] == fn &&
2265                     li[this.EL] == el &&
2266                     li[this.TYPE] == eventName) {
2267                     return i;
2268                 }
2269             }
2270
2271             return -1;
2272         },
2273
2274
2275         elCache: {},
2276
2277
2278         getEl: function(id) {
2279             return document.getElementById(id);
2280         },
2281
2282
2283         clearCache: function() {
2284         },
2285
2286
2287         _load: function(e) {
2288             loadComplete = true;
2289             var EU = Roo.lib.Event;
2290
2291
2292             if (Roo.isIE) {
2293                 EU.doRemove(window, "load", EU._load);
2294             }
2295         },
2296
2297
2298         _tryPreloadAttach: function() {
2299
2300             if (this.locked) {
2301                 return false;
2302             }
2303
2304             this.locked = true;
2305
2306
2307             var tryAgain = !loadComplete;
2308             if (!tryAgain) {
2309                 tryAgain = (retryCount > 0);
2310             }
2311
2312
2313             var notAvail = [];
2314             for (var i = 0,len = onAvailStack.length; i < len; ++i) {
2315                 var item = onAvailStack[i];
2316                 if (item) {
2317                     var el = this.getEl(item.id);
2318
2319                     if (el) {
2320                         if (!item.checkReady ||
2321                             loadComplete ||
2322                             el.nextSibling ||
2323                             (document && document.body)) {
2324
2325                             var scope = el;
2326                             if (item.override) {
2327                                 if (item.override === true) {
2328                                     scope = item.obj;
2329                                 } else {
2330                                     scope = item.override;
2331                                 }
2332                             }
2333                             item.fn.call(scope, item.obj);
2334                             onAvailStack[i] = null;
2335                         }
2336                     } else {
2337                         notAvail.push(item);
2338                     }
2339                 }
2340             }
2341
2342             retryCount = (notAvail.length === 0) ? 0 : retryCount - 1;
2343
2344             if (tryAgain) {
2345
2346                 this.startInterval();
2347             } else {
2348                 clearInterval(this._interval);
2349                 this._interval = null;
2350             }
2351
2352             this.locked = false;
2353
2354             return true;
2355
2356         },
2357
2358
2359         purgeElement: function(el, recurse, eventName) {
2360             var elListeners = this.getListeners(el, eventName);
2361             if (elListeners) {
2362                 for (var i = 0,len = elListeners.length; i < len; ++i) {
2363                     var l = elListeners[i];
2364                     this.removeListener(el, l.type, l.fn);
2365                 }
2366             }
2367
2368             if (recurse && el && el.childNodes) {
2369                 for (i = 0,len = el.childNodes.length; i < len; ++i) {
2370                     this.purgeElement(el.childNodes[i], recurse, eventName);
2371                 }
2372             }
2373         },
2374
2375
2376         getListeners: function(el, eventName) {
2377             var results = [], searchLists;
2378             if (!eventName) {
2379                 searchLists = [listeners, unloadListeners];
2380             } else if (eventName == "unload") {
2381                 searchLists = [unloadListeners];
2382             } else {
2383                 searchLists = [listeners];
2384             }
2385
2386             for (var j = 0; j < searchLists.length; ++j) {
2387                 var searchList = searchLists[j];
2388                 if (searchList && searchList.length > 0) {
2389                     for (var i = 0,len = searchList.length; i < len; ++i) {
2390                         var l = searchList[i];
2391                         if (l && l[this.EL] === el &&
2392                             (!eventName || eventName === l[this.TYPE])) {
2393                             results.push({
2394                                 type:   l[this.TYPE],
2395                                 fn:     l[this.FN],
2396                                 obj:    l[this.OBJ],
2397                                 adjust: l[this.ADJ_SCOPE],
2398                                 index:  i
2399                             });
2400                         }
2401                     }
2402                 }
2403             }
2404
2405             return (results.length) ? results : null;
2406         },
2407
2408
2409         _unload: function(e) {
2410
2411             var EU = Roo.lib.Event, i, j, l, len, index;
2412
2413             for (i = 0,len = unloadListeners.length; i < len; ++i) {
2414                 l = unloadListeners[i];
2415                 if (l) {
2416                     var scope = window;
2417                     if (l[EU.ADJ_SCOPE]) {
2418                         if (l[EU.ADJ_SCOPE] === true) {
2419                             scope = l[EU.OBJ];
2420                         } else {
2421                             scope = l[EU.ADJ_SCOPE];
2422                         }
2423                     }
2424                     l[EU.FN].call(scope, EU.getEvent(e), l[EU.OBJ]);
2425                     unloadListeners[i] = null;
2426                     l = null;
2427                     scope = null;
2428                 }
2429             }
2430
2431             unloadListeners = null;
2432
2433             if (listeners && listeners.length > 0) {
2434                 j = listeners.length;
2435                 while (j) {
2436                     index = j - 1;
2437                     l = listeners[index];
2438                     if (l) {
2439                         EU.removeListener(l[EU.EL], l[EU.TYPE],
2440                                 l[EU.FN], index);
2441                     }
2442                     j = j - 1;
2443                 }
2444                 l = null;
2445
2446                 EU.clearCache();
2447             }
2448
2449             EU.doRemove(window, "unload", EU._unload);
2450
2451         },
2452
2453
2454         getScroll: function() {
2455             var dd = document.documentElement, db = document.body;
2456             if (dd && (dd.scrollTop || dd.scrollLeft)) {
2457                 return [dd.scrollTop, dd.scrollLeft];
2458             } else if (db) {
2459                 return [db.scrollTop, db.scrollLeft];
2460             } else {
2461                 return [0, 0];
2462             }
2463         },
2464
2465
2466         doAdd: function () {
2467             if (window.addEventListener) {
2468                 return function(el, eventName, fn, capture) {
2469                     el.addEventListener(eventName, fn, (capture));
2470                 };
2471             } else if (window.attachEvent) {
2472                 return function(el, eventName, fn, capture) {
2473                     el.attachEvent("on" + eventName, fn);
2474                 };
2475             } else {
2476                 return function() {
2477                 };
2478             }
2479         }(),
2480
2481
2482         doRemove: function() {
2483             if (window.removeEventListener) {
2484                 return function (el, eventName, fn, capture) {
2485                     el.removeEventListener(eventName, fn, (capture));
2486                 };
2487             } else if (window.detachEvent) {
2488                 return function (el, eventName, fn) {
2489                     el.detachEvent("on" + eventName, fn);
2490                 };
2491             } else {
2492                 return function() {
2493                 };
2494             }
2495         }()
2496     };
2497     
2498 }();
2499 (function() {     
2500    
2501     var E = Roo.lib.Event;
2502     E.on = E.addListener;
2503     E.un = E.removeListener;
2504
2505     if (document && document.body) {
2506         E._load();
2507     } else {
2508         E.doAdd(window, "load", E._load);
2509     }
2510     E.doAdd(window, "unload", E._unload);
2511     E._tryPreloadAttach();
2512 })();
2513
2514 /*
2515  * Portions of this file are based on pieces of Yahoo User Interface Library
2516  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
2517  * YUI licensed under the BSD License:
2518  * http://developer.yahoo.net/yui/license.txt
2519  * <script type="text/javascript">
2520  *
2521  */
2522
2523 (function() {
2524     /**
2525      * @class Roo.lib.Ajax
2526      *
2527      */
2528     Roo.lib.Ajax = {
2529         /**
2530          * @static 
2531          */
2532         request : function(method, uri, cb, data, options) {
2533             if(options){
2534                 var hs = options.headers;
2535                 if(hs){
2536                     for(var h in hs){
2537                         if(hs.hasOwnProperty(h)){
2538                             this.initHeader(h, hs[h], false);
2539                         }
2540                     }
2541                 }
2542                 if(options.xmlData){
2543                     this.initHeader('Content-Type', 'text/xml', false);
2544                     method = 'POST';
2545                     data = options.xmlData;
2546                 }
2547             }
2548
2549             return this.asyncRequest(method, uri, cb, data);
2550         },
2551
2552         serializeForm : function(form) {
2553             if(typeof form == 'string') {
2554                 form = (document.getElementById(form) || document.forms[form]);
2555             }
2556
2557             var el, name, val, disabled, data = '', hasSubmit = false;
2558             for (var i = 0; i < form.elements.length; i++) {
2559                 el = form.elements[i];
2560                 disabled = form.elements[i].disabled;
2561                 name = form.elements[i].name;
2562                 val = form.elements[i].value;
2563
2564                 if (!disabled && name){
2565                     switch (el.type)
2566                             {
2567                         case 'select-one':
2568                         case 'select-multiple':
2569                             for (var j = 0; j < el.options.length; j++) {
2570                                 if (el.options[j].selected) {
2571                                     if (Roo.isIE) {
2572                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].attributes['value'].specified ? el.options[j].value : el.options[j].text) + '&';
2573                                     }
2574                                     else {
2575                                         data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(el.options[j].hasAttribute('value') ? el.options[j].value : el.options[j].text) + '&';
2576                                     }
2577                                 }
2578                             }
2579                             break;
2580                         case 'radio':
2581                         case 'checkbox':
2582                             if (el.checked) {
2583                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2584                             }
2585                             break;
2586                         case 'file':
2587
2588                         case undefined:
2589
2590                         case 'reset':
2591
2592                         case 'button':
2593
2594                             break;
2595                         case 'submit':
2596                             if(hasSubmit == false) {
2597                                 data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2598                                 hasSubmit = true;
2599                             }
2600                             break;
2601                         default:
2602                             data += Roo.encodeURIComponent(name) + '=' + Roo.encodeURIComponent(val) + '&';
2603                             break;
2604                     }
2605                 }
2606             }
2607             data = data.substr(0, data.length - 1);
2608             return data;
2609         },
2610
2611         headers:{},
2612
2613         hasHeaders:false,
2614
2615         useDefaultHeader:true,
2616
2617         defaultPostHeader:'application/x-www-form-urlencoded',
2618
2619         useDefaultXhrHeader:true,
2620
2621         defaultXhrHeader:'XMLHttpRequest',
2622
2623         hasDefaultHeaders:true,
2624
2625         defaultHeaders:{},
2626
2627         poll:{},
2628
2629         timeout:{},
2630
2631         pollInterval:50,
2632
2633         transactionId:0,
2634
2635         setProgId:function(id)
2636         {
2637             this.activeX.unshift(id);
2638         },
2639
2640         setDefaultPostHeader:function(b)
2641         {
2642             this.useDefaultHeader = b;
2643         },
2644
2645         setDefaultXhrHeader:function(b)
2646         {
2647             this.useDefaultXhrHeader = b;
2648         },
2649
2650         setPollingInterval:function(i)
2651         {
2652             if (typeof i == 'number' && isFinite(i)) {
2653                 this.pollInterval = i;
2654             }
2655         },
2656
2657         createXhrObject:function(transactionId)
2658         {
2659             var obj,http;
2660             try
2661             {
2662
2663                 http = new XMLHttpRequest();
2664
2665                 obj = { conn:http, tId:transactionId };
2666             }
2667             catch(e)
2668             {
2669                 for (var i = 0; i < this.activeX.length; ++i) {
2670                     try
2671                     {
2672
2673                         http = new ActiveXObject(this.activeX[i]);
2674
2675                         obj = { conn:http, tId:transactionId };
2676                         break;
2677                     }
2678                     catch(e) {
2679                     }
2680                 }
2681             }
2682             finally
2683             {
2684                 return obj;
2685             }
2686         },
2687
2688         getConnectionObject:function()
2689         {
2690             var o;
2691             var tId = this.transactionId;
2692
2693             try
2694             {
2695                 o = this.createXhrObject(tId);
2696                 if (o) {
2697                     this.transactionId++;
2698                 }
2699             }
2700             catch(e) {
2701             }
2702             finally
2703             {
2704                 return o;
2705             }
2706         },
2707
2708         asyncRequest:function(method, uri, callback, postData)
2709         {
2710             var o = this.getConnectionObject();
2711
2712             if (!o) {
2713                 return null;
2714             }
2715             else {
2716                 o.conn.open(method, uri, true);
2717
2718                 if (this.useDefaultXhrHeader) {
2719                     if (!this.defaultHeaders['X-Requested-With']) {
2720                         this.initHeader('X-Requested-With', this.defaultXhrHeader, true);
2721                     }
2722                 }
2723
2724                 if(postData && this.useDefaultHeader){
2725                     this.initHeader('Content-Type', this.defaultPostHeader);
2726                 }
2727
2728                  if (this.hasDefaultHeaders || this.hasHeaders) {
2729                     this.setHeader(o);
2730                 }
2731
2732                 this.handleReadyState(o, callback);
2733                 o.conn.send(postData || null);
2734
2735                 return o;
2736             }
2737         },
2738
2739         handleReadyState:function(o, callback)
2740         {
2741             var oConn = this;
2742
2743             if (callback && callback.timeout) {
2744                 
2745                 this.timeout[o.tId] = window.setTimeout(function() {
2746                     oConn.abort(o, callback, true);
2747                 }, callback.timeout);
2748             }
2749
2750             this.poll[o.tId] = window.setInterval(
2751                     function() {
2752                         if (o.conn && o.conn.readyState == 4) {
2753                             window.clearInterval(oConn.poll[o.tId]);
2754                             delete oConn.poll[o.tId];
2755
2756                             if(callback && callback.timeout) {
2757                                 window.clearTimeout(oConn.timeout[o.tId]);
2758                                 delete oConn.timeout[o.tId];
2759                             }
2760
2761                             oConn.handleTransactionResponse(o, callback);
2762                         }
2763                     }
2764                     , this.pollInterval);
2765         },
2766
2767         handleTransactionResponse:function(o, callback, isAbort)
2768         {
2769
2770             if (!callback) {
2771                 this.releaseObject(o);
2772                 return;
2773             }
2774
2775             var httpStatus, responseObject;
2776
2777             try
2778             {
2779                 if (o.conn.status !== undefined && o.conn.status != 0) {
2780                     httpStatus = o.conn.status;
2781                 }
2782                 else {
2783                     httpStatus = 13030;
2784                 }
2785             }
2786             catch(e) {
2787
2788
2789                 httpStatus = 13030;
2790             }
2791
2792             if (httpStatus >= 200 && httpStatus < 300) {
2793                 responseObject = this.createResponseObject(o, callback.argument);
2794                 if (callback.success) {
2795                     if (!callback.scope) {
2796                         callback.success(responseObject);
2797                     }
2798                     else {
2799
2800
2801                         callback.success.apply(callback.scope, [responseObject]);
2802                     }
2803                 }
2804             }
2805             else {
2806                 switch (httpStatus) {
2807
2808                     case 12002:
2809                     case 12029:
2810                     case 12030:
2811                     case 12031:
2812                     case 12152:
2813                     case 13030:
2814                         responseObject = this.createExceptionObject(o.tId, callback.argument, (isAbort ? isAbort : false));
2815                         if (callback.failure) {
2816                             if (!callback.scope) {
2817                                 callback.failure(responseObject);
2818                             }
2819                             else {
2820                                 callback.failure.apply(callback.scope, [responseObject]);
2821                             }
2822                         }
2823                         break;
2824                     default:
2825                         responseObject = this.createResponseObject(o, callback.argument);
2826                         if (callback.failure) {
2827                             if (!callback.scope) {
2828                                 callback.failure(responseObject);
2829                             }
2830                             else {
2831                                 callback.failure.apply(callback.scope, [responseObject]);
2832                             }
2833                         }
2834                 }
2835             }
2836
2837             this.releaseObject(o);
2838             responseObject = null;
2839         },
2840
2841         createResponseObject:function(o, callbackArg)
2842         {
2843             var obj = {};
2844             var headerObj = {};
2845
2846             try
2847             {
2848                 var headerStr = o.conn.getAllResponseHeaders();
2849                 var header = headerStr.split('\n');
2850                 for (var i = 0; i < header.length; i++) {
2851                     var delimitPos = header[i].indexOf(':');
2852                     if (delimitPos != -1) {
2853                         headerObj[header[i].substring(0, delimitPos)] = header[i].substring(delimitPos + 2);
2854                     }
2855                 }
2856             }
2857             catch(e) {
2858             }
2859
2860             obj.tId = o.tId;
2861             obj.status = o.conn.status;
2862             obj.statusText = o.conn.statusText;
2863             obj.getResponseHeader = headerObj;
2864             obj.getAllResponseHeaders = headerStr;
2865             obj.responseText = o.conn.responseText;
2866             obj.responseXML = o.conn.responseXML;
2867
2868             if (typeof callbackArg !== undefined) {
2869                 obj.argument = callbackArg;
2870             }
2871
2872             return obj;
2873         },
2874
2875         createExceptionObject:function(tId, callbackArg, isAbort)
2876         {
2877             var COMM_CODE = 0;
2878             var COMM_ERROR = 'communication failure';
2879             var ABORT_CODE = -1;
2880             var ABORT_ERROR = 'transaction aborted';
2881
2882             var obj = {};
2883
2884             obj.tId = tId;
2885             if (isAbort) {
2886                 obj.status = ABORT_CODE;
2887                 obj.statusText = ABORT_ERROR;
2888             }
2889             else {
2890                 obj.status = COMM_CODE;
2891                 obj.statusText = COMM_ERROR;
2892             }
2893
2894             if (callbackArg) {
2895                 obj.argument = callbackArg;
2896             }
2897
2898             return obj;
2899         },
2900
2901         initHeader:function(label, value, isDefault)
2902         {
2903             var headerObj = (isDefault) ? this.defaultHeaders : this.headers;
2904
2905             if (headerObj[label] === undefined) {
2906                 headerObj[label] = value;
2907             }
2908             else {
2909
2910
2911                 headerObj[label] = value + "," + headerObj[label];
2912             }
2913
2914             if (isDefault) {
2915                 this.hasDefaultHeaders = true;
2916             }
2917             else {
2918                 this.hasHeaders = true;
2919             }
2920         },
2921
2922
2923         setHeader:function(o)
2924         {
2925             if (this.hasDefaultHeaders) {
2926                 for (var prop in this.defaultHeaders) {
2927                     if (this.defaultHeaders.hasOwnProperty(prop)) {
2928                         o.conn.setRequestHeader(prop, this.defaultHeaders[prop]);
2929                     }
2930                 }
2931             }
2932
2933             if (this.hasHeaders) {
2934                 for (var prop in this.headers) {
2935                     if (this.headers.hasOwnProperty(prop)) {
2936                         o.conn.setRequestHeader(prop, this.headers[prop]);
2937                     }
2938                 }
2939                 this.headers = {};
2940                 this.hasHeaders = false;
2941             }
2942         },
2943
2944         resetDefaultHeaders:function() {
2945             delete this.defaultHeaders;
2946             this.defaultHeaders = {};
2947             this.hasDefaultHeaders = false;
2948         },
2949
2950         abort:function(o, callback, isTimeout)
2951         {
2952             if(this.isCallInProgress(o)) {
2953                 o.conn.abort();
2954                 window.clearInterval(this.poll[o.tId]);
2955                 delete this.poll[o.tId];
2956                 if (isTimeout) {
2957                     delete this.timeout[o.tId];
2958                 }
2959
2960                 this.handleTransactionResponse(o, callback, true);
2961
2962                 return true;
2963             }
2964             else {
2965                 return false;
2966             }
2967         },
2968
2969
2970         isCallInProgress:function(o)
2971         {
2972             if (o && o.conn) {
2973                 return o.conn.readyState != 4 && o.conn.readyState != 0;
2974             }
2975             else {
2976
2977                 return false;
2978             }
2979         },
2980
2981
2982         releaseObject:function(o)
2983         {
2984
2985             o.conn = null;
2986
2987             o = null;
2988         },
2989
2990         activeX:[
2991         'MSXML2.XMLHTTP.3.0',
2992         'MSXML2.XMLHTTP',
2993         'Microsoft.XMLHTTP'
2994         ]
2995
2996
2997     };
2998 })();/*
2999  * Portions of this file are based on pieces of Yahoo User Interface Library
3000  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3001  * YUI licensed under the BSD License:
3002  * http://developer.yahoo.net/yui/license.txt
3003  * <script type="text/javascript">
3004  *
3005  */
3006
3007 Roo.lib.Region = function(t, r, b, l) {
3008     this.top = t;
3009     this[1] = t;
3010     this.right = r;
3011     this.bottom = b;
3012     this.left = l;
3013     this[0] = l;
3014 };
3015
3016
3017 Roo.lib.Region.prototype = {
3018     contains : function(region) {
3019         return ( region.left >= this.left &&
3020                  region.right <= this.right &&
3021                  region.top >= this.top &&
3022                  region.bottom <= this.bottom    );
3023
3024     },
3025
3026     getArea : function() {
3027         return ( (this.bottom - this.top) * (this.right - this.left) );
3028     },
3029
3030     intersect : function(region) {
3031         var t = Math.max(this.top, region.top);
3032         var r = Math.min(this.right, region.right);
3033         var b = Math.min(this.bottom, region.bottom);
3034         var l = Math.max(this.left, region.left);
3035
3036         if (b >= t && r >= l) {
3037             return new Roo.lib.Region(t, r, b, l);
3038         } else {
3039             return null;
3040         }
3041     },
3042     union : function(region) {
3043         var t = Math.min(this.top, region.top);
3044         var r = Math.max(this.right, region.right);
3045         var b = Math.max(this.bottom, region.bottom);
3046         var l = Math.min(this.left, region.left);
3047
3048         return new Roo.lib.Region(t, r, b, l);
3049     },
3050
3051     adjust : function(t, l, b, r) {
3052         this.top += t;
3053         this.left += l;
3054         this.right += r;
3055         this.bottom += b;
3056         return this;
3057     }
3058 };
3059
3060 Roo.lib.Region.getRegion = function(el) {
3061     var p = Roo.lib.Dom.getXY(el);
3062
3063     var t = p[1];
3064     var r = p[0] + el.offsetWidth;
3065     var b = p[1] + el.offsetHeight;
3066     var l = p[0];
3067
3068     return new Roo.lib.Region(t, r, b, l);
3069 };
3070 /*
3071  * Portions of this file are based on pieces of Yahoo User Interface Library
3072  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3073  * YUI licensed under the BSD License:
3074  * http://developer.yahoo.net/yui/license.txt
3075  * <script type="text/javascript">
3076  *
3077  */
3078 //@@dep Roo.lib.Region
3079
3080
3081 Roo.lib.Point = function(x, y) {
3082     if (x instanceof Array) {
3083         y = x[1];
3084         x = x[0];
3085     }
3086     this.x = this.right = this.left = this[0] = x;
3087     this.y = this.top = this.bottom = this[1] = y;
3088 };
3089
3090 Roo.lib.Point.prototype = new Roo.lib.Region();
3091 /*
3092  * Portions of this file are based on pieces of Yahoo User Interface Library
3093  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3094  * YUI licensed under the BSD License:
3095  * http://developer.yahoo.net/yui/license.txt
3096  * <script type="text/javascript">
3097  *
3098  */
3099  
3100 (function() {   
3101
3102     Roo.lib.Anim = {
3103         scroll : function(el, args, duration, easing, cb, scope) {
3104             this.run(el, args, duration, easing, cb, scope, Roo.lib.Scroll);
3105         },
3106
3107         motion : function(el, args, duration, easing, cb, scope) {
3108             this.run(el, args, duration, easing, cb, scope, Roo.lib.Motion);
3109         },
3110
3111         color : function(el, args, duration, easing, cb, scope) {
3112             this.run(el, args, duration, easing, cb, scope, Roo.lib.ColorAnim);
3113         },
3114
3115         run : function(el, args, duration, easing, cb, scope, type) {
3116             type = type || Roo.lib.AnimBase;
3117             if (typeof easing == "string") {
3118                 easing = Roo.lib.Easing[easing];
3119             }
3120             var anim = new type(el, args, duration, easing);
3121             anim.animateX(function() {
3122                 Roo.callback(cb, scope);
3123             });
3124             return anim;
3125         }
3126     };
3127 })();/*
3128  * Portions of this file are based on pieces of Yahoo User Interface Library
3129  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3130  * YUI licensed under the BSD License:
3131  * http://developer.yahoo.net/yui/license.txt
3132  * <script type="text/javascript">
3133  *
3134  */
3135
3136 (function() {    
3137     var libFlyweight;
3138     
3139     function fly(el) {
3140         if (!libFlyweight) {
3141             libFlyweight = new Roo.Element.Flyweight();
3142         }
3143         libFlyweight.dom = el;
3144         return libFlyweight;
3145     }
3146
3147     // since this uses fly! - it cant be in DOM (which does not have fly yet..)
3148     
3149    
3150     
3151     Roo.lib.AnimBase = function(el, attributes, duration, method) {
3152         if (el) {
3153             this.init(el, attributes, duration, method);
3154         }
3155     };
3156
3157     Roo.lib.AnimBase.fly = fly;
3158     
3159     
3160     
3161     Roo.lib.AnimBase.prototype = {
3162
3163         toString: function() {
3164             var el = this.getEl();
3165             var id = el.id || el.tagName;
3166             return ("Anim " + id);
3167         },
3168
3169         patterns: {
3170             noNegatives:        /width|height|opacity|padding/i,
3171             offsetAttribute:  /^((width|height)|(top|left))$/,
3172             defaultUnit:        /width|height|top$|bottom$|left$|right$/i,
3173             offsetUnit:         /\d+(em|%|en|ex|pt|in|cm|mm|pc)$/i
3174         },
3175
3176
3177         doMethod: function(attr, start, end) {
3178             return this.method(this.currentFrame, start, end - start, this.totalFrames);
3179         },
3180
3181
3182         setAttribute: function(attr, val, unit) {
3183             if (this.patterns.noNegatives.test(attr)) {
3184                 val = (val > 0) ? val : 0;
3185             }
3186
3187             Roo.fly(this.getEl(), '_anim').setStyle(attr, val + unit);
3188         },
3189
3190
3191         getAttribute: function(attr) {
3192             var el = this.getEl();
3193             var val = fly(el).getStyle(attr);
3194
3195             if (val !== 'auto' && !this.patterns.offsetUnit.test(val)) {
3196                 return parseFloat(val);
3197             }
3198
3199             var a = this.patterns.offsetAttribute.exec(attr) || [];
3200             var pos = !!( a[3] );
3201             var box = !!( a[2] );
3202
3203
3204             if (box || (fly(el).getStyle('position') == 'absolute' && pos)) {
3205                 val = el['offset' + a[0].charAt(0).toUpperCase() + a[0].substr(1)];
3206             } else {
3207                 val = 0;
3208             }
3209
3210             return val;
3211         },
3212
3213
3214         getDefaultUnit: function(attr) {
3215             if (this.patterns.defaultUnit.test(attr)) {
3216                 return 'px';
3217             }
3218
3219             return '';
3220         },
3221
3222         animateX : function(callback, scope) {
3223             var f = function() {
3224                 this.onComplete.removeListener(f);
3225                 if (typeof callback == "function") {
3226                     callback.call(scope || this, this);
3227                 }
3228             };
3229             this.onComplete.addListener(f, this);
3230             this.animate();
3231         },
3232
3233
3234         setRuntimeAttribute: function(attr) {
3235             var start;
3236             var end;
3237             var attributes = this.attributes;
3238
3239             this.runtimeAttributes[attr] = {};
3240
3241             var isset = function(prop) {
3242                 return (typeof prop !== 'undefined');
3243             };
3244
3245             if (!isset(attributes[attr]['to']) && !isset(attributes[attr]['by'])) {
3246                 return false;
3247             }
3248
3249             start = ( isset(attributes[attr]['from']) ) ? attributes[attr]['from'] : this.getAttribute(attr);
3250
3251
3252             if (isset(attributes[attr]['to'])) {
3253                 end = attributes[attr]['to'];
3254             } else if (isset(attributes[attr]['by'])) {
3255                 if (start.constructor == Array) {
3256                     end = [];
3257                     for (var i = 0, len = start.length; i < len; ++i) {
3258                         end[i] = start[i] + attributes[attr]['by'][i];
3259                     }
3260                 } else {
3261                     end = start + attributes[attr]['by'];
3262                 }
3263             }
3264
3265             this.runtimeAttributes[attr].start = start;
3266             this.runtimeAttributes[attr].end = end;
3267
3268
3269             this.runtimeAttributes[attr].unit = ( isset(attributes[attr].unit) ) ? attributes[attr]['unit'] : this.getDefaultUnit(attr);
3270         },
3271
3272
3273         init: function(el, attributes, duration, method) {
3274
3275             var isAnimated = false;
3276
3277
3278             var startTime = null;
3279
3280
3281             var actualFrames = 0;
3282
3283
3284             el = Roo.getDom(el);
3285
3286
3287             this.attributes = attributes || {};
3288
3289
3290             this.duration = duration || 1;
3291
3292
3293             this.method = method || Roo.lib.Easing.easeNone;
3294
3295
3296             this.useSeconds = true;
3297
3298
3299             this.currentFrame = 0;
3300
3301
3302             this.totalFrames = Roo.lib.AnimMgr.fps;
3303
3304
3305             this.getEl = function() {
3306                 return el;
3307             };
3308
3309
3310             this.isAnimated = function() {
3311                 return isAnimated;
3312             };
3313
3314
3315             this.getStartTime = function() {
3316                 return startTime;
3317             };
3318
3319             this.runtimeAttributes = {};
3320
3321
3322             this.animate = function() {
3323                 if (this.isAnimated()) {
3324                     return false;
3325                 }
3326
3327                 this.currentFrame = 0;
3328
3329                 this.totalFrames = ( this.useSeconds ) ? Math.ceil(Roo.lib.AnimMgr.fps * this.duration) : this.duration;
3330
3331                 Roo.lib.AnimMgr.registerElement(this);
3332             };
3333
3334
3335             this.stop = function(finish) {
3336                 if (finish) {
3337                     this.currentFrame = this.totalFrames;
3338                     this._onTween.fire();
3339                 }
3340                 Roo.lib.AnimMgr.stop(this);
3341             };
3342
3343             var onStart = function() {
3344                 this.onStart.fire();
3345
3346                 this.runtimeAttributes = {};
3347                 for (var attr in this.attributes) {
3348                     this.setRuntimeAttribute(attr);
3349                 }
3350
3351                 isAnimated = true;
3352                 actualFrames = 0;
3353                 startTime = new Date();
3354             };
3355
3356
3357             var onTween = function() {
3358                 var data = {
3359                     duration: new Date() - this.getStartTime(),
3360                     currentFrame: this.currentFrame
3361                 };
3362
3363                 data.toString = function() {
3364                     return (
3365                             'duration: ' + data.duration +
3366                             ', currentFrame: ' + data.currentFrame
3367                             );
3368                 };
3369
3370                 this.onTween.fire(data);
3371
3372                 var runtimeAttributes = this.runtimeAttributes;
3373
3374                 for (var attr in runtimeAttributes) {
3375                     this.setAttribute(attr, this.doMethod(attr, runtimeAttributes[attr].start, runtimeAttributes[attr].end), runtimeAttributes[attr].unit);
3376                 }
3377
3378                 actualFrames += 1;
3379             };
3380
3381             var onComplete = function() {
3382                 var actual_duration = (new Date() - startTime) / 1000 ;
3383
3384                 var data = {
3385                     duration: actual_duration,
3386                     frames: actualFrames,
3387                     fps: actualFrames / actual_duration
3388                 };
3389
3390                 data.toString = function() {
3391                     return (
3392                             'duration: ' + data.duration +
3393                             ', frames: ' + data.frames +
3394                             ', fps: ' + data.fps
3395                             );
3396                 };
3397
3398                 isAnimated = false;
3399                 actualFrames = 0;
3400                 this.onComplete.fire(data);
3401             };
3402
3403
3404             this._onStart = new Roo.util.Event(this);
3405             this.onStart = new Roo.util.Event(this);
3406             this.onTween = new Roo.util.Event(this);
3407             this._onTween = new Roo.util.Event(this);
3408             this.onComplete = new Roo.util.Event(this);
3409             this._onComplete = new Roo.util.Event(this);
3410             this._onStart.addListener(onStart);
3411             this._onTween.addListener(onTween);
3412             this._onComplete.addListener(onComplete);
3413         }
3414     };
3415 })();
3416 /*
3417  * Portions of this file are based on pieces of Yahoo User Interface Library
3418  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3419  * YUI licensed under the BSD License:
3420  * http://developer.yahoo.net/yui/license.txt
3421  * <script type="text/javascript">
3422  *
3423  */
3424
3425 Roo.lib.AnimMgr = new function() {
3426
3427     var thread = null;
3428
3429
3430     var queue = [];
3431
3432
3433     var tweenCount = 0;
3434
3435
3436     this.fps = 1000;
3437
3438
3439     this.delay = 1;
3440
3441
3442     this.registerElement = function(tween) {
3443         queue[queue.length] = tween;
3444         tweenCount += 1;
3445         tween._onStart.fire();
3446         this.start();
3447     };
3448
3449
3450     this.unRegister = function(tween, index) {
3451         tween._onComplete.fire();
3452         index = index || getIndex(tween);
3453         if (index != -1) {
3454             queue.splice(index, 1);
3455         }
3456
3457         tweenCount -= 1;
3458         if (tweenCount <= 0) {
3459             this.stop();
3460         }
3461     };
3462
3463
3464     this.start = function() {
3465         if (thread === null) {
3466             thread = setInterval(this.run, this.delay);
3467         }
3468     };
3469
3470
3471     this.stop = function(tween) {
3472         if (!tween) {
3473             clearInterval(thread);
3474
3475             for (var i = 0, len = queue.length; i < len; ++i) {
3476                 if (queue[0].isAnimated()) {
3477                     this.unRegister(queue[0], 0);
3478                 }
3479             }
3480
3481             queue = [];
3482             thread = null;
3483             tweenCount = 0;
3484         }
3485         else {
3486             this.unRegister(tween);
3487         }
3488     };
3489
3490
3491     this.run = function() {
3492         for (var i = 0, len = queue.length; i < len; ++i) {
3493             var tween = queue[i];
3494             if (!tween || !tween.isAnimated()) {
3495                 continue;
3496             }
3497
3498             if (tween.currentFrame < tween.totalFrames || tween.totalFrames === null)
3499             {
3500                 tween.currentFrame += 1;
3501
3502                 if (tween.useSeconds) {
3503                     correctFrame(tween);
3504                 }
3505                 tween._onTween.fire();
3506             }
3507             else {
3508                 Roo.lib.AnimMgr.stop(tween, i);
3509             }
3510         }
3511     };
3512
3513     var getIndex = function(anim) {
3514         for (var i = 0, len = queue.length; i < len; ++i) {
3515             if (queue[i] == anim) {
3516                 return i;
3517             }
3518         }
3519         return -1;
3520     };
3521
3522
3523     var correctFrame = function(tween) {
3524         var frames = tween.totalFrames;
3525         var frame = tween.currentFrame;
3526         var expected = (tween.currentFrame * tween.duration * 1000 / tween.totalFrames);
3527         var elapsed = (new Date() - tween.getStartTime());
3528         var tweak = 0;
3529
3530         if (elapsed < tween.duration * 1000) {
3531             tweak = Math.round((elapsed / expected - 1) * tween.currentFrame);
3532         } else {
3533             tweak = frames - (frame + 1);
3534         }
3535         if (tweak > 0 && isFinite(tweak)) {
3536             if (tween.currentFrame + tweak >= frames) {
3537                 tweak = frames - (frame + 1);
3538             }
3539
3540             tween.currentFrame += tweak;
3541         }
3542     };
3543 };
3544
3545     /*
3546  * Portions of this file are based on pieces of Yahoo User Interface Library
3547  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3548  * YUI licensed under the BSD License:
3549  * http://developer.yahoo.net/yui/license.txt
3550  * <script type="text/javascript">
3551  *
3552  */
3553 Roo.lib.Bezier = new function() {
3554
3555         this.getPosition = function(points, t) {
3556             var n = points.length;
3557             var tmp = [];
3558
3559             for (var i = 0; i < n; ++i) {
3560                 tmp[i] = [points[i][0], points[i][1]];
3561             }
3562
3563             for (var j = 1; j < n; ++j) {
3564                 for (i = 0; i < n - j; ++i) {
3565                     tmp[i][0] = (1 - t) * tmp[i][0] + t * tmp[parseInt(i + 1, 10)][0];
3566                     tmp[i][1] = (1 - t) * tmp[i][1] + t * tmp[parseInt(i + 1, 10)][1];
3567                 }
3568             }
3569
3570             return [ tmp[0][0], tmp[0][1] ];
3571
3572         };
3573     };/*
3574  * Portions of this file are based on pieces of Yahoo User Interface Library
3575  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3576  * YUI licensed under the BSD License:
3577  * http://developer.yahoo.net/yui/license.txt
3578  * <script type="text/javascript">
3579  *
3580  */
3581 (function() {
3582
3583     Roo.lib.ColorAnim = function(el, attributes, duration, method) {
3584         Roo.lib.ColorAnim.superclass.constructor.call(this, el, attributes, duration, method);
3585     };
3586
3587     Roo.extend(Roo.lib.ColorAnim, Roo.lib.AnimBase);
3588
3589     var fly = Roo.lib.AnimBase.fly;
3590     var Y = Roo.lib;
3591     var superclass = Y.ColorAnim.superclass;
3592     var proto = Y.ColorAnim.prototype;
3593
3594     proto.toString = function() {
3595         var el = this.getEl();
3596         var id = el.id || el.tagName;
3597         return ("ColorAnim " + id);
3598     };
3599
3600     proto.patterns.color = /color$/i;
3601     proto.patterns.rgb = /^rgb\(([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\)$/i;
3602     proto.patterns.hex = /^#?([0-9A-F]{2})([0-9A-F]{2})([0-9A-F]{2})$/i;
3603     proto.patterns.hex3 = /^#?([0-9A-F]{1})([0-9A-F]{1})([0-9A-F]{1})$/i;
3604     proto.patterns.transparent = /^transparent|rgba\(0, 0, 0, 0\)$/;
3605
3606
3607     proto.parseColor = function(s) {
3608         if (s.length == 3) {
3609             return s;
3610         }
3611
3612         var c = this.patterns.hex.exec(s);
3613         if (c && c.length == 4) {
3614             return [ parseInt(c[1], 16), parseInt(c[2], 16), parseInt(c[3], 16) ];
3615         }
3616
3617         c = this.patterns.rgb.exec(s);
3618         if (c && c.length == 4) {
3619             return [ parseInt(c[1], 10), parseInt(c[2], 10), parseInt(c[3], 10) ];
3620         }
3621
3622         c = this.patterns.hex3.exec(s);
3623         if (c && c.length == 4) {
3624             return [ parseInt(c[1] + c[1], 16), parseInt(c[2] + c[2], 16), parseInt(c[3] + c[3], 16) ];
3625         }
3626
3627         return null;
3628     };
3629     // since this uses fly! - it cant be in ColorAnim (which does not have fly yet..)
3630     proto.getAttribute = function(attr) {
3631         var el = this.getEl();
3632         if (this.patterns.color.test(attr)) {
3633             var val = fly(el).getStyle(attr);
3634
3635             if (this.patterns.transparent.test(val)) {
3636                 var parent = el.parentNode;
3637                 val = fly(parent).getStyle(attr);
3638
3639                 while (parent && this.patterns.transparent.test(val)) {
3640                     parent = parent.parentNode;
3641                     val = fly(parent).getStyle(attr);
3642                     if (parent.tagName.toUpperCase() == 'HTML') {
3643                         val = '#fff';
3644                     }
3645                 }
3646             }
3647         } else {
3648             val = superclass.getAttribute.call(this, attr);
3649         }
3650
3651         return val;
3652     };
3653     proto.getAttribute = function(attr) {
3654         var el = this.getEl();
3655         if (this.patterns.color.test(attr)) {
3656             var val = fly(el).getStyle(attr);
3657
3658             if (this.patterns.transparent.test(val)) {
3659                 var parent = el.parentNode;
3660                 val = fly(parent).getStyle(attr);
3661
3662                 while (parent && this.patterns.transparent.test(val)) {
3663                     parent = parent.parentNode;
3664                     val = fly(parent).getStyle(attr);
3665                     if (parent.tagName.toUpperCase() == 'HTML') {
3666                         val = '#fff';
3667                     }
3668                 }
3669             }
3670         } else {
3671             val = superclass.getAttribute.call(this, attr);
3672         }
3673
3674         return val;
3675     };
3676
3677     proto.doMethod = function(attr, start, end) {
3678         var val;
3679
3680         if (this.patterns.color.test(attr)) {
3681             val = [];
3682             for (var i = 0, len = start.length; i < len; ++i) {
3683                 val[i] = superclass.doMethod.call(this, attr, start[i], end[i]);
3684             }
3685
3686             val = 'rgb(' + Math.floor(val[0]) + ',' + Math.floor(val[1]) + ',' + Math.floor(val[2]) + ')';
3687         }
3688         else {
3689             val = superclass.doMethod.call(this, attr, start, end);
3690         }
3691
3692         return val;
3693     };
3694
3695     proto.setRuntimeAttribute = function(attr) {
3696         superclass.setRuntimeAttribute.call(this, attr);
3697
3698         if (this.patterns.color.test(attr)) {
3699             var attributes = this.attributes;
3700             var start = this.parseColor(this.runtimeAttributes[attr].start);
3701             var end = this.parseColor(this.runtimeAttributes[attr].end);
3702
3703             if (typeof attributes[attr]['to'] === 'undefined' && typeof attributes[attr]['by'] !== 'undefined') {
3704                 end = this.parseColor(attributes[attr].by);
3705
3706                 for (var i = 0, len = start.length; i < len; ++i) {
3707                     end[i] = start[i] + end[i];
3708                 }
3709             }
3710
3711             this.runtimeAttributes[attr].start = start;
3712             this.runtimeAttributes[attr].end = end;
3713         }
3714     };
3715 })();
3716
3717 /*
3718  * Portions of this file are based on pieces of Yahoo User Interface Library
3719  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3720  * YUI licensed under the BSD License:
3721  * http://developer.yahoo.net/yui/license.txt
3722  * <script type="text/javascript">
3723  *
3724  */
3725 Roo.lib.Easing = {
3726
3727
3728     easeNone: function (t, b, c, d) {
3729         return c * t / d + b;
3730     },
3731
3732
3733     easeIn: function (t, b, c, d) {
3734         return c * (t /= d) * t + b;
3735     },
3736
3737
3738     easeOut: function (t, b, c, d) {
3739         return -c * (t /= d) * (t - 2) + b;
3740     },
3741
3742
3743     easeBoth: function (t, b, c, d) {
3744         if ((t /= d / 2) < 1) {
3745             return c / 2 * t * t + b;
3746         }
3747
3748         return -c / 2 * ((--t) * (t - 2) - 1) + b;
3749     },
3750
3751
3752     easeInStrong: function (t, b, c, d) {
3753         return c * (t /= d) * t * t * t + b;
3754     },
3755
3756
3757     easeOutStrong: function (t, b, c, d) {
3758         return -c * ((t = t / d - 1) * t * t * t - 1) + b;
3759     },
3760
3761
3762     easeBothStrong: function (t, b, c, d) {
3763         if ((t /= d / 2) < 1) {
3764             return c / 2 * t * t * t * t + b;
3765         }
3766
3767         return -c / 2 * ((t -= 2) * t * t * t - 2) + b;
3768     },
3769
3770
3771
3772     elasticIn: function (t, b, c, d, a, p) {
3773         if (t == 0) {
3774             return b;
3775         }
3776         if ((t /= d) == 1) {
3777             return b + c;
3778         }
3779         if (!p) {
3780             p = d * .3;
3781         }
3782
3783         if (!a || a < Math.abs(c)) {
3784             a = c;
3785             var s = p / 4;
3786         }
3787         else {
3788             var s = p / (2 * Math.PI) * Math.asin(c / a);
3789         }
3790
3791         return -(a * Math.pow(2, 10 * (t -= 1)) * Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3792     },
3793
3794
3795     elasticOut: function (t, b, c, d, a, p) {
3796         if (t == 0) {
3797             return b;
3798         }
3799         if ((t /= d) == 1) {
3800             return b + c;
3801         }
3802         if (!p) {
3803             p = d * .3;
3804         }
3805
3806         if (!a || a < Math.abs(c)) {
3807             a = c;
3808             var s = p / 4;
3809         }
3810         else {
3811             var s = p / (2 * Math.PI) * Math.asin(c / a);
3812         }
3813
3814         return a * Math.pow(2, -10 * t) * Math.sin((t * d - s) * (2 * Math.PI) / p) + c + b;
3815     },
3816
3817
3818     elasticBoth: function (t, b, c, d, a, p) {
3819         if (t == 0) {
3820             return b;
3821         }
3822
3823         if ((t /= d / 2) == 2) {
3824             return b + c;
3825         }
3826
3827         if (!p) {
3828             p = d * (.3 * 1.5);
3829         }
3830
3831         if (!a || a < Math.abs(c)) {
3832             a = c;
3833             var s = p / 4;
3834         }
3835         else {
3836             var s = p / (2 * Math.PI) * Math.asin(c / a);
3837         }
3838
3839         if (t < 1) {
3840             return -.5 * (a * Math.pow(2, 10 * (t -= 1)) *
3841                           Math.sin((t * d - s) * (2 * Math.PI) / p)) + b;
3842         }
3843         return a * Math.pow(2, -10 * (t -= 1)) *
3844                Math.sin((t * d - s) * (2 * Math.PI) / p) * .5 + c + b;
3845     },
3846
3847
3848
3849     backIn: function (t, b, c, d, s) {
3850         if (typeof s == 'undefined') {
3851             s = 1.70158;
3852         }
3853         return c * (t /= d) * t * ((s + 1) * t - s) + b;
3854     },
3855
3856
3857     backOut: function (t, b, c, d, s) {
3858         if (typeof s == 'undefined') {
3859             s = 1.70158;
3860         }
3861         return c * ((t = t / d - 1) * t * ((s + 1) * t + s) + 1) + b;
3862     },
3863
3864
3865     backBoth: function (t, b, c, d, s) {
3866         if (typeof s == 'undefined') {
3867             s = 1.70158;
3868         }
3869
3870         if ((t /= d / 2 ) < 1) {
3871             return c / 2 * (t * t * (((s *= (1.525)) + 1) * t - s)) + b;
3872         }
3873         return c / 2 * ((t -= 2) * t * (((s *= (1.525)) + 1) * t + s) + 2) + b;
3874     },
3875
3876
3877     bounceIn: function (t, b, c, d) {
3878         return c - Roo.lib.Easing.bounceOut(d - t, 0, c, d) + b;
3879     },
3880
3881
3882     bounceOut: function (t, b, c, d) {
3883         if ((t /= d) < (1 / 2.75)) {
3884             return c * (7.5625 * t * t) + b;
3885         } else if (t < (2 / 2.75)) {
3886             return c * (7.5625 * (t -= (1.5 / 2.75)) * t + .75) + b;
3887         } else if (t < (2.5 / 2.75)) {
3888             return c * (7.5625 * (t -= (2.25 / 2.75)) * t + .9375) + b;
3889         }
3890         return c * (7.5625 * (t -= (2.625 / 2.75)) * t + .984375) + b;
3891     },
3892
3893
3894     bounceBoth: function (t, b, c, d) {
3895         if (t < d / 2) {
3896             return Roo.lib.Easing.bounceIn(t * 2, 0, c, d) * .5 + b;
3897         }
3898         return Roo.lib.Easing.bounceOut(t * 2 - d, 0, c, d) * .5 + c * .5 + b;
3899     }
3900 };/*
3901  * Portions of this file are based on pieces of Yahoo User Interface Library
3902  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
3903  * YUI licensed under the BSD License:
3904  * http://developer.yahoo.net/yui/license.txt
3905  * <script type="text/javascript">
3906  *
3907  */
3908     (function() {
3909         Roo.lib.Motion = function(el, attributes, duration, method) {
3910             if (el) {
3911                 Roo.lib.Motion.superclass.constructor.call(this, el, attributes, duration, method);
3912             }
3913         };
3914
3915         Roo.extend(Roo.lib.Motion, Roo.lib.ColorAnim);
3916
3917
3918         var Y = Roo.lib;
3919         var superclass = Y.Motion.superclass;
3920         var proto = Y.Motion.prototype;
3921
3922         proto.toString = function() {
3923             var el = this.getEl();
3924             var id = el.id || el.tagName;
3925             return ("Motion " + id);
3926         };
3927
3928         proto.patterns.points = /^points$/i;
3929
3930         proto.setAttribute = function(attr, val, unit) {
3931             if (this.patterns.points.test(attr)) {
3932                 unit = unit || 'px';
3933                 superclass.setAttribute.call(this, 'left', val[0], unit);
3934                 superclass.setAttribute.call(this, 'top', val[1], unit);
3935             } else {
3936                 superclass.setAttribute.call(this, attr, val, unit);
3937             }
3938         };
3939
3940         proto.getAttribute = function(attr) {
3941             if (this.patterns.points.test(attr)) {
3942                 var val = [
3943                         superclass.getAttribute.call(this, 'left'),
3944                         superclass.getAttribute.call(this, 'top')
3945                         ];
3946             } else {
3947                 val = superclass.getAttribute.call(this, attr);
3948             }
3949
3950             return val;
3951         };
3952
3953         proto.doMethod = function(attr, start, end) {
3954             var val = null;
3955
3956             if (this.patterns.points.test(attr)) {
3957                 var t = this.method(this.currentFrame, 0, 100, this.totalFrames) / 100;
3958                 val = Y.Bezier.getPosition(this.runtimeAttributes[attr], t);
3959             } else {
3960                 val = superclass.doMethod.call(this, attr, start, end);
3961             }
3962             return val;
3963         };
3964
3965         proto.setRuntimeAttribute = function(attr) {
3966             if (this.patterns.points.test(attr)) {
3967                 var el = this.getEl();
3968                 var attributes = this.attributes;
3969                 var start;
3970                 var control = attributes['points']['control'] || [];
3971                 var end;
3972                 var i, len;
3973
3974                 if (control.length > 0 && !(control[0] instanceof Array)) {
3975                     control = [control];
3976                 } else {
3977                     var tmp = [];
3978                     for (i = 0,len = control.length; i < len; ++i) {
3979                         tmp[i] = control[i];
3980                     }
3981                     control = tmp;
3982                 }
3983
3984                 Roo.fly(el).position();
3985
3986                 if (isset(attributes['points']['from'])) {
3987                     Roo.lib.Dom.setXY(el, attributes['points']['from']);
3988                 }
3989                 else {
3990                     Roo.lib.Dom.setXY(el, Roo.lib.Dom.getXY(el));
3991                 }
3992
3993                 start = this.getAttribute('points');
3994
3995
3996                 if (isset(attributes['points']['to'])) {
3997                     end = translateValues.call(this, attributes['points']['to'], start);
3998
3999                     var pageXY = Roo.lib.Dom.getXY(this.getEl());
4000                     for (i = 0,len = control.length; i < len; ++i) {
4001                         control[i] = translateValues.call(this, control[i], start);
4002                     }
4003
4004
4005                 } else if (isset(attributes['points']['by'])) {
4006                     end = [ start[0] + attributes['points']['by'][0], start[1] + attributes['points']['by'][1] ];
4007
4008                     for (i = 0,len = control.length; i < len; ++i) {
4009                         control[i] = [ start[0] + control[i][0], start[1] + control[i][1] ];
4010                     }
4011                 }
4012
4013                 this.runtimeAttributes[attr] = [start];
4014
4015                 if (control.length > 0) {
4016                     this.runtimeAttributes[attr] = this.runtimeAttributes[attr].concat(control);
4017                 }
4018
4019                 this.runtimeAttributes[attr][this.runtimeAttributes[attr].length] = end;
4020             }
4021             else {
4022                 superclass.setRuntimeAttribute.call(this, attr);
4023             }
4024         };
4025
4026         var translateValues = function(val, start) {
4027             var pageXY = Roo.lib.Dom.getXY(this.getEl());
4028             val = [ val[0] - pageXY[0] + start[0], val[1] - pageXY[1] + start[1] ];
4029
4030             return val;
4031         };
4032
4033         var isset = function(prop) {
4034             return (typeof prop !== 'undefined');
4035         };
4036     })();
4037 /*
4038  * Portions of this file are based on pieces of Yahoo User Interface Library
4039  * Copyright (c) 2007, Yahoo! Inc. All rights reserved.
4040  * YUI licensed under the BSD License:
4041  * http://developer.yahoo.net/yui/license.txt
4042  * <script type="text/javascript">
4043  *
4044  */
4045     (function() {
4046         Roo.lib.Scroll = function(el, attributes, duration, method) {
4047             if (el) {
4048                 Roo.lib.Scroll.superclass.constructor.call(this, el, attributes, duration, method);
4049             }
4050         };
4051
4052         Roo.extend(Roo.lib.Scroll, Roo.lib.ColorAnim);
4053
4054
4055         var Y = Roo.lib;
4056         var superclass = Y.Scroll.superclass;
4057         var proto = Y.Scroll.prototype;
4058
4059         proto.toString = function() {
4060             var el = this.getEl();
4061             var id = el.id || el.tagName;
4062             return ("Scroll " + id);
4063         };
4064
4065         proto.doMethod = function(attr, start, end) {
4066             var val = null;
4067
4068             if (attr == 'scroll') {
4069                 val = [
4070                         this.method(this.currentFrame, start[0], end[0] - start[0], this.totalFrames),
4071                         this.method(this.currentFrame, start[1], end[1] - start[1], this.totalFrames)
4072                         ];
4073
4074             } else {
4075                 val = superclass.doMethod.call(this, attr, start, end);
4076             }
4077             return val;
4078         };
4079
4080         proto.getAttribute = function(attr) {
4081             var val = null;
4082             var el = this.getEl();
4083
4084             if (attr == 'scroll') {
4085                 val = [ el.scrollLeft, el.scrollTop ];
4086             } else {
4087                 val = superclass.getAttribute.call(this, attr);
4088             }
4089
4090             return val;
4091         };
4092
4093         proto.setAttribute = function(attr, val, unit) {
4094             var el = this.getEl();
4095
4096             if (attr == 'scroll') {
4097                 el.scrollLeft = val[0];
4098                 el.scrollTop = val[1];
4099             } else {
4100                 superclass.setAttribute.call(this, attr, val, unit);
4101             }
4102         };
4103     })();
4104 /*
4105  * Based on:
4106  * Ext JS Library 1.1.1
4107  * Copyright(c) 2006-2007, Ext JS, LLC.
4108  *
4109  * Originally Released Under LGPL - original licence link has changed is not relivant.
4110  *
4111  * Fork - LGPL
4112  * <script type="text/javascript">
4113  */
4114
4115
4116 // nasty IE9 hack - what a pile of crap that is..
4117
4118  if (typeof Range != "undefined" && typeof Range.prototype.createContextualFragment == "undefined") {
4119     Range.prototype.createContextualFragment = function (html) {
4120         var doc = window.document;
4121         var container = doc.createElement("div");
4122         container.innerHTML = html;
4123         var frag = doc.createDocumentFragment(), n;
4124         while ((n = container.firstChild)) {
4125             frag.appendChild(n);
4126         }
4127         return frag;
4128     };
4129 }
4130
4131 /**
4132  * @class Roo.DomHelper
4133  * Utility class for working with DOM and/or Templates. It transparently supports using HTML fragments or DOM.
4134  * For more information see <a href="http://web.archive.org/web/20071221063734/http://www.jackslocum.com/blog/2006/10/06/domhelper-create-elements-using-dom-html-fragments-or-templates/">this blog post with examples</a>.
4135  * @singleton
4136  */
4137 Roo.DomHelper = function(){
4138     var tempTableEl = null;
4139     var emptyTags = /^(?:br|frame|hr|img|input|link|meta|range|spacer|wbr|area|param|col)$/i;
4140     var tableRe = /^table|tbody|tr|td$/i;
4141     var xmlns = {};
4142     // build as innerHTML where available
4143     /** @ignore */
4144     var createHtml = function(o){
4145         if(typeof o == 'string'){
4146             return o;
4147         }
4148         var b = "";
4149         if(!o.tag){
4150             o.tag = "div";
4151         }
4152         b += "<" + o.tag;
4153         for(var attr in o){
4154             if(attr == "tag" || attr == "children" || attr == "cn" || attr == "html" || typeof o[attr] == "function") continue;
4155             if(attr == "style"){
4156                 var s = o["style"];
4157                 if(typeof s == "function"){
4158                     s = s.call();
4159                 }
4160                 if(typeof s == "string"){
4161                     b += ' style="' + s + '"';
4162                 }else if(typeof s == "object"){
4163                     b += ' style="';
4164                     for(var key in s){
4165                         if(typeof s[key] != "function"){
4166                             b += key + ":" + s[key] + ";";
4167                         }
4168                     }
4169                     b += '"';
4170                 }
4171             }else{
4172                 if(attr == "cls"){
4173                     b += ' class="' + o["cls"] + '"';
4174                 }else if(attr == "htmlFor"){
4175                     b += ' for="' + o["htmlFor"] + '"';
4176                 }else{
4177                     b += " " + attr + '="' + o[attr] + '"';
4178                 }
4179             }
4180         }
4181         if(emptyTags.test(o.tag)){
4182             b += "/>";
4183         }else{
4184             b += ">";
4185             var cn = o.children || o.cn;
4186             if(cn){
4187                 //http://bugs.kde.org/show_bug.cgi?id=71506
4188                 if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4189                     for(var i = 0, len = cn.length; i < len; i++) {
4190                         b += createHtml(cn[i], b);
4191                     }
4192                 }else{
4193                     b += createHtml(cn, b);
4194                 }
4195             }
4196             if(o.html){
4197                 b += o.html;
4198             }
4199             b += "</" + o.tag + ">";
4200         }
4201         return b;
4202     };
4203
4204     // build as dom
4205     /** @ignore */
4206     var createDom = function(o, parentNode){
4207          
4208         // defininition craeted..
4209         var ns = false;
4210         if (o.ns && o.ns != 'html') {
4211                
4212             if (o.xmlns && typeof(xmlns[o.ns]) == 'undefined') {
4213                 xmlns[o.ns] = o.xmlns;
4214                 ns = o.xmlns;
4215             }
4216             if (typeof(xmlns[o.ns]) == 'undefined') {
4217                 console.log("Trying to create namespace element " + o.ns + ", however no xmlns was sent to builder previously");
4218             }
4219             ns = xmlns[o.ns];
4220         }
4221         
4222         
4223         if (typeof(o) == 'string') {
4224             return parentNode.appendChild(document.createTextNode(o));
4225         }
4226         o.tag = o.tag || div;
4227         if (o.ns && Roo.isIE) {
4228             ns = false;
4229             o.tag = o.ns + ':' + o.tag;
4230             
4231         }
4232         var el = ns ? document.createElementNS( ns, o.tag||'div') :  document.createElement(o.tag||'div');
4233         var useSet = el.setAttribute ? true : false; // In IE some elements don't have setAttribute
4234         for(var attr in o){
4235             
4236             if(attr == "tag" || attr == "ns" ||attr == "xmlns" ||attr == "children" || attr == "cn" || attr == "html" || 
4237                     attr == "style" || typeof o[attr] == "function") continue;
4238                     
4239             if(attr=="cls" && Roo.isIE){
4240                 el.className = o["cls"];
4241             }else{
4242                 if(useSet) { el.setAttribute(attr=="cls" ? 'class' : attr, o[attr]);}
4243                 else { 
4244                     el[attr] = o[attr];
4245                 }
4246             }
4247         }
4248         Roo.DomHelper.applyStyles(el, o.style);
4249         var cn = o.children || o.cn;
4250         if(cn){
4251             //http://bugs.kde.org/show_bug.cgi?id=71506
4252              if((cn instanceof Array) || (Roo.isSafari && typeof(cn.join) == "function")){
4253                 for(var i = 0, len = cn.length; i < len; i++) {
4254                     createDom(cn[i], el);
4255                 }
4256             }else{
4257                 createDom(cn, el);
4258             }
4259         }
4260         if(o.html){
4261             el.innerHTML = o.html;
4262         }
4263         if(parentNode){
4264            parentNode.appendChild(el);
4265         }
4266         return el;
4267     };
4268
4269     var ieTable = function(depth, s, h, e){
4270         tempTableEl.innerHTML = [s, h, e].join('');
4271         var i = -1, el = tempTableEl;
4272         while(++i < depth){
4273             el = el.firstChild;
4274         }
4275         return el;
4276     };
4277
4278     // kill repeat to save bytes
4279     var ts = '<table>',
4280         te = '</table>',
4281         tbs = ts+'<tbody>',
4282         tbe = '</tbody>'+te,
4283         trs = tbs + '<tr>',
4284         tre = '</tr>'+tbe;
4285
4286     /**
4287      * @ignore
4288      * Nasty code for IE's broken table implementation
4289      */
4290     var insertIntoTable = function(tag, where, el, html){
4291         if(!tempTableEl){
4292             tempTableEl = document.createElement('div');
4293         }
4294         var node;
4295         var before = null;
4296         if(tag == 'td'){
4297             if(where == 'afterbegin' || where == 'beforeend'){ // INTO a TD
4298                 return;
4299             }
4300             if(where == 'beforebegin'){
4301                 before = el;
4302                 el = el.parentNode;
4303             } else{
4304                 before = el.nextSibling;
4305                 el = el.parentNode;
4306             }
4307             node = ieTable(4, trs, html, tre);
4308         }
4309         else if(tag == 'tr'){
4310             if(where == 'beforebegin'){
4311                 before = el;
4312                 el = el.parentNode;
4313                 node = ieTable(3, tbs, html, tbe);
4314             } else if(where == 'afterend'){
4315                 before = el.nextSibling;
4316                 el = el.parentNode;
4317                 node = ieTable(3, tbs, html, tbe);
4318             } else{ // INTO a TR
4319                 if(where == 'afterbegin'){
4320                     before = el.firstChild;
4321                 }
4322                 node = ieTable(4, trs, html, tre);
4323             }
4324         } else if(tag == 'tbody'){
4325             if(where == 'beforebegin'){
4326                 before = el;
4327                 el = el.parentNode;
4328                 node = ieTable(2, ts, html, te);
4329             } else if(where == 'afterend'){
4330                 before = el.nextSibling;
4331                 el = el.parentNode;
4332                 node = ieTable(2, ts, html, te);
4333             } else{
4334                 if(where == 'afterbegin'){
4335                     before = el.firstChild;
4336                 }
4337                 node = ieTable(3, tbs, html, tbe);
4338             }
4339         } else{ // TABLE
4340             if(where == 'beforebegin' || where == 'afterend'){ // OUTSIDE the table
4341                 return;
4342             }
4343             if(where == 'afterbegin'){
4344                 before = el.firstChild;
4345             }
4346             node = ieTable(2, ts, html, te);
4347         }
4348         el.insertBefore(node, before);
4349         return node;
4350     };
4351
4352     return {
4353     /** True to force the use of DOM instead of html fragments @type Boolean */
4354     useDom : false,
4355
4356     /**
4357      * Returns the markup for the passed Element(s) config
4358      * @param {Object} o The Dom object spec (and children)
4359      * @return {String}
4360      */
4361     markup : function(o){
4362         return createHtml(o);
4363     },
4364
4365     /**
4366      * Applies a style specification to an element
4367      * @param {String/HTMLElement} el The element to apply styles to
4368      * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or
4369      * a function which returns such a specification.
4370      */
4371     applyStyles : function(el, styles){
4372         if(styles){
4373            el = Roo.fly(el);
4374            if(typeof styles == "string"){
4375                var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi;
4376                var matches;
4377                while ((matches = re.exec(styles)) != null){
4378                    el.setStyle(matches[1], matches[2]);
4379                }
4380            }else if (typeof styles == "object"){
4381                for (var style in styles){
4382                   el.setStyle(style, styles[style]);
4383                }
4384            }else if (typeof styles == "function"){
4385                 Roo.DomHelper.applyStyles(el, styles.call());
4386            }
4387         }
4388     },
4389
4390     /**
4391      * Inserts an HTML fragment into the Dom
4392      * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd.
4393      * @param {HTMLElement} el The context element
4394      * @param {String} html The HTML fragmenet
4395      * @return {HTMLElement} The new node
4396      */
4397     insertHtml : function(where, el, html){
4398         where = where.toLowerCase();
4399         if(el.insertAdjacentHTML){
4400             if(tableRe.test(el.tagName)){
4401                 var rs;
4402                 if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){
4403                     return rs;
4404                 }
4405             }
4406             switch(where){
4407                 case "beforebegin":
4408                     el.insertAdjacentHTML('BeforeBegin', html);
4409                     return el.previousSibling;
4410                 case "afterbegin":
4411                     el.insertAdjacentHTML('AfterBegin', html);
4412                     return el.firstChild;
4413                 case "beforeend":
4414                     el.insertAdjacentHTML('BeforeEnd', html);
4415                     return el.lastChild;
4416                 case "afterend":
4417                     el.insertAdjacentHTML('AfterEnd', html);
4418                     return el.nextSibling;
4419             }
4420             throw 'Illegal insertion point -> "' + where + '"';
4421         }
4422         var range = el.ownerDocument.createRange();
4423         var frag;
4424         switch(where){
4425              case "beforebegin":
4426                 range.setStartBefore(el);
4427                 frag = range.createContextualFragment(html);
4428                 el.parentNode.insertBefore(frag, el);
4429                 return el.previousSibling;
4430              case "afterbegin":
4431                 if(el.firstChild){
4432                     range.setStartBefore(el.firstChild);
4433                     frag = range.createContextualFragment(html);
4434                     el.insertBefore(frag, el.firstChild);
4435                     return el.firstChild;
4436                 }else{
4437                     el.innerHTML = html;
4438                     return el.firstChild;
4439                 }
4440             case "beforeend":
4441                 if(el.lastChild){
4442                     range.setStartAfter(el.lastChild);
4443                     frag = range.createContextualFragment(html);
4444                     el.appendChild(frag);
4445                     return el.lastChild;
4446                 }else{
4447                     el.innerHTML = html;
4448                     return el.lastChild;
4449                 }
4450             case "afterend":
4451                 range.setStartAfter(el);
4452                 frag = range.createContextualFragment(html);
4453                 el.parentNode.insertBefore(frag, el.nextSibling);
4454                 return el.nextSibling;
4455             }
4456             throw 'Illegal insertion point -> "' + where + '"';
4457     },
4458
4459     /**
4460      * Creates new Dom element(s) and inserts them before el
4461      * @param {String/HTMLElement/Element} el The context element
4462      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4463      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4464      * @return {HTMLElement/Roo.Element} The new node
4465      */
4466     insertBefore : function(el, o, returnElement){
4467         return this.doInsert(el, o, returnElement, "beforeBegin");
4468     },
4469
4470     /**
4471      * Creates new Dom element(s) and inserts them after el
4472      * @param {String/HTMLElement/Element} el The context element
4473      * @param {Object} o The Dom object spec (and children)
4474      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4475      * @return {HTMLElement/Roo.Element} The new node
4476      */
4477     insertAfter : function(el, o, returnElement){
4478         return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling");
4479     },
4480
4481     /**
4482      * Creates new Dom element(s) and inserts them as the first child of el
4483      * @param {String/HTMLElement/Element} el The context element
4484      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4485      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4486      * @return {HTMLElement/Roo.Element} The new node
4487      */
4488     insertFirst : function(el, o, returnElement){
4489         return this.doInsert(el, o, returnElement, "afterBegin");
4490     },
4491
4492     // private
4493     doInsert : function(el, o, returnElement, pos, sibling){
4494         el = Roo.getDom(el);
4495         var newNode;
4496         if(this.useDom || o.ns){
4497             newNode = createDom(o, null);
4498             el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el);
4499         }else{
4500             var html = createHtml(o);
4501             newNode = this.insertHtml(pos, el, html);
4502         }
4503         return returnElement ? Roo.get(newNode, true) : newNode;
4504     },
4505
4506     /**
4507      * Creates new Dom element(s) and appends them to el
4508      * @param {String/HTMLElement/Element} el The context element
4509      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4510      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4511      * @return {HTMLElement/Roo.Element} The new node
4512      */
4513     append : function(el, o, returnElement){
4514         el = Roo.getDom(el);
4515         var newNode;
4516         if(this.useDom || o.ns){
4517             newNode = createDom(o, null);
4518             el.appendChild(newNode);
4519         }else{
4520             var html = createHtml(o);
4521             newNode = this.insertHtml("beforeEnd", el, html);
4522         }
4523         return returnElement ? Roo.get(newNode, true) : newNode;
4524     },
4525
4526     /**
4527      * Creates new Dom element(s) and overwrites the contents of el with them
4528      * @param {String/HTMLElement/Element} el The context element
4529      * @param {Object/String} o The Dom object spec (and children) or raw HTML blob
4530      * @param {Boolean} returnElement (optional) true to return a Roo.Element
4531      * @return {HTMLElement/Roo.Element} The new node
4532      */
4533     overwrite : function(el, o, returnElement){
4534         el = Roo.getDom(el);
4535         if (o.ns) {
4536           
4537             while (el.childNodes.length) {
4538                 el.removeChild(el.firstChild);
4539             }
4540             createDom(o, el);
4541         } else {
4542             el.innerHTML = createHtml(o);   
4543         }
4544         
4545         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4546     },
4547
4548     /**
4549      * Creates a new Roo.DomHelper.Template from the Dom object spec
4550      * @param {Object} o The Dom object spec (and children)
4551      * @return {Roo.DomHelper.Template} The new template
4552      */
4553     createTemplate : function(o){
4554         var html = createHtml(o);
4555         return new Roo.Template(html);
4556     }
4557     };
4558 }();
4559 /*
4560  * Based on:
4561  * Ext JS Library 1.1.1
4562  * Copyright(c) 2006-2007, Ext JS, LLC.
4563  *
4564  * Originally Released Under LGPL - original licence link has changed is not relivant.
4565  *
4566  * Fork - LGPL
4567  * <script type="text/javascript">
4568  */
4569  
4570 /**
4571 * @class Roo.Template
4572 * Represents an HTML fragment template. Templates can be precompiled for greater performance.
4573 * For a list of available format functions, see {@link Roo.util.Format}.<br />
4574 * Usage:
4575 <pre><code>
4576 var t = new Roo.Template({
4577     html :  '&lt;div name="{id}"&gt;' + 
4578         '&lt;span class="{cls}"&gt;{name:trim} {someval:this.myformat}{value:ellipsis(10)}&lt;/span&gt;' +
4579         '&lt;/div&gt;',
4580     myformat: function (value, allValues) {
4581         return 'XX' + value;
4582     }
4583 });
4584 t.append('some-element', {id: 'myid', cls: 'myclass', name: 'foo', value: 'bar'});
4585 </code></pre>
4586 * For more information see this blog post with examples:
4587 *  <a href="http://www.cnitblog.com/seeyeah/archive/2011/12/30/38728.html/">DomHelper
4588      - Create Elements using DOM, HTML fragments and Templates</a>. 
4589 * @constructor
4590 * @param {Object} cfg - Configuration object.
4591 */
4592 Roo.Template = function(cfg){
4593     // BC!
4594     if(cfg instanceof Array){
4595         cfg = cfg.join("");
4596     }else if(arguments.length > 1){
4597         cfg = Array.prototype.join.call(arguments, "");
4598     }
4599     
4600     
4601     if (typeof(cfg) == 'object') {
4602         Roo.apply(this,cfg)
4603     } else {
4604         // bc
4605         this.html = cfg;
4606     }
4607     if (this.url) {
4608         this.load();
4609     }
4610     
4611 };
4612 Roo.Template.prototype = {
4613     
4614     /**
4615      * @cfg {String} url  The Url to load the template from. beware if you are loading from a url, the data may not be ready if you use it instantly..
4616      *                    it should be fixed so that template is observable...
4617      */
4618     url : false,
4619     /**
4620      * @cfg {String} html  The HTML fragment or an array of fragments to join("") or multiple arguments to join("")
4621      */
4622     html : '',
4623     /**
4624      * Returns an HTML fragment of this template with the specified values applied.
4625      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4626      * @return {String} The HTML fragment
4627      */
4628     applyTemplate : function(values){
4629         try {
4630            
4631             if(this.compiled){
4632                 return this.compiled(values);
4633             }
4634             var useF = this.disableFormats !== true;
4635             var fm = Roo.util.Format, tpl = this;
4636             var fn = function(m, name, format, args){
4637                 if(format && useF){
4638                     if(format.substr(0, 5) == "this."){
4639                         return tpl.call(format.substr(5), values[name], values);
4640                     }else{
4641                         if(args){
4642                             // quoted values are required for strings in compiled templates, 
4643                             // but for non compiled we need to strip them
4644                             // quoted reversed for jsmin
4645                             var re = /^\s*['"](.*)["']\s*$/;
4646                             args = args.split(',');
4647                             for(var i = 0, len = args.length; i < len; i++){
4648                                 args[i] = args[i].replace(re, "$1");
4649                             }
4650                             args = [values[name]].concat(args);
4651                         }else{
4652                             args = [values[name]];
4653                         }
4654                         return fm[format].apply(fm, args);
4655                     }
4656                 }else{
4657                     return values[name] !== undefined ? values[name] : "";
4658                 }
4659             };
4660             return this.html.replace(this.re, fn);
4661         } catch (e) {
4662             Roo.log(e);
4663             throw e;
4664         }
4665          
4666     },
4667     
4668     loading : false,
4669       
4670     load : function ()
4671     {
4672          
4673         if (this.loading) {
4674             return;
4675         }
4676         var _t = this;
4677         
4678         this.loading = true;
4679         this.compiled = false;
4680         
4681         var cx = new Roo.data.Connection();
4682         cx.request({
4683             url : this.url,
4684             method : 'GET',
4685             success : function (response) {
4686                 _t.loading = false;
4687                 _t.html = response.responseText;
4688                 _t.url = false;
4689                 _t.compile();
4690              },
4691             failure : function(response) {
4692                 Roo.log("Template failed to load from " + _t.url);
4693                 _t.loading = false;
4694             }
4695         });
4696     },
4697
4698     /**
4699      * Sets the HTML used as the template and optionally compiles it.
4700      * @param {String} html
4701      * @param {Boolean} compile (optional) True to compile the template (defaults to undefined)
4702      * @return {Roo.Template} this
4703      */
4704     set : function(html, compile){
4705         this.html = html;
4706         this.compiled = null;
4707         if(compile){
4708             this.compile();
4709         }
4710         return this;
4711     },
4712     
4713     /**
4714      * True to disable format functions (defaults to false)
4715      * @type Boolean
4716      */
4717     disableFormats : false,
4718     
4719     /**
4720     * The regular expression used to match template variables 
4721     * @type RegExp
4722     * @property 
4723     */
4724     re : /\{([\w-]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
4725     
4726     /**
4727      * Compiles the template into an internal function, eliminating the RegEx overhead.
4728      * @return {Roo.Template} this
4729      */
4730     compile : function(){
4731         var fm = Roo.util.Format;
4732         var useF = this.disableFormats !== true;
4733         var sep = Roo.isGecko ? "+" : ",";
4734         var fn = function(m, name, format, args){
4735             if(format && useF){
4736                 args = args ? ',' + args : "";
4737                 if(format.substr(0, 5) != "this."){
4738                     format = "fm." + format + '(';
4739                 }else{
4740                     format = 'this.call("'+ format.substr(5) + '", ';
4741                     args = ", values";
4742                 }
4743             }else{
4744                 args= ''; format = "(values['" + name + "'] == undefined ? '' : ";
4745             }
4746             return "'"+ sep + format + "values['" + name + "']" + args + ")"+sep+"'";
4747         };
4748         var body;
4749         // branched to use + in gecko and [].join() in others
4750         if(Roo.isGecko){
4751             body = "this.compiled = function(values){ return '" +
4752                    this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
4753                     "';};";
4754         }else{
4755             body = ["this.compiled = function(values){ return ['"];
4756             body.push(this.html.replace(/\\/g, '\\\\').replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn));
4757             body.push("'].join('');};");
4758             body = body.join('');
4759         }
4760         /**
4761          * eval:var:values
4762          * eval:var:fm
4763          */
4764         eval(body);
4765         return this;
4766     },
4767     
4768     // private function used to call members
4769     call : function(fnName, value, allValues){
4770         return this[fnName](value, allValues);
4771     },
4772     
4773     /**
4774      * Applies the supplied values to the template and inserts the new node(s) as the first child of el.
4775      * @param {String/HTMLElement/Roo.Element} el The context element
4776      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4777      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4778      * @return {HTMLElement/Roo.Element} The new node or Element
4779      */
4780     insertFirst: function(el, values, returnElement){
4781         return this.doInsert('afterBegin', el, values, returnElement);
4782     },
4783
4784     /**
4785      * Applies the supplied values to the template and inserts the new node(s) before el.
4786      * @param {String/HTMLElement/Roo.Element} el The context element
4787      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4788      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4789      * @return {HTMLElement/Roo.Element} The new node or Element
4790      */
4791     insertBefore: function(el, values, returnElement){
4792         return this.doInsert('beforeBegin', el, values, returnElement);
4793     },
4794
4795     /**
4796      * Applies the supplied values to the template and inserts the new node(s) after el.
4797      * @param {String/HTMLElement/Roo.Element} el The context element
4798      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4799      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4800      * @return {HTMLElement/Roo.Element} The new node or Element
4801      */
4802     insertAfter : function(el, values, returnElement){
4803         return this.doInsert('afterEnd', el, values, returnElement);
4804     },
4805     
4806     /**
4807      * Applies the supplied values to the template and appends the new node(s) to el.
4808      * @param {String/HTMLElement/Roo.Element} el The context element
4809      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4810      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4811      * @return {HTMLElement/Roo.Element} The new node or Element
4812      */
4813     append : function(el, values, returnElement){
4814         return this.doInsert('beforeEnd', el, values, returnElement);
4815     },
4816
4817     doInsert : function(where, el, values, returnEl){
4818         el = Roo.getDom(el);
4819         var newNode = Roo.DomHelper.insertHtml(where, el, this.applyTemplate(values));
4820         return returnEl ? Roo.get(newNode, true) : newNode;
4821     },
4822
4823     /**
4824      * Applies the supplied values to the template and overwrites the content of el with the new node(s).
4825      * @param {String/HTMLElement/Roo.Element} el The context element
4826      * @param {Object} values The template values. Can be an array if your params are numeric (i.e. {0}) or an object (i.e. {foo: 'bar'})
4827      * @param {Boolean} returnElement (optional) true to return a Roo.Element (defaults to undefined)
4828      * @return {HTMLElement/Roo.Element} The new node or Element
4829      */
4830     overwrite : function(el, values, returnElement){
4831         el = Roo.getDom(el);
4832         el.innerHTML = this.applyTemplate(values);
4833         return returnElement ? Roo.get(el.firstChild, true) : el.firstChild;
4834     }
4835 };
4836 /**
4837  * Alias for {@link #applyTemplate}
4838  * @method
4839  */
4840 Roo.Template.prototype.apply = Roo.Template.prototype.applyTemplate;
4841
4842 // backwards compat
4843 Roo.DomHelper.Template = Roo.Template;
4844
4845 /**
4846  * Creates a template from the passed element's value (<i>display:none</i> textarea, preferred) or innerHTML.
4847  * @param {String/HTMLElement} el A DOM element or its id
4848  * @returns {Roo.Template} The created template
4849  * @static
4850  */
4851 Roo.Template.from = function(el){
4852     el = Roo.getDom(el);
4853     return new Roo.Template(el.value || el.innerHTML);
4854 };/*
4855  * Based on:
4856  * Ext JS Library 1.1.1
4857  * Copyright(c) 2006-2007, Ext JS, LLC.
4858  *
4859  * Originally Released Under LGPL - original licence link has changed is not relivant.
4860  *
4861  * Fork - LGPL
4862  * <script type="text/javascript">
4863  */
4864  
4865
4866 /*
4867  * This is code is also distributed under MIT license for use
4868  * with jQuery and prototype JavaScript libraries.
4869  */
4870 /**
4871  * @class Roo.DomQuery
4872 Provides high performance selector/xpath processing by compiling queries into reusable functions. New pseudo classes and matchers can be plugged. It works on HTML and XML documents (if a content node is passed in).
4873 <p>
4874 DomQuery supports most of the <a href="http://www.w3.org/TR/2005/WD-css3-selectors-20051215/">CSS3 selectors spec</a>, along with some custom selectors and basic XPath.</p>
4875
4876 <p>
4877 All selectors, attribute filters and pseudos below can be combined infinitely in any order. For example "div.foo:nth-child(odd)[@foo=bar].bar:first" would be a perfectly valid selector. Node filters are processed in the order in which they appear, which allows you to optimize your queries for your document structure.
4878 </p>
4879 <h4>Element Selectors:</h4>
4880 <ul class="list">
4881     <li> <b>*</b> any element</li>
4882     <li> <b>E</b> an element with the tag E</li>
4883     <li> <b>E F</b> All descendent elements of E that have the tag F</li>
4884     <li> <b>E > F</b> or <b>E/F</b> all direct children elements of E that have the tag F</li>
4885     <li> <b>E + F</b> all elements with the tag F that are immediately preceded by an element with the tag E</li>
4886     <li> <b>E ~ F</b> all elements with the tag F that are preceded by a sibling element with the tag E</li>
4887 </ul>
4888 <h4>Attribute Selectors:</h4>
4889 <p>The use of @ and quotes are optional. For example, div[@foo='bar'] is also a valid attribute selector.</p>
4890 <ul class="list">
4891     <li> <b>E[foo]</b> has an attribute "foo"</li>
4892     <li> <b>E[foo=bar]</b> has an attribute "foo" that equals "bar"</li>
4893     <li> <b>E[foo^=bar]</b> has an attribute "foo" that starts with "bar"</li>
4894     <li> <b>E[foo$=bar]</b> has an attribute "foo" that ends with "bar"</li>
4895     <li> <b>E[foo*=bar]</b> has an attribute "foo" that contains the substring "bar"</li>
4896     <li> <b>E[foo%=2]</b> has an attribute "foo" that is evenly divisible by 2</li>
4897     <li> <b>E[foo!=bar]</b> has an attribute "foo" that does not equal "bar"</li>
4898 </ul>
4899 <h4>Pseudo Classes:</h4>
4900 <ul class="list">
4901     <li> <b>E:first-child</b> E is the first child of its parent</li>
4902     <li> <b>E:last-child</b> E is the last child of its parent</li>
4903     <li> <b>E:nth-child(<i>n</i>)</b> E is the <i>n</i>th child of its parent (1 based as per the spec)</li>
4904     <li> <b>E:nth-child(odd)</b> E is an odd child of its parent</li>
4905     <li> <b>E:nth-child(even)</b> E is an even child of its parent</li>
4906     <li> <b>E:only-child</b> E is the only child of its parent</li>
4907     <li> <b>E:checked</b> E is an element that is has a checked attribute that is true (e.g. a radio or checkbox) </li>
4908     <li> <b>E:first</b> the first E in the resultset</li>
4909     <li> <b>E:last</b> the last E in the resultset</li>
4910     <li> <b>E:nth(<i>n</i>)</b> the <i>n</i>th E in the resultset (1 based)</li>
4911     <li> <b>E:odd</b> shortcut for :nth-child(odd)</li>
4912     <li> <b>E:even</b> shortcut for :nth-child(even)</li>
4913     <li> <b>E:contains(foo)</b> E's innerHTML contains the substring "foo"</li>
4914     <li> <b>E:nodeValue(foo)</b> E contains a textNode with a nodeValue that equals "foo"</li>
4915     <li> <b>E:not(S)</b> an E element that does not match simple selector S</li>
4916     <li> <b>E:has(S)</b> an E element that has a descendent that matches simple selector S</li>
4917     <li> <b>E:next(S)</b> an E element whose next sibling matches simple selector S</li>
4918     <li> <b>E:prev(S)</b> an E element whose previous sibling matches simple selector S</li>
4919 </ul>
4920 <h4>CSS Value Selectors:</h4>
4921 <ul class="list">
4922     <li> <b>E{display=none}</b> css value "display" that equals "none"</li>
4923     <li> <b>E{display^=none}</b> css value "display" that starts with "none"</li>
4924     <li> <b>E{display$=none}</b> css value "display" that ends with "none"</li>
4925     <li> <b>E{display*=none}</b> css value "display" that contains the substring "none"</li>
4926     <li> <b>E{display%=2}</b> css value "display" that is evenly divisible by 2</li>
4927     <li> <b>E{display!=none}</b> css value "display" that does not equal "none"</li>
4928 </ul>
4929  * @singleton
4930  */
4931 Roo.DomQuery = function(){
4932     var cache = {}, simpleCache = {}, valueCache = {};
4933     var nonSpace = /\S/;
4934     var trimRe = /^\s+|\s+$/g;
4935     var tplRe = /\{(\d+)\}/g;
4936     var modeRe = /^(\s?[\/>+~]\s?|\s|$)/;
4937     var tagTokenRe = /^(#)?([\w-\*]+)/;
4938     var nthRe = /(\d*)n\+?(\d*)/, nthRe2 = /\D/;
4939
4940     function child(p, index){
4941         var i = 0;
4942         var n = p.firstChild;
4943         while(n){
4944             if(n.nodeType == 1){
4945                if(++i == index){
4946                    return n;
4947                }
4948             }
4949             n = n.nextSibling;
4950         }
4951         return null;
4952     };
4953
4954     function next(n){
4955         while((n = n.nextSibling) && n.nodeType != 1);
4956         return n;
4957     };
4958
4959     function prev(n){
4960         while((n = n.previousSibling) && n.nodeType != 1);
4961         return n;
4962     };
4963
4964     function children(d){
4965         var n = d.firstChild, ni = -1;
4966             while(n){
4967                 var nx = n.nextSibling;
4968                 if(n.nodeType == 3 && !nonSpace.test(n.nodeValue)){
4969                     d.removeChild(n);
4970                 }else{
4971                     n.nodeIndex = ++ni;
4972                 }
4973                 n = nx;
4974             }
4975             return this;
4976         };
4977
4978     function byClassName(c, a, v){
4979         if(!v){
4980             return c;
4981         }
4982         var r = [], ri = -1, cn;
4983         for(var i = 0, ci; ci = c[i]; i++){
4984             if((' '+ci.className+' ').indexOf(v) != -1){
4985                 r[++ri] = ci;
4986             }
4987         }
4988         return r;
4989     };
4990
4991     function attrValue(n, attr){
4992         if(!n.tagName && typeof n.length != "undefined"){
4993             n = n[0];
4994         }
4995         if(!n){
4996             return null;
4997         }
4998         if(attr == "for"){
4999             return n.htmlFor;
5000         }
5001         if(attr == "class" || attr == "className"){
5002             return n.className;
5003         }
5004         return n.getAttribute(attr) || n[attr];
5005
5006     };
5007
5008     function getNodes(ns, mode, tagName){
5009         var result = [], ri = -1, cs;
5010         if(!ns){
5011             return result;
5012         }
5013         tagName = tagName || "*";
5014         if(typeof ns.getElementsByTagName != "undefined"){
5015             ns = [ns];
5016         }
5017         if(!mode){
5018             for(var i = 0, ni; ni = ns[i]; i++){
5019                 cs = ni.getElementsByTagName(tagName);
5020                 for(var j = 0, ci; ci = cs[j]; j++){
5021                     result[++ri] = ci;
5022                 }
5023             }
5024         }else if(mode == "/" || mode == ">"){
5025             var utag = tagName.toUpperCase();
5026             for(var i = 0, ni, cn; ni = ns[i]; i++){
5027                 cn = ni.children || ni.childNodes;
5028                 for(var j = 0, cj; cj = cn[j]; j++){
5029                     if(cj.nodeName == utag || cj.nodeName == tagName  || tagName == '*'){
5030                         result[++ri] = cj;
5031                     }
5032                 }
5033             }
5034         }else if(mode == "+"){
5035             var utag = tagName.toUpperCase();
5036             for(var i = 0, n; n = ns[i]; i++){
5037                 while((n = n.nextSibling) && n.nodeType != 1);
5038                 if(n && (n.nodeName == utag || n.nodeName == tagName || tagName == '*')){
5039                     result[++ri] = n;
5040                 }
5041             }
5042         }else if(mode == "~"){
5043             for(var i = 0, n; n = ns[i]; i++){
5044                 while((n = n.nextSibling) && (n.nodeType != 1 || (tagName == '*' || n.tagName.toLowerCase()!=tagName)));
5045                 if(n){
5046                     result[++ri] = n;
5047                 }
5048             }
5049         }
5050         return result;
5051     };
5052
5053     function concat(a, b){
5054         if(b.slice){
5055             return a.concat(b);
5056         }
5057         for(var i = 0, l = b.length; i < l; i++){
5058             a[a.length] = b[i];
5059         }
5060         return a;
5061     }
5062
5063     function byTag(cs, tagName){
5064         if(cs.tagName || cs == document){
5065             cs = [cs];
5066         }
5067         if(!tagName){
5068             return cs;
5069         }
5070         var r = [], ri = -1;
5071         tagName = tagName.toLowerCase();
5072         for(var i = 0, ci; ci = cs[i]; i++){
5073             if(ci.nodeType == 1 && ci.tagName.toLowerCase()==tagName){
5074                 r[++ri] = ci;
5075             }
5076         }
5077         return r;
5078     };
5079
5080     function byId(cs, attr, id){
5081         if(cs.tagName || cs == document){
5082             cs = [cs];
5083         }
5084         if(!id){
5085             return cs;
5086         }
5087         var r = [], ri = -1;
5088         for(var i = 0,ci; ci = cs[i]; i++){
5089             if(ci && ci.id == id){
5090                 r[++ri] = ci;
5091                 return r;
5092             }
5093         }
5094         return r;
5095     };
5096
5097     function byAttribute(cs, attr, value, op, custom){
5098         var r = [], ri = -1, st = custom=="{";
5099         var f = Roo.DomQuery.operators[op];
5100         for(var i = 0, ci; ci = cs[i]; i++){
5101             var a;
5102             if(st){
5103                 a = Roo.DomQuery.getStyle(ci, attr);
5104             }
5105             else if(attr == "class" || attr == "className"){
5106                 a = ci.className;
5107             }else if(attr == "for"){
5108                 a = ci.htmlFor;
5109             }else if(attr == "href"){
5110                 a = ci.getAttribute("href", 2);
5111             }else{
5112                 a = ci.getAttribute(attr);
5113             }
5114             if((f && f(a, value)) || (!f && a)){
5115                 r[++ri] = ci;
5116             }
5117         }
5118         return r;
5119     };
5120
5121     function byPseudo(cs, name, value){
5122         return Roo.DomQuery.pseudos[name](cs, value);
5123     };
5124
5125     // This is for IE MSXML which does not support expandos.
5126     // IE runs the same speed using setAttribute, however FF slows way down
5127     // and Safari completely fails so they need to continue to use expandos.
5128     var isIE = window.ActiveXObject ? true : false;
5129
5130     // this eval is stop the compressor from
5131     // renaming the variable to something shorter
5132     
5133     /** eval:var:batch */
5134     var batch = 30803; 
5135
5136     var key = 30803;
5137
5138     function nodupIEXml(cs){
5139         var d = ++key;
5140         cs[0].setAttribute("_nodup", d);
5141         var r = [cs[0]];
5142         for(var i = 1, len = cs.length; i < len; i++){
5143             var c = cs[i];
5144             if(!c.getAttribute("_nodup") != d){
5145                 c.setAttribute("_nodup", d);
5146                 r[r.length] = c;
5147             }
5148         }
5149         for(var i = 0, len = cs.length; i < len; i++){
5150             cs[i].removeAttribute("_nodup");
5151         }
5152         return r;
5153     }
5154
5155     function nodup(cs){
5156         if(!cs){
5157             return [];
5158         }
5159         var len = cs.length, c, i, r = cs, cj, ri = -1;
5160         if(!len || typeof cs.nodeType != "undefined" || len == 1){
5161             return cs;
5162         }
5163         if(isIE && typeof cs[0].selectSingleNode != "undefined"){
5164             return nodupIEXml(cs);
5165         }
5166         var d = ++key;
5167         cs[0]._nodup = d;
5168         for(i = 1; c = cs[i]; i++){
5169             if(c._nodup != d){
5170                 c._nodup = d;
5171             }else{
5172                 r = [];
5173                 for(var j = 0; j < i; j++){
5174                     r[++ri] = cs[j];
5175                 }
5176                 for(j = i+1; cj = cs[j]; j++){
5177                     if(cj._nodup != d){
5178                         cj._nodup = d;
5179                         r[++ri] = cj;
5180                     }
5181                 }
5182                 return r;
5183             }
5184         }
5185         return r;
5186     }
5187
5188     function quickDiffIEXml(c1, c2){
5189         var d = ++key;
5190         for(var i = 0, len = c1.length; i < len; i++){
5191             c1[i].setAttribute("_qdiff", d);
5192         }
5193         var r = [];
5194         for(var i = 0, len = c2.length; i < len; i++){
5195             if(c2[i].getAttribute("_qdiff") != d){
5196                 r[r.length] = c2[i];
5197             }
5198         }
5199         for(var i = 0, len = c1.length; i < len; i++){
5200            c1[i].removeAttribute("_qdiff");
5201         }
5202         return r;
5203     }
5204
5205     function quickDiff(c1, c2){
5206         var len1 = c1.length;
5207         if(!len1){
5208             return c2;
5209         }
5210         if(isIE && c1[0].selectSingleNode){
5211             return quickDiffIEXml(c1, c2);
5212         }
5213         var d = ++key;
5214         for(var i = 0; i < len1; i++){
5215             c1[i]._qdiff = d;
5216         }
5217         var r = [];
5218         for(var i = 0, len = c2.length; i < len; i++){
5219             if(c2[i]._qdiff != d){
5220                 r[r.length] = c2[i];
5221             }
5222         }
5223         return r;
5224     }
5225
5226     function quickId(ns, mode, root, id){
5227         if(ns == root){
5228            var d = root.ownerDocument || root;
5229            return d.getElementById(id);
5230         }
5231         ns = getNodes(ns, mode, "*");
5232         return byId(ns, null, id);
5233     }
5234
5235     return {
5236         getStyle : function(el, name){
5237             return Roo.fly(el).getStyle(name);
5238         },
5239         /**
5240          * Compiles a selector/xpath query into a reusable function. The returned function
5241          * takes one parameter "root" (optional), which is the context node from where the query should start.
5242          * @param {String} selector The selector/xpath query
5243          * @param {String} type (optional) Either "select" (the default) or "simple" for a simple selector match
5244          * @return {Function}
5245          */
5246         compile : function(path, type){
5247             type = type || "select";
5248             
5249             var fn = ["var f = function(root){\n var mode; ++batch; var n = root || document;\n"];
5250             var q = path, mode, lq;
5251             var tk = Roo.DomQuery.matchers;
5252             var tklen = tk.length;
5253             var mm;
5254
5255             // accept leading mode switch
5256             var lmode = q.match(modeRe);
5257             if(lmode && lmode[1]){
5258                 fn[fn.length] = 'mode="'+lmode[1].replace(trimRe, "")+'";';
5259                 q = q.replace(lmode[1], "");
5260             }
5261             // strip leading slashes
5262             while(path.substr(0, 1)=="/"){
5263                 path = path.substr(1);
5264             }
5265
5266             while(q && lq != q){
5267                 lq = q;
5268                 var tm = q.match(tagTokenRe);
5269                 if(type == "select"){
5270                     if(tm){
5271                         if(tm[1] == "#"){
5272                             fn[fn.length] = 'n = quickId(n, mode, root, "'+tm[2]+'");';
5273                         }else{
5274                             fn[fn.length] = 'n = getNodes(n, mode, "'+tm[2]+'");';
5275                         }
5276                         q = q.replace(tm[0], "");
5277                     }else if(q.substr(0, 1) != '@'){
5278                         fn[fn.length] = 'n = getNodes(n, mode, "*");';
5279                     }
5280                 }else{
5281                     if(tm){
5282                         if(tm[1] == "#"){
5283                             fn[fn.length] = 'n = byId(n, null, "'+tm[2]+'");';
5284                         }else{
5285                             fn[fn.length] = 'n = byTag(n, "'+tm[2]+'");';
5286                         }
5287                         q = q.replace(tm[0], "");
5288                     }
5289                 }
5290                 while(!(mm = q.match(modeRe))){
5291                     var matched = false;
5292                     for(var j = 0; j < tklen; j++){
5293                         var t = tk[j];
5294                         var m = q.match(t.re);
5295                         if(m){
5296                             fn[fn.length] = t.select.replace(tplRe, function(x, i){
5297                                                     return m[i];
5298                                                 });
5299                             q = q.replace(m[0], "");
5300                             matched = true;
5301                             break;
5302                         }
5303                     }
5304                     // prevent infinite loop on bad selector
5305                     if(!matched){
5306                         throw 'Error parsing selector, parsing failed at "' + q + '"';
5307                     }
5308                 }
5309                 if(mm[1]){
5310                     fn[fn.length] = 'mode="'+mm[1].replace(trimRe, "")+'";';
5311                     q = q.replace(mm[1], "");
5312                 }
5313             }
5314             fn[fn.length] = "return nodup(n);\n}";
5315             
5316              /** 
5317               * list of variables that need from compression as they are used by eval.
5318              *  eval:var:batch 
5319              *  eval:var:nodup
5320              *  eval:var:byTag
5321              *  eval:var:ById
5322              *  eval:var:getNodes
5323              *  eval:var:quickId
5324              *  eval:var:mode
5325              *  eval:var:root
5326              *  eval:var:n
5327              *  eval:var:byClassName
5328              *  eval:var:byPseudo
5329              *  eval:var:byAttribute
5330              *  eval:var:attrValue
5331              * 
5332              **/ 
5333             eval(fn.join(""));
5334             return f;
5335         },
5336
5337         /**
5338          * Selects a group of elements.
5339          * @param {String} selector The selector/xpath query (can be a comma separated list of selectors)
5340          * @param {Node} root (optional) The start of the query (defaults to document).
5341          * @return {Array}
5342          */
5343         select : function(path, root, type){
5344             if(!root || root == document){
5345                 root = document;
5346             }
5347             if(typeof root == "string"){
5348                 root = document.getElementById(root);
5349             }
5350             var paths = path.split(",");
5351             var results = [];
5352             for(var i = 0, len = paths.length; i < len; i++){
5353                 var p = paths[i].replace(trimRe, "");
5354                 if(!cache[p]){
5355                     cache[p] = Roo.DomQuery.compile(p);
5356                     if(!cache[p]){
5357                         throw p + " is not a valid selector";
5358                     }
5359                 }
5360                 var result = cache[p](root);
5361                 if(result && result != document){
5362                     results = results.concat(result);
5363                 }
5364             }
5365             if(paths.length > 1){
5366                 return nodup(results);
5367             }
5368             return results;
5369         },
5370
5371         /**
5372          * Selects a single element.
5373          * @param {String} selector The selector/xpath query
5374          * @param {Node} root (optional) The start of the query (defaults to document).
5375          * @return {Element}
5376          */
5377         selectNode : function(path, root){
5378             return Roo.DomQuery.select(path, root)[0];
5379         },
5380
5381         /**
5382          * Selects the value of a node, optionally replacing null with the defaultValue.
5383          * @param {String} selector The selector/xpath query
5384          * @param {Node} root (optional) The start of the query (defaults to document).
5385          * @param {String} defaultValue
5386          */
5387         selectValue : function(path, root, defaultValue){
5388             path = path.replace(trimRe, "");
5389             if(!valueCache[path]){
5390                 valueCache[path] = Roo.DomQuery.compile(path, "select");
5391             }
5392             var n = valueCache[path](root);
5393             n = n[0] ? n[0] : n;
5394             var v = (n && n.firstChild ? n.firstChild.nodeValue : null);
5395             return ((v === null||v === undefined||v==='') ? defaultValue : v);
5396         },
5397
5398         /**
5399          * Selects the value of a node, parsing integers and floats.
5400          * @param {String} selector The selector/xpath query
5401          * @param {Node} root (optional) The start of the query (defaults to document).
5402          * @param {Number} defaultValue
5403          * @return {Number}
5404          */
5405         selectNumber : function(path, root, defaultValue){
5406             var v = Roo.DomQuery.selectValue(path, root, defaultValue || 0);
5407             return parseFloat(v);
5408         },
5409
5410         /**
5411          * Returns true if the passed element(s) match the passed simple selector (e.g. div.some-class or span:first-child)
5412          * @param {String/HTMLElement/Array} el An element id, element or array of elements
5413          * @param {String} selector The simple selector to test
5414          * @return {Boolean}
5415          */
5416         is : function(el, ss){
5417             if(typeof el == "string"){
5418                 el = document.getElementById(el);
5419             }
5420             var isArray = (el instanceof Array);
5421             var result = Roo.DomQuery.filter(isArray ? el : [el], ss);
5422             return isArray ? (result.length == el.length) : (result.length > 0);
5423         },
5424
5425         /**
5426          * Filters an array of elements to only include matches of a simple selector (e.g. div.some-class or span:first-child)
5427          * @param {Array} el An array of elements to filter
5428          * @param {String} selector The simple selector to test
5429          * @param {Boolean} nonMatches If true, it returns the elements that DON'T match
5430          * the selector instead of the ones that match
5431          * @return {Array}
5432          */
5433         filter : function(els, ss, nonMatches){
5434             ss = ss.replace(trimRe, "");
5435             if(!simpleCache[ss]){
5436                 simpleCache[ss] = Roo.DomQuery.compile(ss, "simple");
5437             }
5438             var result = simpleCache[ss](els);
5439             return nonMatches ? quickDiff(result, els) : result;
5440         },
5441
5442         /**
5443          * Collection of matching regular expressions and code snippets.
5444          */
5445         matchers : [{
5446                 re: /^\.([\w-]+)/,
5447                 select: 'n = byClassName(n, null, " {1} ");'
5448             }, {
5449                 re: /^\:([\w-]+)(?:\(((?:[^\s>\/]*|.*?))\))?/,
5450                 select: 'n = byPseudo(n, "{1}", "{2}");'
5451             },{
5452                 re: /^(?:([\[\{])(?:@)?([\w-]+)\s?(?:(=|.=)\s?['"]?(.*?)["']?)?[\]\}])/,
5453                 select: 'n = byAttribute(n, "{2}", "{4}", "{3}", "{1}");'
5454             }, {
5455                 re: /^#([\w-]+)/,
5456                 select: 'n = byId(n, null, "{1}");'
5457             },{
5458                 re: /^@([\w-]+)/,
5459                 select: 'return {firstChild:{nodeValue:attrValue(n, "{1}")}};'
5460             }
5461         ],
5462
5463         /**
5464          * Collection of operator comparison functions. The default operators are =, !=, ^=, $=, *=, %=, |= and ~=.
5465          * New operators can be added as long as the match the format <i>c</i>= where <i>c</i> is any character other than space, &gt; &lt;.
5466          */
5467         operators : {
5468             "=" : function(a, v){
5469                 return a == v;
5470             },
5471             "!=" : function(a, v){
5472                 return a != v;
5473             },
5474             "^=" : function(a, v){
5475                 return a && a.substr(0, v.length) == v;
5476             },
5477             "$=" : function(a, v){
5478                 return a && a.substr(a.length-v.length) == v;
5479             },
5480             "*=" : function(a, v){
5481                 return a && a.indexOf(v) !== -1;
5482             },
5483             "%=" : function(a, v){
5484                 return (a % v) == 0;
5485             },
5486             "|=" : function(a, v){
5487                 return a && (a == v || a.substr(0, v.length+1) == v+'-');
5488             },
5489             "~=" : function(a, v){
5490                 return a && (' '+a+' ').indexOf(' '+v+' ') != -1;
5491             }
5492         },
5493
5494         /**
5495          * Collection of "pseudo class" processors. Each processor is passed the current nodeset (array)
5496          * and the argument (if any) supplied in the selector.
5497          */
5498         pseudos : {
5499             "first-child" : function(c){
5500                 var r = [], ri = -1, n;
5501                 for(var i = 0, ci; ci = n = c[i]; i++){
5502                     while((n = n.previousSibling) && n.nodeType != 1);
5503                     if(!n){
5504                         r[++ri] = ci;
5505                     }
5506                 }
5507                 return r;
5508             },
5509
5510             "last-child" : function(c){
5511                 var r = [], ri = -1, n;
5512                 for(var i = 0, ci; ci = n = c[i]; i++){
5513                     while((n = n.nextSibling) && n.nodeType != 1);
5514                     if(!n){
5515                         r[++ri] = ci;
5516                     }
5517                 }
5518                 return r;
5519             },
5520
5521             "nth-child" : function(c, a) {
5522                 var r = [], ri = -1;
5523                 var m = nthRe.exec(a == "even" && "2n" || a == "odd" && "2n+1" || !nthRe2.test(a) && "n+" + a || a);
5524                 var f = (m[1] || 1) - 0, l = m[2] - 0;
5525                 for(var i = 0, n; n = c[i]; i++){
5526                     var pn = n.parentNode;
5527                     if (batch != pn._batch) {
5528                         var j = 0;
5529                         for(var cn = pn.firstChild; cn; cn = cn.nextSibling){
5530                             if(cn.nodeType == 1){
5531                                cn.nodeIndex = ++j;
5532                             }
5533                         }
5534                         pn._batch = batch;
5535                     }
5536                     if (f == 1) {
5537                         if (l == 0 || n.nodeIndex == l){
5538                             r[++ri] = n;
5539                         }
5540                     } else if ((n.nodeIndex + l) % f == 0){
5541                         r[++ri] = n;
5542                     }
5543                 }
5544
5545                 return r;
5546             },
5547
5548             "only-child" : function(c){
5549                 var r = [], ri = -1;;
5550                 for(var i = 0, ci; ci = c[i]; i++){
5551                     if(!prev(ci) && !next(ci)){
5552                         r[++ri] = ci;
5553                     }
5554                 }
5555                 return r;
5556             },
5557
5558             "empty" : function(c){
5559                 var r = [], ri = -1;
5560                 for(var i = 0, ci; ci = c[i]; i++){
5561                     var cns = ci.childNodes, j = 0, cn, empty = true;
5562                     while(cn = cns[j]){
5563                         ++j;
5564                         if(cn.nodeType == 1 || cn.nodeType == 3){
5565                             empty = false;
5566                             break;
5567                         }
5568                     }
5569                     if(empty){
5570                         r[++ri] = ci;
5571                     }
5572                 }
5573                 return r;
5574             },
5575
5576             "contains" : function(c, v){
5577                 var r = [], ri = -1;
5578                 for(var i = 0, ci; ci = c[i]; i++){
5579                     if((ci.textContent||ci.innerText||'').indexOf(v) != -1){
5580                         r[++ri] = ci;
5581                     }
5582                 }
5583                 return r;
5584             },
5585
5586             "nodeValue" : function(c, v){
5587                 var r = [], ri = -1;
5588                 for(var i = 0, ci; ci = c[i]; i++){
5589                     if(ci.firstChild && ci.firstChild.nodeValue == v){
5590                         r[++ri] = ci;
5591                     }
5592                 }
5593                 return r;
5594             },
5595
5596             "checked" : function(c){
5597                 var r = [], ri = -1;
5598                 for(var i = 0, ci; ci = c[i]; i++){
5599                     if(ci.checked == true){
5600                         r[++ri] = ci;
5601                     }
5602                 }
5603                 return r;
5604             },
5605
5606             "not" : function(c, ss){
5607                 return Roo.DomQuery.filter(c, ss, true);
5608             },
5609
5610             "odd" : function(c){
5611                 return this["nth-child"](c, "odd");
5612             },
5613
5614             "even" : function(c){
5615                 return this["nth-child"](c, "even");
5616             },
5617
5618             "nth" : function(c, a){
5619                 return c[a-1] || [];
5620             },
5621
5622             "first" : function(c){
5623                 return c[0] || [];
5624             },
5625
5626             "last" : function(c){
5627                 return c[c.length-1] || [];
5628             },
5629
5630             "has" : function(c, ss){
5631                 var s = Roo.DomQuery.select;
5632                 var r = [], ri = -1;
5633                 for(var i = 0, ci; ci = c[i]; i++){
5634                     if(s(ss, ci).length > 0){
5635                         r[++ri] = ci;
5636                     }
5637                 }
5638                 return r;
5639             },
5640
5641             "next" : function(c, ss){
5642                 var is = Roo.DomQuery.is;
5643                 var r = [], ri = -1;
5644                 for(var i = 0, ci; ci = c[i]; i++){
5645                     var n = next(ci);
5646                     if(n && is(n, ss)){
5647                         r[++ri] = ci;
5648                     }
5649                 }
5650                 return r;
5651             },
5652
5653             "prev" : function(c, ss){
5654                 var is = Roo.DomQuery.is;
5655                 var r = [], ri = -1;
5656                 for(var i = 0, ci; ci = c[i]; i++){
5657                     var n = prev(ci);
5658                     if(n && is(n, ss)){
5659                         r[++ri] = ci;
5660                     }
5661                 }
5662                 return r;
5663             }
5664         }
5665     };
5666 }();
5667
5668 /**
5669  * Selects an array of DOM nodes by CSS/XPath selector. Shorthand of {@link Roo.DomQuery#select}
5670  * @param {String} path The selector/xpath query
5671  * @param {Node} root (optional) The start of the query (defaults to document).
5672  * @return {Array}
5673  * @member Roo
5674  * @method query
5675  */
5676 Roo.query = Roo.DomQuery.select;
5677 /*
5678  * Based on:
5679  * Ext JS Library 1.1.1
5680  * Copyright(c) 2006-2007, Ext JS, LLC.
5681  *
5682  * Originally Released Under LGPL - original licence link has changed is not relivant.
5683  *
5684  * Fork - LGPL
5685  * <script type="text/javascript">
5686  */
5687
5688 /**
5689  * @class Roo.util.Observable
5690  * Base class that provides a common interface for publishing events. Subclasses are expected to
5691  * to have a property "events" with all the events defined.<br>
5692  * For example:
5693  * <pre><code>
5694  Employee = function(name){
5695     this.name = name;
5696     this.addEvents({
5697         "fired" : true,
5698         "quit" : true
5699     });
5700  }
5701  Roo.extend(Employee, Roo.util.Observable);
5702 </code></pre>
5703  * @param {Object} config properties to use (incuding events / listeners)
5704  */
5705
5706 Roo.util.Observable = function(cfg){
5707     
5708     cfg = cfg|| {};
5709     this.addEvents(cfg.events || {});
5710     if (cfg.events) {
5711         delete cfg.events; // make sure
5712     }
5713      
5714     Roo.apply(this, cfg);
5715     
5716     if(this.listeners){
5717         this.on(this.listeners);
5718         delete this.listeners;
5719     }
5720 };
5721 Roo.util.Observable.prototype = {
5722     /** 
5723  * @cfg {Object} listeners  list of events and functions to call for this object, 
5724  * For example :
5725  * <pre><code>
5726     listeners :  { 
5727        'click' : function(e) {
5728            ..... 
5729         } ,
5730         .... 
5731     } 
5732   </code></pre>
5733  */
5734     
5735     
5736     /**
5737      * Fires the specified event with the passed parameters (minus the event name).
5738      * @param {String} eventName
5739      * @param {Object...} args Variable number of parameters are passed to handlers
5740      * @return {Boolean} returns false if any of the handlers return false otherwise it returns true
5741      */
5742     fireEvent : function(){
5743         var ce = this.events[arguments[0].toLowerCase()];
5744         if(typeof ce == "object"){
5745             return ce.fire.apply(ce, Array.prototype.slice.call(arguments, 1));
5746         }else{
5747             return true;
5748         }
5749     },
5750
5751     // private
5752     filterOptRe : /^(?:scope|delay|buffer|single)$/,
5753
5754     /**
5755      * Appends an event handler to this component
5756      * @param {String}   eventName The type of event to listen for
5757      * @param {Function} handler The method the event invokes
5758      * @param {Object}   scope (optional) The scope in which to execute the handler
5759      * function. The handler function's "this" context.
5760      * @param {Object}   options (optional) An object containing handler configuration
5761      * properties. This may contain any of the following properties:<ul>
5762      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
5763      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
5764      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
5765      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
5766      * by the specified number of milliseconds. If the event fires again within that time, the original
5767      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
5768      * </ul><br>
5769      * <p>
5770      * <b>Combining Options</b><br>
5771      * Using the options argument, it is possible to combine different types of listeners:<br>
5772      * <br>
5773      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)
5774                 <pre><code>
5775                 el.on('click', this.onClick, this, {
5776                         single: true,
5777                 delay: 100,
5778                 forumId: 4
5779                 });
5780                 </code></pre>
5781      * <p>
5782      * <b>Attaching multiple handlers in 1 call</b><br>
5783      * The method also allows for a single argument to be passed which is a config object containing properties
5784      * which specify multiple handlers.
5785      * <pre><code>
5786                 el.on({
5787                         'click': {
5788                         fn: this.onClick,
5789                         scope: this,
5790                         delay: 100
5791                 }, 
5792                 'mouseover': {
5793                         fn: this.onMouseOver,
5794                         scope: this
5795                 },
5796                 'mouseout': {
5797                         fn: this.onMouseOut,
5798                         scope: this
5799                 }
5800                 });
5801                 </code></pre>
5802      * <p>
5803      * Or a shorthand syntax which passes the same scope object to all handlers:
5804         <pre><code>
5805                 el.on({
5806                         'click': this.onClick,
5807                 'mouseover': this.onMouseOver,
5808                 'mouseout': this.onMouseOut,
5809                 scope: this
5810                 });
5811                 </code></pre>
5812      */
5813     addListener : function(eventName, fn, scope, o){
5814         if(typeof eventName == "object"){
5815             o = eventName;
5816             for(var e in o){
5817                 if(this.filterOptRe.test(e)){
5818                     continue;
5819                 }
5820                 if(typeof o[e] == "function"){
5821                     // shared options
5822                     this.addListener(e, o[e], o.scope,  o);
5823                 }else{
5824                     // individual options
5825                     this.addListener(e, o[e].fn, o[e].scope, o[e]);
5826                 }
5827             }
5828             return;
5829         }
5830         o = (!o || typeof o == "boolean") ? {} : o;
5831         eventName = eventName.toLowerCase();
5832         var ce = this.events[eventName] || true;
5833         if(typeof ce == "boolean"){
5834             ce = new Roo.util.Event(this, eventName);
5835             this.events[eventName] = ce;
5836         }
5837         ce.addListener(fn, scope, o);
5838     },
5839
5840     /**
5841      * Removes a listener
5842      * @param {String}   eventName     The type of event to listen for
5843      * @param {Function} handler        The handler to remove
5844      * @param {Object}   scope  (optional) The scope (this object) for the handler
5845      */
5846     removeListener : function(eventName, fn, scope){
5847         var ce = this.events[eventName.toLowerCase()];
5848         if(typeof ce == "object"){
5849             ce.removeListener(fn, scope);
5850         }
5851     },
5852
5853     /**
5854      * Removes all listeners for this object
5855      */
5856     purgeListeners : function(){
5857         for(var evt in this.events){
5858             if(typeof this.events[evt] == "object"){
5859                  this.events[evt].clearListeners();
5860             }
5861         }
5862     },
5863
5864     relayEvents : function(o, events){
5865         var createHandler = function(ename){
5866             return function(){
5867                 return this.fireEvent.apply(this, Roo.combine(ename, Array.prototype.slice.call(arguments, 0)));
5868             };
5869         };
5870         for(var i = 0, len = events.length; i < len; i++){
5871             var ename = events[i];
5872             if(!this.events[ename]){ this.events[ename] = true; };
5873             o.on(ename, createHandler(ename), this);
5874         }
5875     },
5876
5877     /**
5878      * Used to define events on this Observable
5879      * @param {Object} object The object with the events defined
5880      */
5881     addEvents : function(o){
5882         if(!this.events){
5883             this.events = {};
5884         }
5885         Roo.applyIf(this.events, o);
5886     },
5887
5888     /**
5889      * Checks to see if this object has any listeners for a specified event
5890      * @param {String} eventName The name of the event to check for
5891      * @return {Boolean} True if the event is being listened for, else false
5892      */
5893     hasListener : function(eventName){
5894         var e = this.events[eventName];
5895         return typeof e == "object" && e.listeners.length > 0;
5896     }
5897 };
5898 /**
5899  * Appends an event handler to this element (shorthand for addListener)
5900  * @param {String}   eventName     The type of event to listen for
5901  * @param {Function} handler        The method the event invokes
5902  * @param {Object}   scope (optional) The scope in which to execute the handler
5903  * function. The handler function's "this" context.
5904  * @param {Object}   options  (optional)
5905  * @method
5906  */
5907 Roo.util.Observable.prototype.on = Roo.util.Observable.prototype.addListener;
5908 /**
5909  * Removes a listener (shorthand for removeListener)
5910  * @param {String}   eventName     The type of event to listen for
5911  * @param {Function} handler        The handler to remove
5912  * @param {Object}   scope  (optional) The scope (this object) for the handler
5913  * @method
5914  */
5915 Roo.util.Observable.prototype.un = Roo.util.Observable.prototype.removeListener;
5916
5917 /**
5918  * Starts capture on the specified Observable. All events will be passed
5919  * to the supplied function with the event name + standard signature of the event
5920  * <b>before</b> the event is fired. If the supplied function returns false,
5921  * the event will not fire.
5922  * @param {Observable} o The Observable to capture
5923  * @param {Function} fn The function to call
5924  * @param {Object} scope (optional) The scope (this object) for the fn
5925  * @static
5926  */
5927 Roo.util.Observable.capture = function(o, fn, scope){
5928     o.fireEvent = o.fireEvent.createInterceptor(fn, scope);
5929 };
5930
5931 /**
5932  * Removes <b>all</b> added captures from the Observable.
5933  * @param {Observable} o The Observable to release
5934  * @static
5935  */
5936 Roo.util.Observable.releaseCapture = function(o){
5937     o.fireEvent = Roo.util.Observable.prototype.fireEvent;
5938 };
5939
5940 (function(){
5941
5942     var createBuffered = function(h, o, scope){
5943         var task = new Roo.util.DelayedTask();
5944         return function(){
5945             task.delay(o.buffer, h, scope, Array.prototype.slice.call(arguments, 0));
5946         };
5947     };
5948
5949     var createSingle = function(h, e, fn, scope){
5950         return function(){
5951             e.removeListener(fn, scope);
5952             return h.apply(scope, arguments);
5953         };
5954     };
5955
5956     var createDelayed = function(h, o, scope){
5957         return function(){
5958             var args = Array.prototype.slice.call(arguments, 0);
5959             setTimeout(function(){
5960                 h.apply(scope, args);
5961             }, o.delay || 10);
5962         };
5963     };
5964
5965     Roo.util.Event = function(obj, name){
5966         this.name = name;
5967         this.obj = obj;
5968         this.listeners = [];
5969     };
5970
5971     Roo.util.Event.prototype = {
5972         addListener : function(fn, scope, options){
5973             var o = options || {};
5974             scope = scope || this.obj;
5975             if(!this.isListening(fn, scope)){
5976                 var l = {fn: fn, scope: scope, options: o};
5977                 var h = fn;
5978                 if(o.delay){
5979                     h = createDelayed(h, o, scope);
5980                 }
5981                 if(o.single){
5982                     h = createSingle(h, this, fn, scope);
5983                 }
5984                 if(o.buffer){
5985                     h = createBuffered(h, o, scope);
5986                 }
5987                 l.fireFn = h;
5988                 if(!this.firing){ // if we are currently firing this event, don't disturb the listener loop
5989                     this.listeners.push(l);
5990                 }else{
5991                     this.listeners = this.listeners.slice(0);
5992                     this.listeners.push(l);
5993                 }
5994             }
5995         },
5996
5997         findListener : function(fn, scope){
5998             scope = scope || this.obj;
5999             var ls = this.listeners;
6000             for(var i = 0, len = ls.length; i < len; i++){
6001                 var l = ls[i];
6002                 if(l.fn == fn && l.scope == scope){
6003                     return i;
6004                 }
6005             }
6006             return -1;
6007         },
6008
6009         isListening : function(fn, scope){
6010             return this.findListener(fn, scope) != -1;
6011         },
6012
6013         removeListener : function(fn, scope){
6014             var index;
6015             if((index = this.findListener(fn, scope)) != -1){
6016                 if(!this.firing){
6017                     this.listeners.splice(index, 1);
6018                 }else{
6019                     this.listeners = this.listeners.slice(0);
6020                     this.listeners.splice(index, 1);
6021                 }
6022                 return true;
6023             }
6024             return false;
6025         },
6026
6027         clearListeners : function(){
6028             this.listeners = [];
6029         },
6030
6031         fire : function(){
6032             var ls = this.listeners, scope, len = ls.length;
6033             if(len > 0){
6034                 this.firing = true;
6035                 var args = Array.prototype.slice.call(arguments, 0);
6036                 for(var i = 0; i < len; i++){
6037                     var l = ls[i];
6038                     if(l.fireFn.apply(l.scope||this.obj||window, arguments) === false){
6039                         this.firing = false;
6040                         return false;
6041                     }
6042                 }
6043                 this.firing = false;
6044             }
6045             return true;
6046         }
6047     };
6048 })();/*
6049  * Based on:
6050  * Ext JS Library 1.1.1
6051  * Copyright(c) 2006-2007, Ext JS, LLC.
6052  *
6053  * Originally Released Under LGPL - original licence link has changed is not relivant.
6054  *
6055  * Fork - LGPL
6056  * <script type="text/javascript">
6057  */
6058
6059 /**
6060  * @class Roo.EventManager
6061  * Registers event handlers that want to receive a normalized EventObject instead of the standard browser event and provides 
6062  * several useful events directly.
6063  * See {@link Roo.EventObject} for more details on normalized event objects.
6064  * @singleton
6065  */
6066 Roo.EventManager = function(){
6067     var docReadyEvent, docReadyProcId, docReadyState = false;
6068     var resizeEvent, resizeTask, textEvent, textSize;
6069     var E = Roo.lib.Event;
6070     var D = Roo.lib.Dom;
6071
6072     
6073     
6074
6075     var fireDocReady = function(){
6076         if(!docReadyState){
6077             docReadyState = true;
6078             Roo.isReady = true;
6079             if(docReadyProcId){
6080                 clearInterval(docReadyProcId);
6081             }
6082             if(Roo.isGecko || Roo.isOpera) {
6083                 document.removeEventListener("DOMContentLoaded", fireDocReady, false);
6084             }
6085             if(Roo.isIE){
6086                 var defer = document.getElementById("ie-deferred-loader");
6087                 if(defer){
6088                     defer.onreadystatechange = null;
6089                     defer.parentNode.removeChild(defer);
6090                 }
6091             }
6092             if(docReadyEvent){
6093                 docReadyEvent.fire();
6094                 docReadyEvent.clearListeners();
6095             }
6096         }
6097     };
6098     
6099     var initDocReady = function(){
6100         docReadyEvent = new Roo.util.Event();
6101         if(Roo.isGecko || Roo.isOpera) {
6102             document.addEventListener("DOMContentLoaded", fireDocReady, false);
6103         }else if(Roo.isIE){
6104             document.write("<s"+'cript id="ie-deferred-loader" defer="defer" src="/'+'/:"></s'+"cript>");
6105             var defer = document.getElementById("ie-deferred-loader");
6106             defer.onreadystatechange = function(){
6107                 if(this.readyState == "complete"){
6108                     fireDocReady();
6109                 }
6110             };
6111         }else if(Roo.isSafari){ 
6112             docReadyProcId = setInterval(function(){
6113                 var rs = document.readyState;
6114                 if(rs == "complete") {
6115                     fireDocReady();     
6116                  }
6117             }, 10);
6118         }
6119         // no matter what, make sure it fires on load
6120         E.on(window, "load", fireDocReady);
6121     };
6122
6123     var createBuffered = function(h, o){
6124         var task = new Roo.util.DelayedTask(h);
6125         return function(e){
6126             // create new event object impl so new events don't wipe out properties
6127             e = new Roo.EventObjectImpl(e);
6128             task.delay(o.buffer, h, null, [e]);
6129         };
6130     };
6131
6132     var createSingle = function(h, el, ename, fn){
6133         return function(e){
6134             Roo.EventManager.removeListener(el, ename, fn);
6135             h(e);
6136         };
6137     };
6138
6139     var createDelayed = function(h, o){
6140         return function(e){
6141             // create new event object impl so new events don't wipe out properties
6142             e = new Roo.EventObjectImpl(e);
6143             setTimeout(function(){
6144                 h(e);
6145             }, o.delay || 10);
6146         };
6147     };
6148     var transitionEndVal = false;
6149     
6150     var transitionEnd = function()
6151     {
6152         if (transitionEndVal) {
6153             return transitionEndVal;
6154         }
6155         var el = document.createElement('div');
6156
6157         var transEndEventNames = {
6158             WebkitTransition : 'webkitTransitionEnd',
6159             MozTransition    : 'transitionend',
6160             OTransition      : 'oTransitionEnd otransitionend',
6161             transition       : 'transitionend'
6162         };
6163     
6164         for (var name in transEndEventNames) {
6165             if (el.style[name] !== undefined) {
6166                 transitionEndVal = transEndEventNames[name];
6167                 return  transitionEndVal ;
6168             }
6169         }
6170     }
6171     
6172
6173     var listen = function(element, ename, opt, fn, scope){
6174         var o = (!opt || typeof opt == "boolean") ? {} : opt;
6175         fn = fn || o.fn; scope = scope || o.scope;
6176         var el = Roo.getDom(element);
6177         
6178         
6179         if(!el){
6180             throw "Error listening for \"" + ename + '\". Element "' + element + '" doesn\'t exist.';
6181         }
6182         
6183         if (ename == 'transitionend') {
6184             ename = transitionEnd();
6185         }
6186         var h = function(e){
6187             e = Roo.EventObject.setEvent(e);
6188             var t;
6189             if(o.delegate){
6190                 t = e.getTarget(o.delegate, el);
6191                 if(!t){
6192                     return;
6193                 }
6194             }else{
6195                 t = e.target;
6196             }
6197             if(o.stopEvent === true){
6198                 e.stopEvent();
6199             }
6200             if(o.preventDefault === true){
6201                e.preventDefault();
6202             }
6203             if(o.stopPropagation === true){
6204                 e.stopPropagation();
6205             }
6206
6207             if(o.normalized === false){
6208                 e = e.browserEvent;
6209             }
6210
6211             fn.call(scope || el, e, t, o);
6212         };
6213         if(o.delay){
6214             h = createDelayed(h, o);
6215         }
6216         if(o.single){
6217             h = createSingle(h, el, ename, fn);
6218         }
6219         if(o.buffer){
6220             h = createBuffered(h, o);
6221         }
6222         fn._handlers = fn._handlers || [];
6223         
6224         
6225         fn._handlers.push([Roo.id(el), ename, h]);
6226         
6227         
6228          
6229         E.on(el, ename, h);
6230         if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery
6231             el.addEventListener("DOMMouseScroll", h, false);
6232             E.on(window, 'unload', function(){
6233                 el.removeEventListener("DOMMouseScroll", h, false);
6234             });
6235         }
6236         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6237             Roo.EventManager.stoppedMouseDownEvent.addListener(h);
6238         }
6239         return h;
6240     };
6241
6242     var stopListening = function(el, ename, fn){
6243         var id = Roo.id(el), hds = fn._handlers, hd = fn;
6244         if(hds){
6245             for(var i = 0, len = hds.length; i < len; i++){
6246                 var h = hds[i];
6247                 if(h[0] == id && h[1] == ename){
6248                     hd = h[2];
6249                     hds.splice(i, 1);
6250                     break;
6251                 }
6252             }
6253         }
6254         E.un(el, ename, hd);
6255         el = Roo.getDom(el);
6256         if(ename == "mousewheel" && el.addEventListener){
6257             el.removeEventListener("DOMMouseScroll", hd, false);
6258         }
6259         if(ename == "mousedown" && el == document){ // fix stopped mousedowns on the document
6260             Roo.EventManager.stoppedMouseDownEvent.removeListener(hd);
6261         }
6262     };
6263
6264     var propRe = /^(?:scope|delay|buffer|single|stopEvent|preventDefault|stopPropagation|normalized|args|delegate)$/;
6265     
6266     var pub = {
6267         
6268         
6269         /** 
6270          * Fix for doc tools
6271          * @scope Roo.EventManager
6272          */
6273         
6274         
6275         /** 
6276          * This is no longer needed and is deprecated. Places a simple wrapper around an event handler to override the browser event
6277          * object with a Roo.EventObject
6278          * @param {Function} fn        The method the event invokes
6279          * @param {Object}   scope    An object that becomes the scope of the handler
6280          * @param {boolean}  override If true, the obj passed in becomes
6281          *                             the execution scope of the listener
6282          * @return {Function} The wrapped function
6283          * @deprecated
6284          */
6285         wrap : function(fn, scope, override){
6286             return function(e){
6287                 Roo.EventObject.setEvent(e);
6288                 fn.call(override ? scope || window : window, Roo.EventObject, scope);
6289             };
6290         },
6291         
6292         /**
6293      * Appends an event handler to an element (shorthand for addListener)
6294      * @param {String/HTMLElement}   element        The html element or id to assign the
6295      * @param {String}   eventName The type of event to listen for
6296      * @param {Function} handler The method the event invokes
6297      * @param {Object}   scope (optional) The scope in which to execute the handler
6298      * function. The handler function's "this" context.
6299      * @param {Object}   options (optional) An object containing handler configuration
6300      * properties. This may contain any of the following properties:<ul>
6301      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6302      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6303      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6304      * <li>preventDefault {Boolean} True to prevent the default action</li>
6305      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6306      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6307      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6308      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6309      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6310      * by the specified number of milliseconds. If the event fires again within that time, the original
6311      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6312      * </ul><br>
6313      * <p>
6314      * <b>Combining Options</b><br>
6315      * Using the options argument, it is possible to combine different types of listeners:<br>
6316      * <br>
6317      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6318      * Code:<pre><code>
6319 el.on('click', this.onClick, this, {
6320     single: true,
6321     delay: 100,
6322     stopEvent : true,
6323     forumId: 4
6324 });</code></pre>
6325      * <p>
6326      * <b>Attaching multiple handlers in 1 call</b><br>
6327       * The method also allows for a single argument to be passed which is a config object containing properties
6328      * which specify multiple handlers.
6329      * <p>
6330      * Code:<pre><code>
6331 el.on({
6332     'click' : {
6333         fn: this.onClick
6334         scope: this,
6335         delay: 100
6336     },
6337     'mouseover' : {
6338         fn: this.onMouseOver
6339         scope: this
6340     },
6341     'mouseout' : {
6342         fn: this.onMouseOut
6343         scope: this
6344     }
6345 });</code></pre>
6346      * <p>
6347      * Or a shorthand syntax:<br>
6348      * Code:<pre><code>
6349 el.on({
6350     'click' : this.onClick,
6351     'mouseover' : this.onMouseOver,
6352     'mouseout' : this.onMouseOut
6353     scope: this
6354 });</code></pre>
6355      */
6356         addListener : function(element, eventName, fn, scope, options){
6357             if(typeof eventName == "object"){
6358                 var o = eventName;
6359                 for(var e in o){
6360                     if(propRe.test(e)){
6361                         continue;
6362                     }
6363                     if(typeof o[e] == "function"){
6364                         // shared options
6365                         listen(element, e, o, o[e], o.scope);
6366                     }else{
6367                         // individual options
6368                         listen(element, e, o[e]);
6369                     }
6370                 }
6371                 return;
6372             }
6373             return listen(element, eventName, options, fn, scope);
6374         },
6375         
6376         /**
6377          * Removes an event handler
6378          *
6379          * @param {String/HTMLElement}   element        The id or html element to remove the 
6380          *                             event from
6381          * @param {String}   eventName     The type of event
6382          * @param {Function} fn
6383          * @return {Boolean} True if a listener was actually removed
6384          */
6385         removeListener : function(element, eventName, fn){
6386             return stopListening(element, eventName, fn);
6387         },
6388         
6389         /**
6390          * Fires when the document is ready (before onload and before images are loaded). Can be 
6391          * accessed shorthanded Roo.onReady().
6392          * @param {Function} fn        The method the event invokes
6393          * @param {Object}   scope    An  object that becomes the scope of the handler
6394          * @param {boolean}  options
6395          */
6396         onDocumentReady : function(fn, scope, options){
6397             if(docReadyState){ // if it already fired
6398                 docReadyEvent.addListener(fn, scope, options);
6399                 docReadyEvent.fire();
6400                 docReadyEvent.clearListeners();
6401                 return;
6402             }
6403             if(!docReadyEvent){
6404                 initDocReady();
6405             }
6406             docReadyEvent.addListener(fn, scope, options);
6407         },
6408         
6409         /**
6410          * Fires when the window is resized and provides resize event buffering (50 milliseconds), passes new viewport width and height to handlers.
6411          * @param {Function} fn        The method the event invokes
6412          * @param {Object}   scope    An object that becomes the scope of the handler
6413          * @param {boolean}  options
6414          */
6415         onWindowResize : function(fn, scope, options){
6416             if(!resizeEvent){
6417                 resizeEvent = new Roo.util.Event();
6418                 resizeTask = new Roo.util.DelayedTask(function(){
6419                     resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6420                 });
6421                 E.on(window, "resize", function(){
6422                     if(Roo.isIE){
6423                         resizeTask.delay(50);
6424                     }else{
6425                         resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6426                     }
6427                 });
6428             }
6429             resizeEvent.addListener(fn, scope, options);
6430         },
6431
6432         /**
6433          * Fires when the user changes the active text size. Handler gets called with 2 params, the old size and the new size.
6434          * @param {Function} fn        The method the event invokes
6435          * @param {Object}   scope    An object that becomes the scope of the handler
6436          * @param {boolean}  options
6437          */
6438         onTextResize : function(fn, scope, options){
6439             if(!textEvent){
6440                 textEvent = new Roo.util.Event();
6441                 var textEl = new Roo.Element(document.createElement('div'));
6442                 textEl.dom.className = 'x-text-resize';
6443                 textEl.dom.innerHTML = 'X';
6444                 textEl.appendTo(document.body);
6445                 textSize = textEl.dom.offsetHeight;
6446                 setInterval(function(){
6447                     if(textEl.dom.offsetHeight != textSize){
6448                         textEvent.fire(textSize, textSize = textEl.dom.offsetHeight);
6449                     }
6450                 }, this.textResizeInterval);
6451             }
6452             textEvent.addListener(fn, scope, options);
6453         },
6454
6455         /**
6456          * Removes the passed window resize listener.
6457          * @param {Function} fn        The method the event invokes
6458          * @param {Object}   scope    The scope of handler
6459          */
6460         removeResizeListener : function(fn, scope){
6461             if(resizeEvent){
6462                 resizeEvent.removeListener(fn, scope);
6463             }
6464         },
6465
6466         // private
6467         fireResize : function(){
6468             if(resizeEvent){
6469                 resizeEvent.fire(D.getViewWidth(), D.getViewHeight());
6470             }   
6471         },
6472         /**
6473          * Url used for onDocumentReady with using SSL (defaults to Roo.SSL_SECURE_URL)
6474          */
6475         ieDeferSrc : false,
6476         /**
6477          * The frequency, in milliseconds, to check for text resize events (defaults to 50)
6478          */
6479         textResizeInterval : 50
6480     };
6481     
6482     /**
6483      * Fix for doc tools
6484      * @scopeAlias pub=Roo.EventManager
6485      */
6486     
6487      /**
6488      * Appends an event handler to an element (shorthand for addListener)
6489      * @param {String/HTMLElement}   element        The html element or id to assign the
6490      * @param {String}   eventName The type of event to listen for
6491      * @param {Function} handler The method the event invokes
6492      * @param {Object}   scope (optional) The scope in which to execute the handler
6493      * function. The handler function's "this" context.
6494      * @param {Object}   options (optional) An object containing handler configuration
6495      * properties. This may contain any of the following properties:<ul>
6496      * <li>scope {Object} The scope in which to execute the handler function. The handler function's "this" context.</li>
6497      * <li>delegate {String} A simple selector to filter the target or look for a descendant of the target</li>
6498      * <li>stopEvent {Boolean} True to stop the event. That is stop propagation, and prevent the default action.</li>
6499      * <li>preventDefault {Boolean} True to prevent the default action</li>
6500      * <li>stopPropagation {Boolean} True to prevent event propagation</li>
6501      * <li>normalized {Boolean} False to pass a browser event to the handler function instead of an Roo.EventObject</li>
6502      * <li>delay {Number} The number of milliseconds to delay the invocation of the handler after te event fires.</li>
6503      * <li>single {Boolean} True to add a handler to handle just the next firing of the event, and then remove itself.</li>
6504      * <li>buffer {Number} Causes the handler to be scheduled to run in an {@link Roo.util.DelayedTask} delayed
6505      * by the specified number of milliseconds. If the event fires again within that time, the original
6506      * handler is <em>not</em> invoked, but the new handler is scheduled in its place.</li>
6507      * </ul><br>
6508      * <p>
6509      * <b>Combining Options</b><br>
6510      * Using the options argument, it is possible to combine different types of listeners:<br>
6511      * <br>
6512      * A normalized, delayed, one-time listener that auto stops the event and passes a custom argument (forumId)<div style="margin: 5px 20px 20px;">
6513      * Code:<pre><code>
6514 el.on('click', this.onClick, this, {
6515     single: true,
6516     delay: 100,
6517     stopEvent : true,
6518     forumId: 4
6519 });</code></pre>
6520      * <p>
6521      * <b>Attaching multiple handlers in 1 call</b><br>
6522       * The method also allows for a single argument to be passed which is a config object containing properties
6523      * which specify multiple handlers.
6524      * <p>
6525      * Code:<pre><code>
6526 el.on({
6527     'click' : {
6528         fn: this.onClick
6529         scope: this,
6530         delay: 100
6531     },
6532     'mouseover' : {
6533         fn: this.onMouseOver
6534         scope: this
6535     },
6536     'mouseout' : {
6537         fn: this.onMouseOut
6538         scope: this
6539     }
6540 });</code></pre>
6541      * <p>
6542      * Or a shorthand syntax:<br>
6543      * Code:<pre><code>
6544 el.on({
6545     'click' : this.onClick,
6546     'mouseover' : this.onMouseOver,
6547     'mouseout' : this.onMouseOut
6548     scope: this
6549 });</code></pre>
6550      */
6551     pub.on = pub.addListener;
6552     pub.un = pub.removeListener;
6553
6554     pub.stoppedMouseDownEvent = new Roo.util.Event();
6555     return pub;
6556 }();
6557 /**
6558   * Fires when the document is ready (before onload and before images are loaded).  Shorthand of {@link Roo.EventManager#onDocumentReady}.
6559   * @param {Function} fn        The method the event invokes
6560   * @param {Object}   scope    An  object that becomes the scope of the handler
6561   * @param {boolean}  override If true, the obj passed in becomes
6562   *                             the execution scope of the listener
6563   * @member Roo
6564   * @method onReady
6565  */
6566 Roo.onReady = Roo.EventManager.onDocumentReady;
6567
6568 Roo.onReady(function(){
6569     var bd = Roo.get(document.body);
6570     if(!bd){ return; }
6571
6572     var cls = [
6573             Roo.isIE ? "roo-ie"
6574             : Roo.isGecko ? "roo-gecko"
6575             : Roo.isOpera ? "roo-opera"
6576             : Roo.isSafari ? "roo-safari" : ""];
6577
6578     if(Roo.isMac){
6579         cls.push("roo-mac");
6580     }
6581     if(Roo.isLinux){
6582         cls.push("roo-linux");
6583     }
6584     if(Roo.isIOS){
6585         cls.push("roo-ios");
6586     }
6587     if(Roo.isTouch){
6588         cls.push("roo-touch");
6589     }
6590     if(Roo.isBorderBox){
6591         cls.push('roo-border-box');
6592     }
6593     if(Roo.isStrict){ // add to the parent to allow for selectors like ".ext-strict .ext-ie"
6594         var p = bd.dom.parentNode;
6595         if(p){
6596             p.className += ' roo-strict';
6597         }
6598     }
6599     bd.addClass(cls.join(' '));
6600 });
6601
6602 /**
6603  * @class Roo.EventObject
6604  * EventObject exposes the Yahoo! UI Event functionality directly on the object
6605  * passed to your event handler. It exists mostly for convenience. It also fixes the annoying null checks automatically to cleanup your code 
6606  * Example:
6607  * <pre><code>
6608  function handleClick(e){ // e is not a standard event object, it is a Roo.EventObject
6609     e.preventDefault();
6610     var target = e.getTarget();
6611     ...
6612  }
6613  var myDiv = Roo.get("myDiv");
6614  myDiv.on("click", handleClick);
6615  //or
6616  Roo.EventManager.on("myDiv", 'click', handleClick);
6617  Roo.EventManager.addListener("myDiv", 'click', handleClick);
6618  </code></pre>
6619  * @singleton
6620  */
6621 Roo.EventObject = function(){
6622     
6623     var E = Roo.lib.Event;
6624     
6625     // safari keypress events for special keys return bad keycodes
6626     var safariKeys = {
6627         63234 : 37, // left
6628         63235 : 39, // right
6629         63232 : 38, // up
6630         63233 : 40, // down
6631         63276 : 33, // page up
6632         63277 : 34, // page down
6633         63272 : 46, // delete
6634         63273 : 36, // home
6635         63275 : 35  // end
6636     };
6637
6638     // normalize button clicks
6639     var btnMap = Roo.isIE ? {1:0,4:1,2:2} :
6640                 (Roo.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2});
6641
6642     Roo.EventObjectImpl = function(e){
6643         if(e){
6644             this.setEvent(e.browserEvent || e);
6645         }
6646     };
6647     Roo.EventObjectImpl.prototype = {
6648         /**
6649          * Used to fix doc tools.
6650          * @scope Roo.EventObject.prototype
6651          */
6652             
6653
6654         
6655         
6656         /** The normal browser event */
6657         browserEvent : null,
6658         /** The button pressed in a mouse event */
6659         button : -1,
6660         /** True if the shift key was down during the event */
6661         shiftKey : false,
6662         /** True if the control key was down during the event */
6663         ctrlKey : false,
6664         /** True if the alt key was down during the event */
6665         altKey : false,
6666
6667         /** Key constant 
6668         * @type Number */
6669         BACKSPACE : 8,
6670         /** Key constant 
6671         * @type Number */
6672         TAB : 9,
6673         /** Key constant 
6674         * @type Number */
6675         RETURN : 13,
6676         /** Key constant 
6677         * @type Number */
6678         ENTER : 13,
6679         /** Key constant 
6680         * @type Number */
6681         SHIFT : 16,
6682         /** Key constant 
6683         * @type Number */
6684         CONTROL : 17,
6685         /** Key constant 
6686         * @type Number */
6687         ESC : 27,
6688         /** Key constant 
6689         * @type Number */
6690         SPACE : 32,
6691         /** Key constant 
6692         * @type Number */
6693         PAGEUP : 33,
6694         /** Key constant 
6695         * @type Number */
6696         PAGEDOWN : 34,
6697         /** Key constant 
6698         * @type Number */
6699         END : 35,
6700         /** Key constant 
6701         * @type Number */
6702         HOME : 36,
6703         /** Key constant 
6704         * @type Number */
6705         LEFT : 37,
6706         /** Key constant 
6707         * @type Number */
6708         UP : 38,
6709         /** Key constant 
6710         * @type Number */
6711         RIGHT : 39,
6712         /** Key constant 
6713         * @type Number */
6714         DOWN : 40,
6715         /** Key constant 
6716         * @type Number */
6717         DELETE : 46,
6718         /** Key constant 
6719         * @type Number */
6720         F5 : 116,
6721
6722            /** @private */
6723         setEvent : function(e){
6724             if(e == this || (e && e.browserEvent)){ // already wrapped
6725                 return e;
6726             }
6727             this.browserEvent = e;
6728             if(e){
6729                 // normalize buttons
6730                 this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);
6731                 if(e.type == 'click' && this.button == -1){
6732                     this.button = 0;
6733                 }
6734                 this.type = e.type;
6735                 this.shiftKey = e.shiftKey;
6736                 // mac metaKey behaves like ctrlKey
6737                 this.ctrlKey = e.ctrlKey || e.metaKey;
6738                 this.altKey = e.altKey;
6739                 // in getKey these will be normalized for the mac
6740                 this.keyCode = e.keyCode;
6741                 // keyup warnings on firefox.
6742                 this.charCode = (e.type == 'keyup' || e.type == 'keydown') ? 0 : e.charCode;
6743                 // cache the target for the delayed and or buffered events
6744                 this.target = E.getTarget(e);
6745                 // same for XY
6746                 this.xy = E.getXY(e);
6747             }else{
6748                 this.button = -1;
6749                 this.shiftKey = false;
6750                 this.ctrlKey = false;
6751                 this.altKey = false;
6752                 this.keyCode = 0;
6753                 this.charCode =0;
6754                 this.target = null;
6755                 this.xy = [0, 0];
6756             }
6757             return this;
6758         },
6759
6760         /**
6761          * Stop the event (preventDefault and stopPropagation)
6762          */
6763         stopEvent : function(){
6764             if(this.browserEvent){
6765                 if(this.browserEvent.type == 'mousedown'){
6766                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6767                 }
6768                 E.stopEvent(this.browserEvent);
6769             }
6770         },
6771
6772         /**
6773          * Prevents the browsers default handling of the event.
6774          */
6775         preventDefault : function(){
6776             if(this.browserEvent){
6777                 E.preventDefault(this.browserEvent);
6778             }
6779         },
6780
6781         /** @private */
6782         isNavKeyPress : function(){
6783             var k = this.keyCode;
6784             k = Roo.isSafari ? (safariKeys[k] || k) : k;
6785             return (k >= 33 && k <= 40) || k == this.RETURN || k == this.TAB || k == this.ESC;
6786         },
6787
6788         isSpecialKey : function(){
6789             var k = this.keyCode;
6790             return (this.type == 'keypress' && this.ctrlKey) || k == 9 || k == 13  || k == 40 || k == 27 ||
6791             (k == 16) || (k == 17) ||
6792             (k >= 18 && k <= 20) ||
6793             (k >= 33 && k <= 35) ||
6794             (k >= 36 && k <= 39) ||
6795             (k >= 44 && k <= 45);
6796         },
6797         /**
6798          * Cancels bubbling of the event.
6799          */
6800         stopPropagation : function(){
6801             if(this.browserEvent){
6802                 if(this.type == 'mousedown'){
6803                     Roo.EventManager.stoppedMouseDownEvent.fire(this);
6804                 }
6805                 E.stopPropagation(this.browserEvent);
6806             }
6807         },
6808
6809         /**
6810          * Gets the key code for the event.
6811          * @return {Number}
6812          */
6813         getCharCode : function(){
6814             return this.charCode || this.keyCode;
6815         },
6816
6817         /**
6818          * Returns a normalized keyCode for the event.
6819          * @return {Number} The key code
6820          */
6821         getKey : function(){
6822             var k = this.keyCode || this.charCode;
6823             return Roo.isSafari ? (safariKeys[k] || k) : k;
6824         },
6825
6826         /**
6827          * Gets the x coordinate of the event.
6828          * @return {Number}
6829          */
6830         getPageX : function(){
6831             return this.xy[0];
6832         },
6833
6834         /**
6835          * Gets the y coordinate of the event.
6836          * @return {Number}
6837          */
6838         getPageY : function(){
6839             return this.xy[1];
6840         },
6841
6842         /**
6843          * Gets the time of the event.
6844          * @return {Number}
6845          */
6846         getTime : function(){
6847             if(this.browserEvent){
6848                 return E.getTime(this.browserEvent);
6849             }
6850             return null;
6851         },
6852
6853         /**
6854          * Gets the page coordinates of the event.
6855          * @return {Array} The xy values like [x, y]
6856          */
6857         getXY : function(){
6858             return this.xy;
6859         },
6860
6861         /**
6862          * Gets the target for the event.
6863          * @param {String} selector (optional) A simple selector to filter the target or look for an ancestor of the target
6864          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
6865                 search as a number or element (defaults to 10 || document.body)
6866          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
6867          * @return {HTMLelement}
6868          */
6869         getTarget : function(selector, maxDepth, returnEl){
6870             return selector ? Roo.fly(this.target).findParent(selector, maxDepth, returnEl) : this.target;
6871         },
6872         /**
6873          * Gets the related target.
6874          * @return {HTMLElement}
6875          */
6876         getRelatedTarget : function(){
6877             if(this.browserEvent){
6878                 return E.getRelatedTarget(this.browserEvent);
6879             }
6880             return null;
6881         },
6882
6883         /**
6884          * Normalizes mouse wheel delta across browsers
6885          * @return {Number} The delta
6886          */
6887         getWheelDelta : function(){
6888             var e = this.browserEvent;
6889             var delta = 0;
6890             if(e.wheelDelta){ /* IE/Opera. */
6891                 delta = e.wheelDelta/120;
6892             }else if(e.detail){ /* Mozilla case. */
6893                 delta = -e.detail/3;
6894             }
6895             return delta;
6896         },
6897
6898         /**
6899          * Returns true if the control, meta, shift or alt key was pressed during this event.
6900          * @return {Boolean}
6901          */
6902         hasModifier : function(){
6903             return !!((this.ctrlKey || this.altKey) || this.shiftKey);
6904         },
6905
6906         /**
6907          * Returns true if the target of this event equals el or is a child of el
6908          * @param {String/HTMLElement/Element} el
6909          * @param {Boolean} related (optional) true to test if the related target is within el instead of the target
6910          * @return {Boolean}
6911          */
6912         within : function(el, related){
6913             var t = this[related ? "getRelatedTarget" : "getTarget"]();
6914             return t && Roo.fly(el).contains(t);
6915         },
6916
6917         getPoint : function(){
6918             return new Roo.lib.Point(this.xy[0], this.xy[1]);
6919         }
6920     };
6921
6922     return new Roo.EventObjectImpl();
6923 }();
6924             
6925     /*
6926  * Based on:
6927  * Ext JS Library 1.1.1
6928  * Copyright(c) 2006-2007, Ext JS, LLC.
6929  *
6930  * Originally Released Under LGPL - original licence link has changed is not relivant.
6931  *
6932  * Fork - LGPL
6933  * <script type="text/javascript">
6934  */
6935
6936  
6937 // was in Composite Element!??!?!
6938  
6939 (function(){
6940     var D = Roo.lib.Dom;
6941     var E = Roo.lib.Event;
6942     var A = Roo.lib.Anim;
6943
6944     // local style camelizing for speed
6945     var propCache = {};
6946     var camelRe = /(-[a-z])/gi;
6947     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
6948     var view = document.defaultView;
6949
6950 /**
6951  * @class Roo.Element
6952  * Represents an Element in the DOM.<br><br>
6953  * Usage:<br>
6954 <pre><code>
6955 var el = Roo.get("my-div");
6956
6957 // or with getEl
6958 var el = getEl("my-div");
6959
6960 // or with a DOM element
6961 var el = Roo.get(myDivElement);
6962 </code></pre>
6963  * Using Roo.get() or getEl() instead of calling the constructor directly ensures you get the same object
6964  * each call instead of constructing a new one.<br><br>
6965  * <b>Animations</b><br />
6966  * Many of the functions for manipulating an element have an optional "animate" parameter. The animate parameter
6967  * should either be a boolean (true) or an object literal with animation options. The animation options are:
6968 <pre>
6969 Option    Default   Description
6970 --------- --------  ---------------------------------------------
6971 duration  .35       The duration of the animation in seconds
6972 easing    easeOut   The YUI easing method
6973 callback  none      A function to execute when the anim completes
6974 scope     this      The scope (this) of the callback function
6975 </pre>
6976 * Also, the Anim object being used for the animation will be set on your options object as "anim", which allows you to stop or
6977 * manipulate the animation. Here's an example:
6978 <pre><code>
6979 var el = Roo.get("my-div");
6980
6981 // no animation
6982 el.setWidth(100);
6983
6984 // default animation
6985 el.setWidth(100, true);
6986
6987 // animation with some options set
6988 el.setWidth(100, {
6989     duration: 1,
6990     callback: this.foo,
6991     scope: this
6992 });
6993
6994 // using the "anim" property to get the Anim object
6995 var opt = {
6996     duration: 1,
6997     callback: this.foo,
6998     scope: this
6999 };
7000 el.setWidth(100, opt);
7001 ...
7002 if(opt.anim.isAnimated()){
7003     opt.anim.stop();
7004 }
7005 </code></pre>
7006 * <b> Composite (Collections of) Elements</b><br />
7007  * For working with collections of Elements, see <a href="Roo.CompositeElement.html">Roo.CompositeElement</a>
7008  * @constructor Create a new Element directly.
7009  * @param {String/HTMLElement} element
7010  * @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).
7011  */
7012     Roo.Element = function(element, forceNew){
7013         var dom = typeof element == "string" ?
7014                 document.getElementById(element) : element;
7015         if(!dom){ // invalid id/element
7016             return null;
7017         }
7018         var id = dom.id;
7019         if(forceNew !== true && id && Roo.Element.cache[id]){ // element object already exists
7020             return Roo.Element.cache[id];
7021         }
7022
7023         /**
7024          * The DOM element
7025          * @type HTMLElement
7026          */
7027         this.dom = dom;
7028
7029         /**
7030          * The DOM element ID
7031          * @type String
7032          */
7033         this.id = id || Roo.id(dom);
7034     };
7035
7036     var El = Roo.Element;
7037
7038     El.prototype = {
7039         /**
7040          * The element's default display mode  (defaults to "")
7041          * @type String
7042          */
7043         originalDisplay : "",
7044
7045         visibilityMode : 1,
7046         /**
7047          * The default unit to append to CSS values where a unit isn't provided (defaults to px).
7048          * @type String
7049          */
7050         defaultUnit : "px",
7051         
7052         /**
7053          * Sets the element's visibility mode. When setVisible() is called it
7054          * will use this to determine whether to set the visibility or the display property.
7055          * @param visMode Element.VISIBILITY or Element.DISPLAY
7056          * @return {Roo.Element} this
7057          */
7058         setVisibilityMode : function(visMode){
7059             this.visibilityMode = visMode;
7060             return this;
7061         },
7062         /**
7063          * Convenience method for setVisibilityMode(Element.DISPLAY)
7064          * @param {String} display (optional) What to set display to when visible
7065          * @return {Roo.Element} this
7066          */
7067         enableDisplayMode : function(display){
7068             this.setVisibilityMode(El.DISPLAY);
7069             if(typeof display != "undefined") this.originalDisplay = display;
7070             return this;
7071         },
7072
7073         /**
7074          * 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)
7075          * @param {String} selector The simple selector to test
7076          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7077                 search as a number or element (defaults to 10 || document.body)
7078          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7079          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7080          */
7081         findParent : function(simpleSelector, maxDepth, returnEl){
7082             var p = this.dom, b = document.body, depth = 0, dq = Roo.DomQuery, stopEl;
7083             maxDepth = maxDepth || 50;
7084             if(typeof maxDepth != "number"){
7085                 stopEl = Roo.getDom(maxDepth);
7086                 maxDepth = 10;
7087             }
7088             while(p && p.nodeType == 1 && depth < maxDepth && p != b && p != stopEl){
7089                 if(dq.is(p, simpleSelector)){
7090                     return returnEl ? Roo.get(p) : p;
7091                 }
7092                 depth++;
7093                 p = p.parentNode;
7094             }
7095             return null;
7096         },
7097
7098
7099         /**
7100          * Looks at parent nodes for a match of the passed simple selector (e.g. div.some-class or span:first-child)
7101          * @param {String} selector The simple selector to test
7102          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7103                 search as a number or element (defaults to 10 || document.body)
7104          * @param {Boolean} returnEl (optional) True to return a Roo.Element object instead of DOM node
7105          * @return {HTMLElement} The matching DOM node (or null if no match was found)
7106          */
7107         findParentNode : function(simpleSelector, maxDepth, returnEl){
7108             var p = Roo.fly(this.dom.parentNode, '_internal');
7109             return p ? p.findParent(simpleSelector, maxDepth, returnEl) : null;
7110         },
7111
7112         /**
7113          * Walks up the dom looking for a parent node that matches the passed simple selector (e.g. div.some-class or span:first-child).
7114          * This is a shortcut for findParentNode() that always returns an Roo.Element.
7115          * @param {String} selector The simple selector to test
7116          * @param {Number/String/HTMLElement/Element} maxDepth (optional) The max depth to
7117                 search as a number or element (defaults to 10 || document.body)
7118          * @return {Roo.Element} The matching DOM node (or null if no match was found)
7119          */
7120         up : function(simpleSelector, maxDepth){
7121             return this.findParentNode(simpleSelector, maxDepth, true);
7122         },
7123
7124
7125
7126         /**
7127          * Returns true if this element matches the passed simple selector (e.g. div.some-class or span:first-child)
7128          * @param {String} selector The simple selector to test
7129          * @return {Boolean} True if this element matches the selector, else false
7130          */
7131         is : function(simpleSelector){
7132             return Roo.DomQuery.is(this.dom, simpleSelector);
7133         },
7134
7135         /**
7136          * Perform animation on this element.
7137          * @param {Object} args The YUI animation control args
7138          * @param {Float} duration (optional) How long the animation lasts in seconds (defaults to .35)
7139          * @param {Function} onComplete (optional) Function to call when animation completes
7140          * @param {String} easing (optional) Easing method to use (defaults to 'easeOut')
7141          * @param {String} animType (optional) 'run' is the default. Can also be 'color', 'motion', or 'scroll'
7142          * @return {Roo.Element} this
7143          */
7144         animate : function(args, duration, onComplete, easing, animType){
7145             this.anim(args, {duration: duration, callback: onComplete, easing: easing}, animType);
7146             return this;
7147         },
7148
7149         /*
7150          * @private Internal animation call
7151          */
7152         anim : function(args, opt, animType, defaultDur, defaultEase, cb){
7153             animType = animType || 'run';
7154             opt = opt || {};
7155             var anim = Roo.lib.Anim[animType](
7156                 this.dom, args,
7157                 (opt.duration || defaultDur) || .35,
7158                 (opt.easing || defaultEase) || 'easeOut',
7159                 function(){
7160                     Roo.callback(cb, this);
7161                     Roo.callback(opt.callback, opt.scope || this, [this, opt]);
7162                 },
7163                 this
7164             );
7165             opt.anim = anim;
7166             return anim;
7167         },
7168
7169         // private legacy anim prep
7170         preanim : function(a, i){
7171             return !a[i] ? false : (typeof a[i] == "object" ? a[i]: {duration: a[i+1], callback: a[i+2], easing: a[i+3]});
7172         },
7173
7174         /**
7175          * Removes worthless text nodes
7176          * @param {Boolean} forceReclean (optional) By default the element
7177          * keeps track if it has been cleaned already so
7178          * you can call this over and over. However, if you update the element and
7179          * need to force a reclean, you can pass true.
7180          */
7181         clean : function(forceReclean){
7182             if(this.isCleaned && forceReclean !== true){
7183                 return this;
7184             }
7185             var ns = /\S/;
7186             var d = this.dom, n = d.firstChild, ni = -1;
7187             while(n){
7188                 var nx = n.nextSibling;
7189                 if(n.nodeType == 3 && !ns.test(n.nodeValue)){
7190                     d.removeChild(n);
7191                 }else{
7192                     n.nodeIndex = ++ni;
7193                 }
7194                 n = nx;
7195             }
7196             this.isCleaned = true;
7197             return this;
7198         },
7199
7200         // private
7201         calcOffsetsTo : function(el){
7202             el = Roo.get(el);
7203             var d = el.dom;
7204             var restorePos = false;
7205             if(el.getStyle('position') == 'static'){
7206                 el.position('relative');
7207                 restorePos = true;
7208             }
7209             var x = 0, y =0;
7210             var op = this.dom;
7211             while(op && op != d && op.tagName != 'HTML'){
7212                 x+= op.offsetLeft;
7213                 y+= op.offsetTop;
7214                 op = op.offsetParent;
7215             }
7216             if(restorePos){
7217                 el.position('static');
7218             }
7219             return [x, y];
7220         },
7221
7222         /**
7223          * Scrolls this element into view within the passed container.
7224          * @param {String/HTMLElement/Element} container (optional) The container element to scroll (defaults to document.body)
7225          * @param {Boolean} hscroll (optional) False to disable horizontal scroll (defaults to true)
7226          * @return {Roo.Element} this
7227          */
7228         scrollIntoView : function(container, hscroll){
7229             var c = Roo.getDom(container) || document.body;
7230             var el = this.dom;
7231
7232             var o = this.calcOffsetsTo(c),
7233                 l = o[0],
7234                 t = o[1],
7235                 b = t+el.offsetHeight,
7236                 r = l+el.offsetWidth;
7237
7238             var ch = c.clientHeight;
7239             var ct = parseInt(c.scrollTop, 10);
7240             var cl = parseInt(c.scrollLeft, 10);
7241             var cb = ct + ch;
7242             var cr = cl + c.clientWidth;
7243
7244             if(t < ct){
7245                 c.scrollTop = t;
7246             }else if(b > cb){
7247                 c.scrollTop = b-ch;
7248             }
7249
7250             if(hscroll !== false){
7251                 if(l < cl){
7252                     c.scrollLeft = l;
7253                 }else if(r > cr){
7254                     c.scrollLeft = r-c.clientWidth;
7255                 }
7256             }
7257             return this;
7258         },
7259
7260         // private
7261         scrollChildIntoView : function(child, hscroll){
7262             Roo.fly(child, '_scrollChildIntoView').scrollIntoView(this, hscroll);
7263         },
7264
7265         /**
7266          * Measures the element's content height and updates height to match. Note: this function uses setTimeout so
7267          * the new height may not be available immediately.
7268          * @param {Boolean} animate (optional) Animate the transition (defaults to false)
7269          * @param {Float} duration (optional) Length of the animation in seconds (defaults to .35)
7270          * @param {Function} onComplete (optional) Function to call when animation completes
7271          * @param {String} easing (optional) Easing method to use (defaults to easeOut)
7272          * @return {Roo.Element} this
7273          */
7274         autoHeight : function(animate, duration, onComplete, easing){
7275             var oldHeight = this.getHeight();
7276             this.clip();
7277             this.setHeight(1); // force clipping
7278             setTimeout(function(){
7279                 var height = parseInt(this.dom.scrollHeight, 10); // parseInt for Safari
7280                 if(!animate){
7281                     this.setHeight(height);
7282                     this.unclip();
7283                     if(typeof onComplete == "function"){
7284                         onComplete();
7285                     }
7286                 }else{
7287                     this.setHeight(oldHeight); // restore original height
7288                     this.setHeight(height, animate, duration, function(){
7289                         this.unclip();
7290                         if(typeof onComplete == "function") onComplete();
7291                     }.createDelegate(this), easing);
7292                 }
7293             }.createDelegate(this), 0);
7294             return this;
7295         },
7296
7297         /**
7298          * Returns true if this element is an ancestor of the passed element
7299          * @param {HTMLElement/String} el The element to check
7300          * @return {Boolean} True if this element is an ancestor of el, else false
7301          */
7302         contains : function(el){
7303             if(!el){return false;}
7304             return D.isAncestor(this.dom, el.dom ? el.dom : el);
7305         },
7306
7307         /**
7308          * Checks whether the element is currently visible using both visibility and display properties.
7309          * @param {Boolean} deep (optional) True to walk the dom and see if parent elements are hidden (defaults to false)
7310          * @return {Boolean} True if the element is currently visible, else false
7311          */
7312         isVisible : function(deep) {
7313             var vis = !(this.getStyle("visibility") == "hidden" || this.getStyle("display") == "none");
7314             if(deep !== true || !vis){
7315                 return vis;
7316             }
7317             var p = this.dom.parentNode;
7318             while(p && p.tagName.toLowerCase() != "body"){
7319                 if(!Roo.fly(p, '_isVisible').isVisible()){
7320                     return false;
7321                 }
7322                 p = p.parentNode;
7323             }
7324             return true;
7325         },
7326
7327         /**
7328          * Creates a {@link Roo.CompositeElement} for child nodes based on the passed CSS selector (the selector should not contain an id).
7329          * @param {String} selector The CSS selector
7330          * @param {Boolean} unique (optional) True to create a unique Roo.Element for each child (defaults to false, which creates a single shared flyweight object)
7331          * @return {CompositeElement/CompositeElementLite} The composite element
7332          */
7333         select : function(selector, unique){
7334             return El.select(selector, unique, this.dom);
7335         },
7336
7337         /**
7338          * Selects child nodes based on the passed CSS selector (the selector should not contain an id).
7339          * @param {String} selector The CSS selector
7340          * @return {Array} An array of the matched nodes
7341          */
7342         query : function(selector, unique){
7343             return Roo.DomQuery.select(selector, this.dom);
7344         },
7345
7346         /**
7347          * Selects a single child at any depth below this element based on the passed CSS selector (the selector should not contain an id).
7348          * @param {String} selector The CSS selector
7349          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7350          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7351          */
7352         child : function(selector, returnDom){
7353             var n = Roo.DomQuery.selectNode(selector, this.dom);
7354             return returnDom ? n : Roo.get(n);
7355         },
7356
7357         /**
7358          * Selects a single *direct* child based on the passed CSS selector (the selector should not contain an id).
7359          * @param {String} selector The CSS selector
7360          * @param {Boolean} returnDom (optional) True to return the DOM node instead of Roo.Element (defaults to false)
7361          * @return {HTMLElement/Roo.Element} The child Roo.Element (or DOM node if returnDom = true)
7362          */
7363         down : function(selector, returnDom){
7364             var n = Roo.DomQuery.selectNode(" > " + selector, this.dom);
7365             return returnDom ? n : Roo.get(n);
7366         },
7367
7368         /**
7369          * Initializes a {@link Roo.dd.DD} drag drop object for this element.
7370          * @param {String} group The group the DD object is member of
7371          * @param {Object} config The DD config object
7372          * @param {Object} overrides An object containing methods to override/implement on the DD object
7373          * @return {Roo.dd.DD} The DD object
7374          */
7375         initDD : function(group, config, overrides){
7376             var dd = new Roo.dd.DD(Roo.id(this.dom), group, config);
7377             return Roo.apply(dd, overrides);
7378         },
7379
7380         /**
7381          * Initializes a {@link Roo.dd.DDProxy} object for this element.
7382          * @param {String} group The group the DDProxy object is member of
7383          * @param {Object} config The DDProxy config object
7384          * @param {Object} overrides An object containing methods to override/implement on the DDProxy object
7385          * @return {Roo.dd.DDProxy} The DDProxy object
7386          */
7387         initDDProxy : function(group, config, overrides){
7388             var dd = new Roo.dd.DDProxy(Roo.id(this.dom), group, config);
7389             return Roo.apply(dd, overrides);
7390         },
7391
7392         /**
7393          * Initializes a {@link Roo.dd.DDTarget} object for this element.
7394          * @param {String} group The group the DDTarget object is member of
7395          * @param {Object} config The DDTarget config object
7396          * @param {Object} overrides An object containing methods to override/implement on the DDTarget object
7397          * @return {Roo.dd.DDTarget} The DDTarget object
7398          */
7399         initDDTarget : function(group, config, overrides){
7400             var dd = new Roo.dd.DDTarget(Roo.id(this.dom), group, config);
7401             return Roo.apply(dd, overrides);
7402         },
7403
7404         /**
7405          * Sets the visibility of the element (see details). If the visibilityMode is set to Element.DISPLAY, it will use
7406          * the display property to hide the element, otherwise it uses visibility. The default is to hide and show using the visibility property.
7407          * @param {Boolean} visible Whether the element is visible
7408          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7409          * @return {Roo.Element} this
7410          */
7411          setVisible : function(visible, animate){
7412             if(!animate || !A){
7413                 if(this.visibilityMode == El.DISPLAY){
7414                     this.setDisplayed(visible);
7415                 }else{
7416                     this.fixDisplay();
7417                     this.dom.style.visibility = visible ? "visible" : "hidden";
7418                 }
7419             }else{
7420                 // closure for composites
7421                 var dom = this.dom;
7422                 var visMode = this.visibilityMode;
7423                 if(visible){
7424                     this.setOpacity(.01);
7425                     this.setVisible(true);
7426                 }
7427                 this.anim({opacity: { to: (visible?1:0) }},
7428                       this.preanim(arguments, 1),
7429                       null, .35, 'easeIn', function(){
7430                          if(!visible){
7431                              if(visMode == El.DISPLAY){
7432                                  dom.style.display = "none";
7433                              }else{
7434                                  dom.style.visibility = "hidden";
7435                              }
7436                              Roo.get(dom).setOpacity(1);
7437                          }
7438                      });
7439             }
7440             return this;
7441         },
7442
7443         /**
7444          * Returns true if display is not "none"
7445          * @return {Boolean}
7446          */
7447         isDisplayed : function() {
7448             return this.getStyle("display") != "none";
7449         },
7450
7451         /**
7452          * Toggles the element's visibility or display, depending on visibility mode.
7453          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7454          * @return {Roo.Element} this
7455          */
7456         toggle : function(animate){
7457             this.setVisible(!this.isVisible(), this.preanim(arguments, 0));
7458             return this;
7459         },
7460
7461         /**
7462          * Sets the CSS display property. Uses originalDisplay if the specified value is a boolean true.
7463          * @param {Boolean} value Boolean value to display the element using its default display, or a string to set the display directly
7464          * @return {Roo.Element} this
7465          */
7466         setDisplayed : function(value) {
7467             if(typeof value == "boolean"){
7468                value = value ? this.originalDisplay : "none";
7469             }
7470             this.setStyle("display", value);
7471             return this;
7472         },
7473
7474         /**
7475          * Tries to focus the element. Any exceptions are caught and ignored.
7476          * @return {Roo.Element} this
7477          */
7478         focus : function() {
7479             try{
7480                 this.dom.focus();
7481             }catch(e){}
7482             return this;
7483         },
7484
7485         /**
7486          * Tries to blur the element. Any exceptions are caught and ignored.
7487          * @return {Roo.Element} this
7488          */
7489         blur : function() {
7490             try{
7491                 this.dom.blur();
7492             }catch(e){}
7493             return this;
7494         },
7495
7496         /**
7497          * Adds one or more CSS classes to the element. Duplicate classes are automatically filtered out.
7498          * @param {String/Array} className The CSS class to add, or an array of classes
7499          * @return {Roo.Element} this
7500          */
7501         addClass : function(className){
7502             if(className instanceof Array){
7503                 for(var i = 0, len = className.length; i < len; i++) {
7504                     this.addClass(className[i]);
7505                 }
7506             }else{
7507                 if(className && !this.hasClass(className)){
7508                     this.dom.className = this.dom.className + " " + className;
7509                 }
7510             }
7511             return this;
7512         },
7513
7514         /**
7515          * Adds one or more CSS classes to this element and removes the same class(es) from all siblings.
7516          * @param {String/Array} className The CSS class to add, or an array of classes
7517          * @return {Roo.Element} this
7518          */
7519         radioClass : function(className){
7520             var siblings = this.dom.parentNode.childNodes;
7521             for(var i = 0; i < siblings.length; i++) {
7522                 var s = siblings[i];
7523                 if(s.nodeType == 1){
7524                     Roo.get(s).removeClass(className);
7525                 }
7526             }
7527             this.addClass(className);
7528             return this;
7529         },
7530
7531         /**
7532          * Removes one or more CSS classes from the element.
7533          * @param {String/Array} className The CSS class to remove, or an array of classes
7534          * @return {Roo.Element} this
7535          */
7536         removeClass : function(className){
7537             if(!className || !this.dom.className){
7538                 return this;
7539             }
7540             if(className instanceof Array){
7541                 for(var i = 0, len = className.length; i < len; i++) {
7542                     this.removeClass(className[i]);
7543                 }
7544             }else{
7545                 if(this.hasClass(className)){
7546                     var re = this.classReCache[className];
7547                     if (!re) {
7548                        re = new RegExp('(?:^|\\s+)' + className + '(?:\\s+|$)', "g");
7549                        this.classReCache[className] = re;
7550                     }
7551                     this.dom.className =
7552                         this.dom.className.replace(re, " ");
7553                 }
7554             }
7555             return this;
7556         },
7557
7558         // private
7559         classReCache: {},
7560
7561         /**
7562          * Toggles the specified CSS class on this element (removes it if it already exists, otherwise adds it).
7563          * @param {String} className The CSS class to toggle
7564          * @return {Roo.Element} this
7565          */
7566         toggleClass : function(className){
7567             if(this.hasClass(className)){
7568                 this.removeClass(className);
7569             }else{
7570                 this.addClass(className);
7571             }
7572             return this;
7573         },
7574
7575         /**
7576          * Checks if the specified CSS class exists on this element's DOM node.
7577          * @param {String} className The CSS class to check for
7578          * @return {Boolean} True if the class exists, else false
7579          */
7580         hasClass : function(className){
7581             return className && (' '+this.dom.className+' ').indexOf(' '+className+' ') != -1;
7582         },
7583
7584         /**
7585          * Replaces a CSS class on the element with another.  If the old name does not exist, the new name will simply be added.
7586          * @param {String} oldClassName The CSS class to replace
7587          * @param {String} newClassName The replacement CSS class
7588          * @return {Roo.Element} this
7589          */
7590         replaceClass : function(oldClassName, newClassName){
7591             this.removeClass(oldClassName);
7592             this.addClass(newClassName);
7593             return this;
7594         },
7595
7596         /**
7597          * Returns an object with properties matching the styles requested.
7598          * For example, el.getStyles('color', 'font-size', 'width') might return
7599          * {'color': '#FFFFFF', 'font-size': '13px', 'width': '100px'}.
7600          * @param {String} style1 A style name
7601          * @param {String} style2 A style name
7602          * @param {String} etc.
7603          * @return {Object} The style object
7604          */
7605         getStyles : function(){
7606             var a = arguments, len = a.length, r = {};
7607             for(var i = 0; i < len; i++){
7608                 r[a[i]] = this.getStyle(a[i]);
7609             }
7610             return r;
7611         },
7612
7613         /**
7614          * Normalizes currentStyle and computedStyle. This is not YUI getStyle, it is an optimised version.
7615          * @param {String} property The style property whose value is returned.
7616          * @return {String} The current value of the style property for this element.
7617          */
7618         getStyle : function(){
7619             return view && view.getComputedStyle ?
7620                 function(prop){
7621                     var el = this.dom, v, cs, camel;
7622                     if(prop == 'float'){
7623                         prop = "cssFloat";
7624                     }
7625                     if(el.style && (v = el.style[prop])){
7626                         return v;
7627                     }
7628                     if(cs = view.getComputedStyle(el, "")){
7629                         if(!(camel = propCache[prop])){
7630                             camel = propCache[prop] = prop.replace(camelRe, camelFn);
7631                         }
7632                         return cs[camel];
7633                     }
7634                     return null;
7635                 } :
7636                 function(prop){
7637                     var el = this.dom, v, cs, camel;
7638                     if(prop == 'opacity'){
7639                         if(typeof el.style.filter == 'string'){
7640                             var m = el.style.filter.match(/alpha\(opacity=(.*)\)/i);
7641                             if(m){
7642                                 var fv = parseFloat(m[1]);
7643                                 if(!isNaN(fv)){
7644                                     return fv ? fv / 100 : 0;
7645                                 }
7646                             }
7647                         }
7648                         return 1;
7649                     }else if(prop == 'float'){
7650                         prop = "styleFloat";
7651                     }
7652                     if(!(camel = propCache[prop])){
7653                         camel = propCache[prop] = prop.replace(camelRe, camelFn);
7654                     }
7655                     if(v = el.style[camel]){
7656                         return v;
7657                     }
7658                     if(cs = el.currentStyle){
7659                         return cs[camel];
7660                     }
7661                     return null;
7662                 };
7663         }(),
7664
7665         /**
7666          * Wrapper for setting style properties, also takes single object parameter of multiple styles.
7667          * @param {String/Object} property The style property to be set, or an object of multiple styles.
7668          * @param {String} value (optional) The value to apply to the given property, or null if an object was passed.
7669          * @return {Roo.Element} this
7670          */
7671         setStyle : function(prop, value){
7672             if(typeof prop == "string"){
7673                 
7674                 if (prop == 'float') {
7675                     this.setStyle(Roo.isIE ? 'styleFloat'  : 'cssFloat', value);
7676                     return this;
7677                 }
7678                 
7679                 var camel;
7680                 if(!(camel = propCache[prop])){
7681                     camel = propCache[prop] = prop.replace(camelRe, camelFn);
7682                 }
7683                 
7684                 if(camel == 'opacity') {
7685                     this.setOpacity(value);
7686                 }else{
7687                     this.dom.style[camel] = value;
7688                 }
7689             }else{
7690                 for(var style in prop){
7691                     if(typeof prop[style] != "function"){
7692                        this.setStyle(style, prop[style]);
7693                     }
7694                 }
7695             }
7696             return this;
7697         },
7698
7699         /**
7700          * More flexible version of {@link #setStyle} for setting style properties.
7701          * @param {String/Object/Function} styles A style specification string, e.g. "width:100px", or object in the form {width:"100px"}, or
7702          * a function which returns such a specification.
7703          * @return {Roo.Element} this
7704          */
7705         applyStyles : function(style){
7706             Roo.DomHelper.applyStyles(this.dom, style);
7707             return this;
7708         },
7709
7710         /**
7711           * 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).
7712           * @return {Number} The X position of the element
7713           */
7714         getX : function(){
7715             return D.getX(this.dom);
7716         },
7717
7718         /**
7719           * 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).
7720           * @return {Number} The Y position of the element
7721           */
7722         getY : function(){
7723             return D.getY(this.dom);
7724         },
7725
7726         /**
7727           * 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).
7728           * @return {Array} The XY position of the element
7729           */
7730         getXY : function(){
7731             return D.getXY(this.dom);
7732         },
7733
7734         /**
7735          * 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).
7736          * @param {Number} The X position of the element
7737          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7738          * @return {Roo.Element} this
7739          */
7740         setX : function(x, animate){
7741             if(!animate || !A){
7742                 D.setX(this.dom, x);
7743             }else{
7744                 this.setXY([x, this.getY()], this.preanim(arguments, 1));
7745             }
7746             return this;
7747         },
7748
7749         /**
7750          * 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).
7751          * @param {Number} The Y position of the element
7752          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7753          * @return {Roo.Element} this
7754          */
7755         setY : function(y, animate){
7756             if(!animate || !A){
7757                 D.setY(this.dom, y);
7758             }else{
7759                 this.setXY([this.getX(), y], this.preanim(arguments, 1));
7760             }
7761             return this;
7762         },
7763
7764         /**
7765          * Sets the element's left position directly using CSS style (instead of {@link #setX}).
7766          * @param {String} left The left CSS property value
7767          * @return {Roo.Element} this
7768          */
7769         setLeft : function(left){
7770             this.setStyle("left", this.addUnits(left));
7771             return this;
7772         },
7773
7774         /**
7775          * Sets the element's top position directly using CSS style (instead of {@link #setY}).
7776          * @param {String} top The top CSS property value
7777          * @return {Roo.Element} this
7778          */
7779         setTop : function(top){
7780             this.setStyle("top", this.addUnits(top));
7781             return this;
7782         },
7783
7784         /**
7785          * Sets the element's CSS right style.
7786          * @param {String} right The right CSS property value
7787          * @return {Roo.Element} this
7788          */
7789         setRight : function(right){
7790             this.setStyle("right", this.addUnits(right));
7791             return this;
7792         },
7793
7794         /**
7795          * Sets the element's CSS bottom style.
7796          * @param {String} bottom The bottom CSS property value
7797          * @return {Roo.Element} this
7798          */
7799         setBottom : function(bottom){
7800             this.setStyle("bottom", this.addUnits(bottom));
7801             return this;
7802         },
7803
7804         /**
7805          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7806          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7807          * @param {Array} pos Contains X & Y [x, y] values for new position (coordinates are page-based)
7808          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7809          * @return {Roo.Element} this
7810          */
7811         setXY : function(pos, animate){
7812             if(!animate || !A){
7813                 D.setXY(this.dom, pos);
7814             }else{
7815                 this.anim({points: {to: pos}}, this.preanim(arguments, 1), 'motion');
7816             }
7817             return this;
7818         },
7819
7820         /**
7821          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7822          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7823          * @param {Number} x X value for new position (coordinates are page-based)
7824          * @param {Number} y Y value for new position (coordinates are page-based)
7825          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7826          * @return {Roo.Element} this
7827          */
7828         setLocation : function(x, y, animate){
7829             this.setXY([x, y], this.preanim(arguments, 2));
7830             return this;
7831         },
7832
7833         /**
7834          * Sets the position of the element in page coordinates, regardless of how the element is positioned.
7835          * The element must be part of the DOM tree to have page coordinates (display:none or elements not appended return false).
7836          * @param {Number} x X value for new position (coordinates are page-based)
7837          * @param {Number} y Y value for new position (coordinates are page-based)
7838          * @param {Boolean/Object} animate (optional) True for the default animation, or a standard Element animation config object
7839          * @return {Roo.Element} this
7840          */
7841         moveTo : function(x, y, animate){
7842             this.setXY([x, y], this.preanim(arguments, 2));
7843             return this;
7844         },
7845
7846         /**
7847          * Returns the region of the given element.
7848          * The element must be part of the DOM tree to have a region (display:none or elements not appended return false).
7849          * @return {Region} A Roo.lib.Region containing "top, left, bottom, right" member data.
7850          */
7851         getRegion : function(){
7852             return D.getRegion(this.dom);
7853         },
7854
7855         /**
7856          * Returns the offset height of the element
7857          * @param {Boolean} contentHeight (optional) true to get the height minus borders and padding
7858          * @return {Number} The element's height
7859          */
7860         getHeight : function(contentHeight){
7861             var h = this.dom.offsetHeight || 0;
7862             return contentHeight !== true ? h : h-this.getBorderWidth("tb")-this.getPadding("tb");
7863         },
7864
7865         /**
7866          * Returns the offset width of the element
7867          * @param {Boolean} contentWidth (optional) true to get the width minus borders and padding
7868          * @return {Number} The element's width
7869          */
7870         getWidth : function(contentWidth){
7871             var w = this.dom.offsetWidth || 0;
7872             return contentWidth !== true ? w : w-this.getBorderWidth("lr")-this.getPadding("lr");
7873         },
7874
7875         /**
7876          * Returns either the offsetHeight or the height of this element based on CSS height adjusted by padding or borders
7877          * when needed to simulate offsetHeight when offsets aren't available. This may not work on display:none elements
7878          * if a height has not been set using CSS.
7879          * @return {Number}
7880          */
7881         getComputedHeight : function(){
7882             var h = Math.max(this.dom.offsetHeight, this.dom.clientHeight);
7883             if(!h){
7884                 h = parseInt(this.getStyle('height'), 10) || 0;
7885                 if(!this.isBorderBox()){
7886                     h += this.getFrameWidth('tb');
7887                 }
7888             }
7889             return h;
7890         },
7891
7892         /**
7893          * Returns either the offsetWidth or the width of this element based on CSS width adjusted by padding or borders
7894          * when needed to simulate offsetWidth when offsets aren't available. This may not work on display:none elements
7895          * if a width has not been set using CSS.
7896          * @return {Number}
7897          */
7898         getComputedWidth : function(){
7899             var w = Math.max(this.dom.offsetWidth, this.dom.clientWidth);
7900             if(!w){
7901                 w = parseInt(this.getStyle('width'), 10) || 0;
7902                 if(!this.isBorderBox()){
7903                     w += this.getFrameWidth('lr');
7904                 }
7905             }
7906             return w;
7907         },
7908
7909         /**
7910          * Returns the size of the element.
7911          * @param {Boolean} contentSize (optional) true to get the width/size minus borders and padding
7912          * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
7913          */
7914         getSize : function(contentSize){
7915             return {width: this.getWidth(contentSize), height: this.getHeight(contentSize)};
7916         },
7917
7918         /**
7919          * Returns the width and height of the viewport.
7920          * @return {Object} An object containing the viewport's size {width: (viewport width), height: (viewport height)}
7921          */
7922         getViewSize : function(){
7923             var d = this.dom, doc = document, aw = 0, ah = 0;
7924             if(d == doc || d == doc.body){
7925                 return {width : D.getViewWidth(), height: D.getViewHeight()};
7926             }else{
7927                 return {
7928                     width : d.clientWidth,
7929                     height: d.clientHeight
7930                 };
7931             }
7932         },
7933
7934         /**
7935          * Returns the value of the "value" attribute
7936          * @param {Boolean} asNumber true to parse the value as a number
7937          * @return {String/Number}
7938          */
7939         getValue : function(asNumber){
7940             return asNumber ? parseInt(this.dom.value, 10) : this.dom.value;
7941         },
7942
7943         // private
7944         adjustWidth : function(width){
7945             if(typeof width == "number"){
7946                 if(this.autoBoxAdjust && !this.isBorderBox()){
7947                    width -= (this.getBorderWidth("lr") + this.getPadding("lr"));
7948                 }
7949                 if(width < 0){
7950                     width = 0;
7951                 }
7952             }
7953             return width;
7954         },
7955
7956         // private
7957         adjustHeight : function(height){
7958             if(typeof height == "number"){
7959                if(this.autoBoxAdjust && !this.isBorderBox()){
7960                    height -= (this.getBorderWidth("tb") + this.getPadding("tb"));
7961                }
7962                if(height < 0){
7963                    height = 0;
7964                }
7965             }
7966             return height;
7967         },
7968
7969         /**
7970          * Set the width of the element
7971          * @param {Number} width The new width
7972          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7973          * @return {Roo.Element} this
7974          */
7975         setWidth : function(width, animate){
7976             width = this.adjustWidth(width);
7977             if(!animate || !A){
7978                 this.dom.style.width = this.addUnits(width);
7979             }else{
7980                 this.anim({width: {to: width}}, this.preanim(arguments, 1));
7981             }
7982             return this;
7983         },
7984
7985         /**
7986          * Set the height of the element
7987          * @param {Number} height The new height
7988          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
7989          * @return {Roo.Element} this
7990          */
7991          setHeight : function(height, animate){
7992             height = this.adjustHeight(height);
7993             if(!animate || !A){
7994                 this.dom.style.height = this.addUnits(height);
7995             }else{
7996                 this.anim({height: {to: height}}, this.preanim(arguments, 1));
7997             }
7998             return this;
7999         },
8000
8001         /**
8002          * Set the size of the element. If animation is true, both width an height will be animated concurrently.
8003          * @param {Number} width The new width
8004          * @param {Number} height The new height
8005          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8006          * @return {Roo.Element} this
8007          */
8008          setSize : function(width, height, animate){
8009             if(typeof width == "object"){ // in case of object from getSize()
8010                 height = width.height; width = width.width;
8011             }
8012             width = this.adjustWidth(width); height = this.adjustHeight(height);
8013             if(!animate || !A){
8014                 this.dom.style.width = this.addUnits(width);
8015                 this.dom.style.height = this.addUnits(height);
8016             }else{
8017                 this.anim({width: {to: width}, height: {to: height}}, this.preanim(arguments, 2));
8018             }
8019             return this;
8020         },
8021
8022         /**
8023          * Sets the element's position and size in one shot. If animation is true then width, height, x and y will be animated concurrently.
8024          * @param {Number} x X value for new position (coordinates are page-based)
8025          * @param {Number} y Y value for new position (coordinates are page-based)
8026          * @param {Number} width The new width
8027          * @param {Number} height The new height
8028          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8029          * @return {Roo.Element} this
8030          */
8031         setBounds : function(x, y, width, height, animate){
8032             if(!animate || !A){
8033                 this.setSize(width, height);
8034                 this.setLocation(x, y);
8035             }else{
8036                 width = this.adjustWidth(width); height = this.adjustHeight(height);
8037                 this.anim({points: {to: [x, y]}, width: {to: width}, height: {to: height}},
8038                               this.preanim(arguments, 4), 'motion');
8039             }
8040             return this;
8041         },
8042
8043         /**
8044          * 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.
8045          * @param {Roo.lib.Region} region The region to fill
8046          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8047          * @return {Roo.Element} this
8048          */
8049         setRegion : function(region, animate){
8050             this.setBounds(region.left, region.top, region.right-region.left, region.bottom-region.top, this.preanim(arguments, 1));
8051             return this;
8052         },
8053
8054         /**
8055          * Appends an event handler
8056          *
8057          * @param {String}   eventName     The type of event to append
8058          * @param {Function} fn        The method the event invokes
8059          * @param {Object} scope       (optional) The scope (this object) of the fn
8060          * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
8061          */
8062         addListener : function(eventName, fn, scope, options){
8063             if (this.dom) {
8064                 Roo.EventManager.on(this.dom,  eventName, fn, scope || this, options);
8065             }
8066         },
8067
8068         /**
8069          * Removes an event handler from this element
8070          * @param {String} eventName the type of event to remove
8071          * @param {Function} fn the method the event invokes
8072          * @return {Roo.Element} this
8073          */
8074         removeListener : function(eventName, fn){
8075             Roo.EventManager.removeListener(this.dom,  eventName, fn);
8076             return this;
8077         },
8078
8079         /**
8080          * Removes all previous added listeners from this element
8081          * @return {Roo.Element} this
8082          */
8083         removeAllListeners : function(){
8084             E.purgeElement(this.dom);
8085             return this;
8086         },
8087
8088         relayEvent : function(eventName, observable){
8089             this.on(eventName, function(e){
8090                 observable.fireEvent(eventName, e);
8091             });
8092         },
8093
8094         /**
8095          * Set the opacity of the element
8096          * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc
8097          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8098          * @return {Roo.Element} this
8099          */
8100          setOpacity : function(opacity, animate){
8101             if(!animate || !A){
8102                 var s = this.dom.style;
8103                 if(Roo.isIE){
8104                     s.zoom = 1;
8105                     s.filter = (s.filter || '').replace(/alpha\([^\)]*\)/gi,"") +
8106                                (opacity == 1 ? "" : "alpha(opacity=" + opacity * 100 + ")");
8107                 }else{
8108                     s.opacity = opacity;
8109                 }
8110             }else{
8111                 this.anim({opacity: {to: opacity}}, this.preanim(arguments, 1), null, .35, 'easeIn');
8112             }
8113             return this;
8114         },
8115
8116         /**
8117          * Gets the left X coordinate
8118          * @param {Boolean} local True to get the local css position instead of page coordinate
8119          * @return {Number}
8120          */
8121         getLeft : function(local){
8122             if(!local){
8123                 return this.getX();
8124             }else{
8125                 return parseInt(this.getStyle("left"), 10) || 0;
8126             }
8127         },
8128
8129         /**
8130          * Gets the right X coordinate of the element (element X position + element width)
8131          * @param {Boolean} local True to get the local css position instead of page coordinate
8132          * @return {Number}
8133          */
8134         getRight : function(local){
8135             if(!local){
8136                 return this.getX() + this.getWidth();
8137             }else{
8138                 return (this.getLeft(true) + this.getWidth()) || 0;
8139             }
8140         },
8141
8142         /**
8143          * Gets the top Y coordinate
8144          * @param {Boolean} local True to get the local css position instead of page coordinate
8145          * @return {Number}
8146          */
8147         getTop : function(local) {
8148             if(!local){
8149                 return this.getY();
8150             }else{
8151                 return parseInt(this.getStyle("top"), 10) || 0;
8152             }
8153         },
8154
8155         /**
8156          * Gets the bottom Y coordinate of the element (element Y position + element height)
8157          * @param {Boolean} local True to get the local css position instead of page coordinate
8158          * @return {Number}
8159          */
8160         getBottom : function(local){
8161             if(!local){
8162                 return this.getY() + this.getHeight();
8163             }else{
8164                 return (this.getTop(true) + this.getHeight()) || 0;
8165             }
8166         },
8167
8168         /**
8169         * Initializes positioning on this element. If a desired position is not passed, it will make the
8170         * the element positioned relative IF it is not already positioned.
8171         * @param {String} pos (optional) Positioning to use "relative", "absolute" or "fixed"
8172         * @param {Number} zIndex (optional) The zIndex to apply
8173         * @param {Number} x (optional) Set the page X position
8174         * @param {Number} y (optional) Set the page Y position
8175         */
8176         position : function(pos, zIndex, x, y){
8177             if(!pos){
8178                if(this.getStyle('position') == 'static'){
8179                    this.setStyle('position', 'relative');
8180                }
8181             }else{
8182                 this.setStyle("position", pos);
8183             }
8184             if(zIndex){
8185                 this.setStyle("z-index", zIndex);
8186             }
8187             if(x !== undefined && y !== undefined){
8188                 this.setXY([x, y]);
8189             }else if(x !== undefined){
8190                 this.setX(x);
8191             }else if(y !== undefined){
8192                 this.setY(y);
8193             }
8194         },
8195
8196         /**
8197         * Clear positioning back to the default when the document was loaded
8198         * @param {String} value (optional) The value to use for the left,right,top,bottom, defaults to '' (empty string). You could use 'auto'.
8199         * @return {Roo.Element} this
8200          */
8201         clearPositioning : function(value){
8202             value = value ||'';
8203             this.setStyle({
8204                 "left": value,
8205                 "right": value,
8206                 "top": value,
8207                 "bottom": value,
8208                 "z-index": "",
8209                 "position" : "static"
8210             });
8211             return this;
8212         },
8213
8214         /**
8215         * Gets an object with all CSS positioning properties. Useful along with setPostioning to get
8216         * snapshot before performing an update and then restoring the element.
8217         * @return {Object}
8218         */
8219         getPositioning : function(){
8220             var l = this.getStyle("left");
8221             var t = this.getStyle("top");
8222             return {
8223                 "position" : this.getStyle("position"),
8224                 "left" : l,
8225                 "right" : l ? "" : this.getStyle("right"),
8226                 "top" : t,
8227                 "bottom" : t ? "" : this.getStyle("bottom"),
8228                 "z-index" : this.getStyle("z-index")
8229             };
8230         },
8231
8232         /**
8233          * Gets the width of the border(s) for the specified side(s)
8234          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8235          * passing lr would get the border (l)eft width + the border (r)ight width.
8236          * @return {Number} The width of the sides passed added together
8237          */
8238         getBorderWidth : function(side){
8239             return this.addStyles(side, El.borders);
8240         },
8241
8242         /**
8243          * Gets the width of the padding(s) for the specified side(s)
8244          * @param {String} side Can be t, l, r, b or any combination of those to add multiple values. For example,
8245          * passing lr would get the padding (l)eft + the padding (r)ight.
8246          * @return {Number} The padding of the sides passed added together
8247          */
8248         getPadding : function(side){
8249             return this.addStyles(side, El.paddings);
8250         },
8251
8252         /**
8253         * Set positioning with an object returned by getPositioning().
8254         * @param {Object} posCfg
8255         * @return {Roo.Element} this
8256          */
8257         setPositioning : function(pc){
8258             this.applyStyles(pc);
8259             if(pc.right == "auto"){
8260                 this.dom.style.right = "";
8261             }
8262             if(pc.bottom == "auto"){
8263                 this.dom.style.bottom = "";
8264             }
8265             return this;
8266         },
8267
8268         // private
8269         fixDisplay : function(){
8270             if(this.getStyle("display") == "none"){
8271                 this.setStyle("visibility", "hidden");
8272                 this.setStyle("display", this.originalDisplay); // first try reverting to default
8273                 if(this.getStyle("display") == "none"){ // if that fails, default to block
8274                     this.setStyle("display", "block");
8275                 }
8276             }
8277         },
8278
8279         /**
8280          * Quick set left and top adding default units
8281          * @param {String} left The left CSS property value
8282          * @param {String} top The top CSS property value
8283          * @return {Roo.Element} this
8284          */
8285          setLeftTop : function(left, top){
8286             this.dom.style.left = this.addUnits(left);
8287             this.dom.style.top = this.addUnits(top);
8288             return this;
8289         },
8290
8291         /**
8292          * Move this element relative to its current position.
8293          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
8294          * @param {Number} distance How far to move the element in pixels
8295          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8296          * @return {Roo.Element} this
8297          */
8298          move : function(direction, distance, animate){
8299             var xy = this.getXY();
8300             direction = direction.toLowerCase();
8301             switch(direction){
8302                 case "l":
8303                 case "left":
8304                     this.moveTo(xy[0]-distance, xy[1], this.preanim(arguments, 2));
8305                     break;
8306                case "r":
8307                case "right":
8308                     this.moveTo(xy[0]+distance, xy[1], this.preanim(arguments, 2));
8309                     break;
8310                case "t":
8311                case "top":
8312                case "up":
8313                     this.moveTo(xy[0], xy[1]-distance, this.preanim(arguments, 2));
8314                     break;
8315                case "b":
8316                case "bottom":
8317                case "down":
8318                     this.moveTo(xy[0], xy[1]+distance, this.preanim(arguments, 2));
8319                     break;
8320             }
8321             return this;
8322         },
8323
8324         /**
8325          *  Store the current overflow setting and clip overflow on the element - use {@link #unclip} to remove
8326          * @return {Roo.Element} this
8327          */
8328         clip : function(){
8329             if(!this.isClipped){
8330                this.isClipped = true;
8331                this.originalClip = {
8332                    "o": this.getStyle("overflow"),
8333                    "x": this.getStyle("overflow-x"),
8334                    "y": this.getStyle("overflow-y")
8335                };
8336                this.setStyle("overflow", "hidden");
8337                this.setStyle("overflow-x", "hidden");
8338                this.setStyle("overflow-y", "hidden");
8339             }
8340             return this;
8341         },
8342
8343         /**
8344          *  Return clipping (overflow) to original clipping before clip() was called
8345          * @return {Roo.Element} this
8346          */
8347         unclip : function(){
8348             if(this.isClipped){
8349                 this.isClipped = false;
8350                 var o = this.originalClip;
8351                 if(o.o){this.setStyle("overflow", o.o);}
8352                 if(o.x){this.setStyle("overflow-x", o.x);}
8353                 if(o.y){this.setStyle("overflow-y", o.y);}
8354             }
8355             return this;
8356         },
8357
8358
8359         /**
8360          * Gets the x,y coordinates specified by the anchor position on the element.
8361          * @param {String} anchor (optional) The specified anchor position (defaults to "c").  See {@link #alignTo} for details on supported anchor positions.
8362          * @param {Object} size (optional) An object containing the size to use for calculating anchor position
8363          *                       {width: (target width), height: (target height)} (defaults to the element's current size)
8364          * @param {Boolean} local (optional) True to get the local (element top/left-relative) anchor position instead of page coordinates
8365          * @return {Array} [x, y] An array containing the element's x and y coordinates
8366          */
8367         getAnchorXY : function(anchor, local, s){
8368             //Passing a different size is useful for pre-calculating anchors,
8369             //especially for anchored animations that change the el size.
8370
8371             var w, h, vp = false;
8372             if(!s){
8373                 var d = this.dom;
8374                 if(d == document.body || d == document){
8375                     vp = true;
8376                     w = D.getViewWidth(); h = D.getViewHeight();
8377                 }else{
8378                     w = this.getWidth(); h = this.getHeight();
8379                 }
8380             }else{
8381                 w = s.width;  h = s.height;
8382             }
8383             var x = 0, y = 0, r = Math.round;
8384             switch((anchor || "tl").toLowerCase()){
8385                 case "c":
8386                     x = r(w*.5);
8387                     y = r(h*.5);
8388                 break;
8389                 case "t":
8390                     x = r(w*.5);
8391                     y = 0;
8392                 break;
8393                 case "l":
8394                     x = 0;
8395                     y = r(h*.5);
8396                 break;
8397                 case "r":
8398                     x = w;
8399                     y = r(h*.5);
8400                 break;
8401                 case "b":
8402                     x = r(w*.5);
8403                     y = h;
8404                 break;
8405                 case "tl":
8406                     x = 0;
8407                     y = 0;
8408                 break;
8409                 case "bl":
8410                     x = 0;
8411                     y = h;
8412                 break;
8413                 case "br":
8414                     x = w;
8415                     y = h;
8416                 break;
8417                 case "tr":
8418                     x = w;
8419                     y = 0;
8420                 break;
8421             }
8422             if(local === true){
8423                 return [x, y];
8424             }
8425             if(vp){
8426                 var sc = this.getScroll();
8427                 return [x + sc.left, y + sc.top];
8428             }
8429             //Add the element's offset xy
8430             var o = this.getXY();
8431             return [x+o[0], y+o[1]];
8432         },
8433
8434         /**
8435          * Gets the x,y coordinates to align this element with another element. See {@link #alignTo} for more info on the
8436          * supported position values.
8437          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8438          * @param {String} position The position to align to.
8439          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8440          * @return {Array} [x, y]
8441          */
8442         getAlignToXY : function(el, p, o){
8443             el = Roo.get(el);
8444             var d = this.dom;
8445             if(!el.dom){
8446                 throw "Element.alignTo with an element that doesn't exist";
8447             }
8448             var c = false; //constrain to viewport
8449             var p1 = "", p2 = "";
8450             o = o || [0,0];
8451
8452             if(!p){
8453                 p = "tl-bl";
8454             }else if(p == "?"){
8455                 p = "tl-bl?";
8456             }else if(p.indexOf("-") == -1){
8457                 p = "tl-" + p;
8458             }
8459             p = p.toLowerCase();
8460             var m = p.match(/^([a-z]+)-([a-z]+)(\?)?$/);
8461             if(!m){
8462                throw "Element.alignTo with an invalid alignment " + p;
8463             }
8464             p1 = m[1]; p2 = m[2]; c = !!m[3];
8465
8466             //Subtract the aligned el's internal xy from the target's offset xy
8467             //plus custom offset to get the aligned el's new offset xy
8468             var a1 = this.getAnchorXY(p1, true);
8469             var a2 = el.getAnchorXY(p2, false);
8470             var x = a2[0] - a1[0] + o[0];
8471             var y = a2[1] - a1[1] + o[1];
8472             if(c){
8473                 //constrain the aligned el to viewport if necessary
8474                 var w = this.getWidth(), h = this.getHeight(), r = el.getRegion();
8475                 // 5px of margin for ie
8476                 var dw = D.getViewWidth()-5, dh = D.getViewHeight()-5;
8477
8478                 //If we are at a viewport boundary and the aligned el is anchored on a target border that is
8479                 //perpendicular to the vp border, allow the aligned el to slide on that border,
8480                 //otherwise swap the aligned el to the opposite border of the target.
8481                 var p1y = p1.charAt(0), p1x = p1.charAt(p1.length-1);
8482                var p2y = p2.charAt(0), p2x = p2.charAt(p2.length-1);
8483                var swapY = ((p1y=="t" && p2y=="b") || (p1y=="b" && p2y=="t"));
8484                var swapX = ((p1x=="r" && p2x=="l") || (p1x=="l" && p2x=="r"));
8485
8486                var doc = document;
8487                var scrollX = (doc.documentElement.scrollLeft || doc.body.scrollLeft || 0)+5;
8488                var scrollY = (doc.documentElement.scrollTop || doc.body.scrollTop || 0)+5;
8489
8490                if((x+w) > dw + scrollX){
8491                     x = swapX ? r.left-w : dw+scrollX-w;
8492                 }
8493                if(x < scrollX){
8494                    x = swapX ? r.right : scrollX;
8495                }
8496                if((y+h) > dh + scrollY){
8497                     y = swapY ? r.top-h : dh+scrollY-h;
8498                 }
8499                if (y < scrollY){
8500                    y = swapY ? r.bottom : scrollY;
8501                }
8502             }
8503             return [x,y];
8504         },
8505
8506         // private
8507         getConstrainToXY : function(){
8508             var os = {top:0, left:0, bottom:0, right: 0};
8509
8510             return function(el, local, offsets, proposedXY){
8511                 el = Roo.get(el);
8512                 offsets = offsets ? Roo.applyIf(offsets, os) : os;
8513
8514                 var vw, vh, vx = 0, vy = 0;
8515                 if(el.dom == document.body || el.dom == document){
8516                     vw = Roo.lib.Dom.getViewWidth();
8517                     vh = Roo.lib.Dom.getViewHeight();
8518                 }else{
8519                     vw = el.dom.clientWidth;
8520                     vh = el.dom.clientHeight;
8521                     if(!local){
8522                         var vxy = el.getXY();
8523                         vx = vxy[0];
8524                         vy = vxy[1];
8525                     }
8526                 }
8527
8528                 var s = el.getScroll();
8529
8530                 vx += offsets.left + s.left;
8531                 vy += offsets.top + s.top;
8532
8533                 vw -= offsets.right;
8534                 vh -= offsets.bottom;
8535
8536                 var vr = vx+vw;
8537                 var vb = vy+vh;
8538
8539                 var xy = proposedXY || (!local ? this.getXY() : [this.getLeft(true), this.getTop(true)]);
8540                 var x = xy[0], y = xy[1];
8541                 var w = this.dom.offsetWidth, h = this.dom.offsetHeight;
8542
8543                 // only move it if it needs it
8544                 var moved = false;
8545
8546                 // first validate right/bottom
8547                 if((x + w) > vr){
8548                     x = vr - w;
8549                     moved = true;
8550                 }
8551                 if((y + h) > vb){
8552                     y = vb - h;
8553                     moved = true;
8554                 }
8555                 // then make sure top/left isn't negative
8556                 if(x < vx){
8557                     x = vx;
8558                     moved = true;
8559                 }
8560                 if(y < vy){
8561                     y = vy;
8562                     moved = true;
8563                 }
8564                 return moved ? [x, y] : false;
8565             };
8566         }(),
8567
8568         // private
8569         adjustForConstraints : function(xy, parent, offsets){
8570             return this.getConstrainToXY(parent || document, false, offsets, xy) ||  xy;
8571         },
8572
8573         /**
8574          * Aligns this element with another element relative to the specified anchor points. If the other element is the
8575          * document it aligns it to the viewport.
8576          * The position parameter is optional, and can be specified in any one of the following formats:
8577          * <ul>
8578          *   <li><b>Blank</b>: Defaults to aligning the element's top-left corner to the target's bottom-left corner ("tl-bl").</li>
8579          *   <li><b>One anchor (deprecated)</b>: The passed anchor position is used as the target element's anchor point.
8580          *       The element being aligned will position its top-left corner (tl) to that point.  <i>This method has been
8581          *       deprecated in favor of the newer two anchor syntax below</i>.</li>
8582          *   <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
8583          *       element's anchor point, and the second value is used as the target's anchor point.</li>
8584          * </ul>
8585          * In addition to the anchor points, the position parameter also supports the "?" character.  If "?" is passed at the end of
8586          * the position string, the element will attempt to align as specified, but the position will be adjusted to constrain to
8587          * the viewport if necessary.  Note that the element being aligned might be swapped to align to a different position than
8588          * that specified in order to enforce the viewport constraints.
8589          * Following are all of the supported anchor positions:
8590     <pre>
8591     Value  Description
8592     -----  -----------------------------
8593     tl     The top left corner (default)
8594     t      The center of the top edge
8595     tr     The top right corner
8596     l      The center of the left edge
8597     c      In the center of the element
8598     r      The center of the right edge
8599     bl     The bottom left corner
8600     b      The center of the bottom edge
8601     br     The bottom right corner
8602     </pre>
8603     Example Usage:
8604     <pre><code>
8605     // align el to other-el using the default positioning ("tl-bl", non-constrained)
8606     el.alignTo("other-el");
8607
8608     // align the top left corner of el with the top right corner of other-el (constrained to viewport)
8609     el.alignTo("other-el", "tr?");
8610
8611     // align the bottom right corner of el with the center left edge of other-el
8612     el.alignTo("other-el", "br-l?");
8613
8614     // align the center of el with the bottom left corner of other-el and
8615     // adjust the x position by -6 pixels (and the y position by 0)
8616     el.alignTo("other-el", "c-bl", [-6, 0]);
8617     </code></pre>
8618          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8619          * @param {String} position The position to align to.
8620          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8621          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8622          * @return {Roo.Element} this
8623          */
8624         alignTo : function(element, position, offsets, animate){
8625             var xy = this.getAlignToXY(element, position, offsets);
8626             this.setXY(xy, this.preanim(arguments, 3));
8627             return this;
8628         },
8629
8630         /**
8631          * Anchors an element to another element and realigns it when the window is resized.
8632          * @param {String/HTMLElement/Roo.Element} element The element to align to.
8633          * @param {String} position The position to align to.
8634          * @param {Array} offsets (optional) Offset the positioning by [x, y]
8635          * @param {Boolean/Object} animate (optional) True for the default animation or a standard Element animation config object
8636          * @param {Boolean/Number} monitorScroll (optional) True to monitor body scroll and reposition. If this parameter
8637          * is a number, it is used as the buffer delay (defaults to 50ms).
8638          * @param {Function} callback The function to call after the animation finishes
8639          * @return {Roo.Element} this
8640          */
8641         anchorTo : function(el, alignment, offsets, animate, monitorScroll, callback){
8642             var action = function(){
8643                 this.alignTo(el, alignment, offsets, animate);
8644                 Roo.callback(callback, this);
8645             };
8646             Roo.EventManager.onWindowResize(action, this);
8647             var tm = typeof monitorScroll;
8648             if(tm != 'undefined'){
8649                 Roo.EventManager.on(window, 'scroll', action, this,
8650                     {buffer: tm == 'number' ? monitorScroll : 50});
8651             }
8652             action.call(this); // align immediately
8653             return this;
8654         },
8655         /**
8656          * Clears any opacity settings from this element. Required in some cases for IE.
8657          * @return {Roo.Element} this
8658          */
8659         clearOpacity : function(){
8660             if (window.ActiveXObject) {
8661                 if(typeof this.dom.style.filter == 'string' && (/alpha/i).test(this.dom.style.filter)){
8662                     this.dom.style.filter = "";
8663                 }
8664             } else {
8665                 this.dom.style.opacity = "";
8666                 this.dom.style["-moz-opacity"] = "";
8667                 this.dom.style["-khtml-opacity"] = "";
8668             }
8669             return this;
8670         },
8671
8672         /**
8673          * Hide this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8674          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8675          * @return {Roo.Element} this
8676          */
8677         hide : function(animate){
8678             this.setVisible(false, this.preanim(arguments, 0));
8679             return this;
8680         },
8681
8682         /**
8683         * Show this element - Uses display mode to determine whether to use "display" or "visibility". See {@link #setVisible}.
8684         * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8685          * @return {Roo.Element} this
8686          */
8687         show : function(animate){
8688             this.setVisible(true, this.preanim(arguments, 0));
8689             return this;
8690         },
8691
8692         /**
8693          * @private Test if size has a unit, otherwise appends the default
8694          */
8695         addUnits : function(size){
8696             return Roo.Element.addUnits(size, this.defaultUnit);
8697         },
8698
8699         /**
8700          * Temporarily enables offsets (width,height,x,y) for an element with display:none, use endMeasure() when done.
8701          * @return {Roo.Element} this
8702          */
8703         beginMeasure : function(){
8704             var el = this.dom;
8705             if(el.offsetWidth || el.offsetHeight){
8706                 return this; // offsets work already
8707             }
8708             var changed = [];
8709             var p = this.dom, b = document.body; // start with this element
8710             while((!el.offsetWidth && !el.offsetHeight) && p && p.tagName && p != b){
8711                 var pe = Roo.get(p);
8712                 if(pe.getStyle('display') == 'none'){
8713                     changed.push({el: p, visibility: pe.getStyle("visibility")});
8714                     p.style.visibility = "hidden";
8715                     p.style.display = "block";
8716                 }
8717                 p = p.parentNode;
8718             }
8719             this._measureChanged = changed;
8720             return this;
8721
8722         },
8723
8724         /**
8725          * Restores displays to before beginMeasure was called
8726          * @return {Roo.Element} this
8727          */
8728         endMeasure : function(){
8729             var changed = this._measureChanged;
8730             if(changed){
8731                 for(var i = 0, len = changed.length; i < len; i++) {
8732                     var r = changed[i];
8733                     r.el.style.visibility = r.visibility;
8734                     r.el.style.display = "none";
8735                 }
8736                 this._measureChanged = null;
8737             }
8738             return this;
8739         },
8740
8741         /**
8742         * Update the innerHTML of this element, optionally searching for and processing scripts
8743         * @param {String} html The new HTML
8744         * @param {Boolean} loadScripts (optional) true to look for and process scripts
8745         * @param {Function} callback For async script loading you can be noticed when the update completes
8746         * @return {Roo.Element} this
8747          */
8748         update : function(html, loadScripts, callback){
8749             if(typeof html == "undefined"){
8750                 html = "";
8751             }
8752             if(loadScripts !== true){
8753                 this.dom.innerHTML = html;
8754                 if(typeof callback == "function"){
8755                     callback();
8756                 }
8757                 return this;
8758             }
8759             var id = Roo.id();
8760             var dom = this.dom;
8761
8762             html += '<span id="' + id + '"></span>';
8763
8764             E.onAvailable(id, function(){
8765                 var hd = document.getElementsByTagName("head")[0];
8766                 var re = /(?:<script([^>]*)?>)((\n|\r|.)*?)(?:<\/script>)/ig;
8767                 var srcRe = /\ssrc=([\'\"])(.*?)\1/i;
8768                 var typeRe = /\stype=([\'\"])(.*?)\1/i;
8769
8770                 var match;
8771                 while(match = re.exec(html)){
8772                     var attrs = match[1];
8773                     var srcMatch = attrs ? attrs.match(srcRe) : false;
8774                     if(srcMatch && srcMatch[2]){
8775                        var s = document.createElement("script");
8776                        s.src = srcMatch[2];
8777                        var typeMatch = attrs.match(typeRe);
8778                        if(typeMatch && typeMatch[2]){
8779                            s.type = typeMatch[2];
8780                        }
8781                        hd.appendChild(s);
8782                     }else if(match[2] && match[2].length > 0){
8783                         if(window.execScript) {
8784                            window.execScript(match[2]);
8785                         } else {
8786                             /**
8787                              * eval:var:id
8788                              * eval:var:dom
8789                              * eval:var:html
8790                              * 
8791                              */
8792                            window.eval(match[2]);
8793                         }
8794                     }
8795                 }
8796                 var el = document.getElementById(id);
8797                 if(el){el.parentNode.removeChild(el);}
8798                 if(typeof callback == "function"){
8799                     callback();
8800                 }
8801             });
8802             dom.innerHTML = html.replace(/(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)/ig, "");
8803             return this;
8804         },
8805
8806         /**
8807          * Direct access to the UpdateManager update() method (takes the same parameters).
8808          * @param {String/Function} url The url for this request or a function to call to get the url
8809          * @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}
8810          * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
8811          * @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.
8812          * @return {Roo.Element} this
8813          */
8814         load : function(){
8815             var um = this.getUpdateManager();
8816             um.update.apply(um, arguments);
8817             return this;
8818         },
8819
8820         /**
8821         * Gets this element's UpdateManager
8822         * @return {Roo.UpdateManager} The UpdateManager
8823         */
8824         getUpdateManager : function(){
8825             if(!this.updateManager){
8826                 this.updateManager = new Roo.UpdateManager(this);
8827             }
8828             return this.updateManager;
8829         },
8830
8831         /**
8832          * Disables text selection for this element (normalized across browsers)
8833          * @return {Roo.Element} this
8834          */
8835         unselectable : function(){
8836             this.dom.unselectable = "on";
8837             this.swallowEvent("selectstart", true);
8838             this.applyStyles("-moz-user-select:none;-khtml-user-select:none;");
8839             this.addClass("x-unselectable");
8840             return this;
8841         },
8842
8843         /**
8844         * Calculates the x, y to center this element on the screen
8845         * @return {Array} The x, y values [x, y]
8846         */
8847         getCenterXY : function(){
8848             return this.getAlignToXY(document, 'c-c');
8849         },
8850
8851         /**
8852         * Centers the Element in either the viewport, or another Element.
8853         * @param {String/HTMLElement/Roo.Element} centerIn (optional) The element in which to center the element.
8854         */
8855         center : function(centerIn){
8856             this.alignTo(centerIn || document, 'c-c');
8857             return this;
8858         },
8859
8860         /**
8861          * Tests various css rules/browsers to determine if this element uses a border box
8862          * @return {Boolean}
8863          */
8864         isBorderBox : function(){
8865             return noBoxAdjust[this.dom.tagName.toLowerCase()] || Roo.isBorderBox;
8866         },
8867
8868         /**
8869          * Return a box {x, y, width, height} that can be used to set another elements
8870          * size/location to match this element.
8871          * @param {Boolean} contentBox (optional) If true a box for the content of the element is returned.
8872          * @param {Boolean} local (optional) If true the element's left and top are returned instead of page x/y.
8873          * @return {Object} box An object in the format {x, y, width, height}
8874          */
8875         getBox : function(contentBox, local){
8876             var xy;
8877             if(!local){
8878                 xy = this.getXY();
8879             }else{
8880                 var left = parseInt(this.getStyle("left"), 10) || 0;
8881                 var top = parseInt(this.getStyle("top"), 10) || 0;
8882                 xy = [left, top];
8883             }
8884             var el = this.dom, w = el.offsetWidth, h = el.offsetHeight, bx;
8885             if(!contentBox){
8886                 bx = {x: xy[0], y: xy[1], 0: xy[0], 1: xy[1], width: w, height: h};
8887             }else{
8888                 var l = this.getBorderWidth("l")+this.getPadding("l");
8889                 var r = this.getBorderWidth("r")+this.getPadding("r");
8890                 var t = this.getBorderWidth("t")+this.getPadding("t");
8891                 var b = this.getBorderWidth("b")+this.getPadding("b");
8892                 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)};
8893             }
8894             bx.right = bx.x + bx.width;
8895             bx.bottom = bx.y + bx.height;
8896             return bx;
8897         },
8898
8899         /**
8900          * Returns the sum width of the padding and borders for the passed "sides". See getBorderWidth()
8901          for more information about the sides.
8902          * @param {String} sides
8903          * @return {Number}
8904          */
8905         getFrameWidth : function(sides, onlyContentBox){
8906             return onlyContentBox && Roo.isBorderBox ? 0 : (this.getPadding(sides) + this.getBorderWidth(sides));
8907         },
8908
8909         /**
8910          * 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.
8911          * @param {Object} box The box to fill {x, y, width, height}
8912          * @param {Boolean} adjust (optional) Whether to adjust for box-model issues automatically
8913          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
8914          * @return {Roo.Element} this
8915          */
8916         setBox : function(box, adjust, animate){
8917             var w = box.width, h = box.height;
8918             if((adjust && !this.autoBoxAdjust) && !this.isBorderBox()){
8919                w -= (this.getBorderWidth("lr") + this.getPadding("lr"));
8920                h -= (this.getBorderWidth("tb") + this.getPadding("tb"));
8921             }
8922             this.setBounds(box.x, box.y, w, h, this.preanim(arguments, 2));
8923             return this;
8924         },
8925
8926         /**
8927          * Forces the browser to repaint this element
8928          * @return {Roo.Element} this
8929          */
8930          repaint : function(){
8931             var dom = this.dom;
8932             this.addClass("x-repaint");
8933             setTimeout(function(){
8934                 Roo.get(dom).removeClass("x-repaint");
8935             }, 1);
8936             return this;
8937         },
8938
8939         /**
8940          * Returns an object with properties top, left, right and bottom representing the margins of this element unless sides is passed,
8941          * then it returns the calculated width of the sides (see getPadding)
8942          * @param {String} sides (optional) Any combination of l, r, t, b to get the sum of those sides
8943          * @return {Object/Number}
8944          */
8945         getMargins : function(side){
8946             if(!side){
8947                 return {
8948                     top: parseInt(this.getStyle("margin-top"), 10) || 0,
8949                     left: parseInt(this.getStyle("margin-left"), 10) || 0,
8950                     bottom: parseInt(this.getStyle("margin-bottom"), 10) || 0,
8951                     right: parseInt(this.getStyle("margin-right"), 10) || 0
8952                 };
8953             }else{
8954                 return this.addStyles(side, El.margins);
8955              }
8956         },
8957
8958         // private
8959         addStyles : function(sides, styles){
8960             var val = 0, v, w;
8961             for(var i = 0, len = sides.length; i < len; i++){
8962                 v = this.getStyle(styles[sides.charAt(i)]);
8963                 if(v){
8964                      w = parseInt(v, 10);
8965                      if(w){ val += w; }
8966                 }
8967             }
8968             return val;
8969         },
8970
8971         /**
8972          * Creates a proxy element of this element
8973          * @param {String/Object} config The class name of the proxy element or a DomHelper config object
8974          * @param {String/HTMLElement} renderTo (optional) The element or element id to render the proxy to (defaults to document.body)
8975          * @param {Boolean} matchBox (optional) True to align and size the proxy to this element now (defaults to false)
8976          * @return {Roo.Element} The new proxy element
8977          */
8978         createProxy : function(config, renderTo, matchBox){
8979             if(renderTo){
8980                 renderTo = Roo.getDom(renderTo);
8981             }else{
8982                 renderTo = document.body;
8983             }
8984             config = typeof config == "object" ?
8985                 config : {tag : "div", cls: config};
8986             var proxy = Roo.DomHelper.append(renderTo, config, true);
8987             if(matchBox){
8988                proxy.setBox(this.getBox());
8989             }
8990             return proxy;
8991         },
8992
8993         /**
8994          * Puts a mask over this element to disable user interaction. Requires core.css.
8995          * This method can only be applied to elements which accept child nodes.
8996          * @param {String} msg (optional) A message to display in the mask
8997          * @param {String} msgCls (optional) A css class to apply to the msg element
8998          * @return {Element} The mask  element
8999          */
9000         mask : function(msg, msgCls)
9001         {
9002             if(this.getStyle("position") == "static" && this.dom.tagName !== 'BODY'){
9003                 this.setStyle("position", "relative");
9004             }
9005             if(!this._mask){
9006                 this._mask = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask"}, true);
9007             }
9008             this.addClass("x-masked");
9009             this._mask.setDisplayed(true);
9010             
9011             // we wander
9012             var z = 0;
9013             var dom = this.dom;
9014             while (dom && dom.style) {
9015                 if (!isNaN(parseInt(dom.style.zIndex))) {
9016                     z = Math.max(z, parseInt(dom.style.zIndex));
9017                 }
9018                 dom = dom.parentNode;
9019             }
9020             // if we are masking the body - then it hides everything..
9021             if (this.dom == document.body) {
9022                 z = 1000000;
9023                 this._mask.setWidth(Roo.lib.Dom.getDocumentWidth());
9024                 this._mask.setHeight(Roo.lib.Dom.getDocumentHeight());
9025             }
9026            
9027             if(typeof msg == 'string'){
9028                 if(!this._maskMsg){
9029                     this._maskMsg = Roo.DomHelper.append(this.dom, {cls:"roo-el-mask-msg", cn:{tag:'div'}}, true);
9030                 }
9031                 var mm = this._maskMsg;
9032                 mm.dom.className = msgCls ? "roo-el-mask-msg " + msgCls : "roo-el-mask-msg";
9033                 if (mm.dom.firstChild) { // weird IE issue?
9034                     mm.dom.firstChild.innerHTML = msg;
9035                 }
9036                 mm.setDisplayed(true);
9037                 mm.center(this);
9038                 mm.setStyle('z-index', z + 102);
9039             }
9040             if(Roo.isIE && !(Roo.isIE7 && Roo.isStrict) && this.getStyle('height') == 'auto'){ // ie will not expand full height automatically
9041                 this._mask.setHeight(this.getHeight());
9042             }
9043             this._mask.setStyle('z-index', z + 100);
9044             
9045             return this._mask;
9046         },
9047
9048         /**
9049          * Removes a previously applied mask. If removeEl is true the mask overlay is destroyed, otherwise
9050          * it is cached for reuse.
9051          */
9052         unmask : function(removeEl){
9053             if(this._mask){
9054                 if(removeEl === true){
9055                     this._mask.remove();
9056                     delete this._mask;
9057                     if(this._maskMsg){
9058                         this._maskMsg.remove();
9059                         delete this._maskMsg;
9060                     }
9061                 }else{
9062                     this._mask.setDisplayed(false);
9063                     if(this._maskMsg){
9064                         this._maskMsg.setDisplayed(false);
9065                     }
9066                 }
9067             }
9068             this.removeClass("x-masked");
9069         },
9070
9071         /**
9072          * Returns true if this element is masked
9073          * @return {Boolean}
9074          */
9075         isMasked : function(){
9076             return this._mask && this._mask.isVisible();
9077         },
9078
9079         /**
9080          * Creates an iframe shim for this element to keep selects and other windowed objects from
9081          * showing through.
9082          * @return {Roo.Element} The new shim element
9083          */
9084         createShim : function(){
9085             var el = document.createElement('iframe');
9086             el.frameBorder = 'no';
9087             el.className = 'roo-shim';
9088             if(Roo.isIE && Roo.isSecure){
9089                 el.src = Roo.SSL_SECURE_URL;
9090             }
9091             var shim = Roo.get(this.dom.parentNode.insertBefore(el, this.dom));
9092             shim.autoBoxAdjust = false;
9093             return shim;
9094         },
9095
9096         /**
9097          * Removes this element from the DOM and deletes it from the cache
9098          */
9099         remove : function(){
9100             if(this.dom.parentNode){
9101                 this.dom.parentNode.removeChild(this.dom);
9102             }
9103             delete El.cache[this.dom.id];
9104         },
9105
9106         /**
9107          * Sets up event handlers to add and remove a css class when the mouse is over this element
9108          * @param {String} className
9109          * @param {Boolean} preventFlicker (optional) If set to true, it prevents flickering by filtering
9110          * mouseout events for children elements
9111          * @return {Roo.Element} this
9112          */
9113         addClassOnOver : function(className, preventFlicker){
9114             this.on("mouseover", function(){
9115                 Roo.fly(this, '_internal').addClass(className);
9116             }, this.dom);
9117             var removeFn = function(e){
9118                 if(preventFlicker !== true || !e.within(this, true)){
9119                     Roo.fly(this, '_internal').removeClass(className);
9120                 }
9121             };
9122             this.on("mouseout", removeFn, this.dom);
9123             return this;
9124         },
9125
9126         /**
9127          * Sets up event handlers to add and remove a css class when this element has the focus
9128          * @param {String} className
9129          * @return {Roo.Element} this
9130          */
9131         addClassOnFocus : function(className){
9132             this.on("focus", function(){
9133                 Roo.fly(this, '_internal').addClass(className);
9134             }, this.dom);
9135             this.on("blur", function(){
9136                 Roo.fly(this, '_internal').removeClass(className);
9137             }, this.dom);
9138             return this;
9139         },
9140         /**
9141          * 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)
9142          * @param {String} className
9143          * @return {Roo.Element} this
9144          */
9145         addClassOnClick : function(className){
9146             var dom = this.dom;
9147             this.on("mousedown", function(){
9148                 Roo.fly(dom, '_internal').addClass(className);
9149                 var d = Roo.get(document);
9150                 var fn = function(){
9151                     Roo.fly(dom, '_internal').removeClass(className);
9152                     d.removeListener("mouseup", fn);
9153                 };
9154                 d.on("mouseup", fn);
9155             });
9156             return this;
9157         },
9158
9159         /**
9160          * Stops the specified event from bubbling and optionally prevents the default action
9161          * @param {String} eventName
9162          * @param {Boolean} preventDefault (optional) true to prevent the default action too
9163          * @return {Roo.Element} this
9164          */
9165         swallowEvent : function(eventName, preventDefault){
9166             var fn = function(e){
9167                 e.stopPropagation();
9168                 if(preventDefault){
9169                     e.preventDefault();
9170                 }
9171             };
9172             if(eventName instanceof Array){
9173                 for(var i = 0, len = eventName.length; i < len; i++){
9174                      this.on(eventName[i], fn);
9175                 }
9176                 return this;
9177             }
9178             this.on(eventName, fn);
9179             return this;
9180         },
9181
9182         /**
9183          * @private
9184          */
9185       fitToParentDelegate : Roo.emptyFn, // keep a reference to the fitToParent delegate
9186
9187         /**
9188          * Sizes this element to its parent element's dimensions performing
9189          * neccessary box adjustments.
9190          * @param {Boolean} monitorResize (optional) If true maintains the fit when the browser window is resized.
9191          * @param {String/HTMLElment/Element} targetParent (optional) The target parent, default to the parentNode.
9192          * @return {Roo.Element} this
9193          */
9194         fitToParent : function(monitorResize, targetParent) {
9195           Roo.EventManager.removeResizeListener(this.fitToParentDelegate); // always remove previous fitToParent delegate from onWindowResize
9196           this.fitToParentDelegate = Roo.emptyFn; // remove reference to previous delegate
9197           if (monitorResize === true && !this.dom.parentNode) { // check if this Element still exists
9198             return;
9199           }
9200           var p = Roo.get(targetParent || this.dom.parentNode);
9201           this.setSize(p.getComputedWidth() - p.getFrameWidth('lr'), p.getComputedHeight() - p.getFrameWidth('tb'));
9202           if (monitorResize === true) {
9203             this.fitToParentDelegate = this.fitToParent.createDelegate(this, [true, targetParent]);
9204             Roo.EventManager.onWindowResize(this.fitToParentDelegate);
9205           }
9206           return this;
9207         },
9208
9209         /**
9210          * Gets the next sibling, skipping text nodes
9211          * @return {HTMLElement} The next sibling or null
9212          */
9213         getNextSibling : function(){
9214             var n = this.dom.nextSibling;
9215             while(n && n.nodeType != 1){
9216                 n = n.nextSibling;
9217             }
9218             return n;
9219         },
9220
9221         /**
9222          * Gets the previous sibling, skipping text nodes
9223          * @return {HTMLElement} The previous sibling or null
9224          */
9225         getPrevSibling : function(){
9226             var n = this.dom.previousSibling;
9227             while(n && n.nodeType != 1){
9228                 n = n.previousSibling;
9229             }
9230             return n;
9231         },
9232
9233
9234         /**
9235          * Appends the passed element(s) to this element
9236          * @param {String/HTMLElement/Array/Element/CompositeElement} el
9237          * @return {Roo.Element} this
9238          */
9239         appendChild: function(el){
9240             el = Roo.get(el);
9241             el.appendTo(this);
9242             return this;
9243         },
9244
9245         /**
9246          * Creates the passed DomHelper config and appends it to this element or optionally inserts it before the passed child element.
9247          * @param {Object} config DomHelper element config object.  If no tag is specified (e.g., {tag:'input'}) then a div will be
9248          * automatically generated with the specified attributes.
9249          * @param {HTMLElement} insertBefore (optional) a child element of this element
9250          * @param {Boolean} returnDom (optional) true to return the dom node instead of creating an Element
9251          * @return {Roo.Element} The new child element
9252          */
9253         createChild: function(config, insertBefore, returnDom){
9254             config = config || {tag:'div'};
9255             if(insertBefore){
9256                 return Roo.DomHelper.insertBefore(insertBefore, config, returnDom !== true);
9257             }
9258             return Roo.DomHelper[!this.dom.firstChild ? 'overwrite' : 'append'](this.dom, config,  returnDom !== true);
9259         },
9260
9261         /**
9262          * Appends this element to the passed element
9263          * @param {String/HTMLElement/Element} el The new parent element
9264          * @return {Roo.Element} this
9265          */
9266         appendTo: function(el){
9267             el = Roo.getDom(el);
9268             el.appendChild(this.dom);
9269             return this;
9270         },
9271
9272         /**
9273          * Inserts this element before the passed element in the DOM
9274          * @param {String/HTMLElement/Element} el The element to insert before
9275          * @return {Roo.Element} this
9276          */
9277         insertBefore: function(el){
9278             el = Roo.getDom(el);
9279             el.parentNode.insertBefore(this.dom, el);
9280             return this;
9281         },
9282
9283         /**
9284          * Inserts this element after the passed element in the DOM
9285          * @param {String/HTMLElement/Element} el The element to insert after
9286          * @return {Roo.Element} this
9287          */
9288         insertAfter: function(el){
9289             el = Roo.getDom(el);
9290             el.parentNode.insertBefore(this.dom, el.nextSibling);
9291             return this;
9292         },
9293
9294         /**
9295          * Inserts (or creates) an element (or DomHelper config) as the first child of the this element
9296          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9297          * @return {Roo.Element} The new child
9298          */
9299         insertFirst: function(el, returnDom){
9300             el = el || {};
9301             if(typeof el == 'object' && !el.nodeType){ // dh config
9302                 return this.createChild(el, this.dom.firstChild, returnDom);
9303             }else{
9304                 el = Roo.getDom(el);
9305                 this.dom.insertBefore(el, this.dom.firstChild);
9306                 return !returnDom ? Roo.get(el) : el;
9307             }
9308         },
9309
9310         /**
9311          * Inserts (or creates) the passed element (or DomHelper config) as a sibling of this element
9312          * @param {String/HTMLElement/Element/Object} el The id or element to insert or a DomHelper config to create and insert
9313          * @param {String} where (optional) 'before' or 'after' defaults to before
9314          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9315          * @return {Roo.Element} the inserted Element
9316          */
9317         insertSibling: function(el, where, returnDom){
9318             where = where ? where.toLowerCase() : 'before';
9319             el = el || {};
9320             var rt, refNode = where == 'before' ? this.dom : this.dom.nextSibling;
9321
9322             if(typeof el == 'object' && !el.nodeType){ // dh config
9323                 if(where == 'after' && !this.dom.nextSibling){
9324                     rt = Roo.DomHelper.append(this.dom.parentNode, el, !returnDom);
9325                 }else{
9326                     rt = Roo.DomHelper[where == 'after' ? 'insertAfter' : 'insertBefore'](this.dom, el, !returnDom);
9327                 }
9328
9329             }else{
9330                 rt = this.dom.parentNode.insertBefore(Roo.getDom(el),
9331                             where == 'before' ? this.dom : this.dom.nextSibling);
9332                 if(!returnDom){
9333                     rt = Roo.get(rt);
9334                 }
9335             }
9336             return rt;
9337         },
9338
9339         /**
9340          * Creates and wraps this element with another element
9341          * @param {Object} config (optional) DomHelper element config object for the wrapper element or null for an empty div
9342          * @param {Boolean} returnDom (optional) True to return the raw DOM element instead of Roo.Element
9343          * @return {HTMLElement/Element} The newly created wrapper element
9344          */
9345         wrap: function(config, returnDom){
9346             if(!config){
9347                 config = {tag: "div"};
9348             }
9349             var newEl = Roo.DomHelper.insertBefore(this.dom, config, !returnDom);
9350             newEl.dom ? newEl.dom.appendChild(this.dom) : newEl.appendChild(this.dom);
9351             return newEl;
9352         },
9353
9354         /**
9355          * Replaces the passed element with this element
9356          * @param {String/HTMLElement/Element} el The element to replace
9357          * @return {Roo.Element} this
9358          */
9359         replace: function(el){
9360             el = Roo.get(el);
9361             this.insertBefore(el);
9362             el.remove();
9363             return this;
9364         },
9365
9366         /**
9367          * Inserts an html fragment into this element
9368          * @param {String} where Where to insert the html in relation to the this element - beforeBegin, afterBegin, beforeEnd, afterEnd.
9369          * @param {String} html The HTML fragment
9370          * @param {Boolean} returnEl True to return an Roo.Element
9371          * @return {HTMLElement/Roo.Element} The inserted node (or nearest related if more than 1 inserted)
9372          */
9373         insertHtml : function(where, html, returnEl){
9374             var el = Roo.DomHelper.insertHtml(where, this.dom, html);
9375             return returnEl ? Roo.get(el) : el;
9376         },
9377
9378         /**
9379          * Sets the passed attributes as attributes of this element (a style attribute can be a string, object or function)
9380          * @param {Object} o The object with the attributes
9381          * @param {Boolean} useSet (optional) false to override the default setAttribute to use expandos.
9382          * @return {Roo.Element} this
9383          */
9384         set : function(o, useSet){
9385             var el = this.dom;
9386             useSet = typeof useSet == 'undefined' ? (el.setAttribute ? true : false) : useSet;
9387             for(var attr in o){
9388                 if(attr == "style" || typeof o[attr] == "function") continue;
9389                 if(attr=="cls"){
9390                     el.className = o["cls"];
9391                 }else{
9392                     if(useSet) el.setAttribute(attr, o[attr]);
9393                     else el[attr] = o[attr];
9394                 }
9395             }
9396             if(o.style){
9397                 Roo.DomHelper.applyStyles(el, o.style);
9398             }
9399             return this;
9400         },
9401
9402         /**
9403          * Convenience method for constructing a KeyMap
9404          * @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:
9405          *                                  {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
9406          * @param {Function} fn The function to call
9407          * @param {Object} scope (optional) The scope of the function
9408          * @return {Roo.KeyMap} The KeyMap created
9409          */
9410         addKeyListener : function(key, fn, scope){
9411             var config;
9412             if(typeof key != "object" || key instanceof Array){
9413                 config = {
9414                     key: key,
9415                     fn: fn,
9416                     scope: scope
9417                 };
9418             }else{
9419                 config = {
9420                     key : key.key,
9421                     shift : key.shift,
9422                     ctrl : key.ctrl,
9423                     alt : key.alt,
9424                     fn: fn,
9425                     scope: scope
9426                 };
9427             }
9428             return new Roo.KeyMap(this, config);
9429         },
9430
9431         /**
9432          * Creates a KeyMap for this element
9433          * @param {Object} config The KeyMap config. See {@link Roo.KeyMap} for more details
9434          * @return {Roo.KeyMap} The KeyMap created
9435          */
9436         addKeyMap : function(config){
9437             return new Roo.KeyMap(this, config);
9438         },
9439
9440         /**
9441          * Returns true if this element is scrollable.
9442          * @return {Boolean}
9443          */
9444          isScrollable : function(){
9445             var dom = this.dom;
9446             return dom.scrollHeight > dom.clientHeight || dom.scrollWidth > dom.clientWidth;
9447         },
9448
9449         /**
9450          * 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().
9451          * @param {String} side Either "left" for scrollLeft values or "top" for scrollTop values.
9452          * @param {Number} value The new scroll value
9453          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9454          * @return {Element} this
9455          */
9456
9457         scrollTo : function(side, value, animate){
9458             var prop = side.toLowerCase() == "left" ? "scrollLeft" : "scrollTop";
9459             if(!animate || !A){
9460                 this.dom[prop] = value;
9461             }else{
9462                 var to = prop == "scrollLeft" ? [value, this.dom.scrollTop] : [this.dom.scrollLeft, value];
9463                 this.anim({scroll: {"to": to}}, this.preanim(arguments, 2), 'scroll');
9464             }
9465             return this;
9466         },
9467
9468         /**
9469          * Scrolls this element the specified direction. Does bounds checking to make sure the scroll is
9470          * within this element's scrollable range.
9471          * @param {String} direction Possible values are: "l","left" - "r","right" - "t","top","up" - "b","bottom","down".
9472          * @param {Number} distance How far to scroll the element in pixels
9473          * @param {Boolean/Object} animate (optional) true for the default animation or a standard Element animation config object
9474          * @return {Boolean} Returns true if a scroll was triggered or false if the element
9475          * was scrolled as far as it could go.
9476          */
9477          scroll : function(direction, distance, animate){
9478              if(!this.isScrollable()){
9479                  return;
9480              }
9481              var el = this.dom;
9482              var l = el.scrollLeft, t = el.scrollTop;
9483              var w = el.scrollWidth, h = el.scrollHeight;
9484              var cw = el.clientWidth, ch = el.clientHeight;
9485              direction = direction.toLowerCase();
9486              var scrolled = false;
9487              var a = this.preanim(arguments, 2);
9488              switch(direction){
9489                  case "l":
9490                  case "left":
9491                      if(w - l > cw){
9492                          var v = Math.min(l + distance, w-cw);
9493                          this.scrollTo("left", v, a);
9494                          scrolled = true;
9495                      }
9496                      break;
9497                 case "r":
9498                 case "right":
9499                      if(l > 0){
9500                          var v = Math.max(l - distance, 0);
9501                          this.scrollTo("left", v, a);
9502                          scrolled = true;
9503                      }
9504                      break;
9505                 case "t":
9506                 case "top":
9507                 case "up":
9508                      if(t > 0){
9509                          var v = Math.max(t - distance, 0);
9510                          this.scrollTo("top", v, a);
9511                          scrolled = true;
9512                      }
9513                      break;
9514                 case "b":
9515                 case "bottom":
9516                 case "down":
9517                      if(h - t > ch){
9518                          var v = Math.min(t + distance, h-ch);
9519                          this.scrollTo("top", v, a);
9520                          scrolled = true;
9521                      }
9522                      break;
9523              }
9524              return scrolled;
9525         },
9526
9527         /**
9528          * Translates the passed page coordinates into left/top css values for this element
9529          * @param {Number/Array} x The page x or an array containing [x, y]
9530          * @param {Number} y The page y
9531          * @return {Object} An object with left and top properties. e.g. {left: (value), top: (value)}
9532          */
9533         translatePoints : function(x, y){
9534             if(typeof x == 'object' || x instanceof Array){
9535                 y = x[1]; x = x[0];
9536             }
9537             var p = this.getStyle('position');
9538             var o = this.getXY();
9539
9540             var l = parseInt(this.getStyle('left'), 10);
9541             var t = parseInt(this.getStyle('top'), 10);
9542
9543             if(isNaN(l)){
9544                 l = (p == "relative") ? 0 : this.dom.offsetLeft;
9545             }
9546             if(isNaN(t)){
9547                 t = (p == "relative") ? 0 : this.dom.offsetTop;
9548             }
9549
9550             return {left: (x - o[0] + l), top: (y - o[1] + t)};
9551         },
9552
9553         /**
9554          * Returns the current scroll position of the element.
9555          * @return {Object} An object containing the scroll position in the format {left: (scrollLeft), top: (scrollTop)}
9556          */
9557         getScroll : function(){
9558             var d = this.dom, doc = document;
9559             if(d == doc || d == doc.body){
9560                 var l = window.pageXOffset || doc.documentElement.scrollLeft || doc.body.scrollLeft || 0;
9561                 var t = window.pageYOffset || doc.documentElement.scrollTop || doc.body.scrollTop || 0;
9562                 return {left: l, top: t};
9563             }else{
9564                 return {left: d.scrollLeft, top: d.scrollTop};
9565             }
9566         },
9567
9568         /**
9569          * Return the CSS color for the specified CSS attribute. rgb, 3 digit (like #fff) and valid values
9570          * are convert to standard 6 digit hex color.
9571          * @param {String} attr The css attribute
9572          * @param {String} defaultValue The default value to use when a valid color isn't found
9573          * @param {String} prefix (optional) defaults to #. Use an empty string when working with
9574          * YUI color anims.
9575          */
9576         getColor : function(attr, defaultValue, prefix){
9577             var v = this.getStyle(attr);
9578             if(!v || v == "transparent" || v == "inherit") {
9579                 return defaultValue;
9580             }
9581             var color = typeof prefix == "undefined" ? "#" : prefix;
9582             if(v.substr(0, 4) == "rgb("){
9583                 var rvs = v.slice(4, v.length -1).split(",");
9584                 for(var i = 0; i < 3; i++){
9585                     var h = parseInt(rvs[i]).toString(16);
9586                     if(h < 16){
9587                         h = "0" + h;
9588                     }
9589                     color += h;
9590                 }
9591             } else {
9592                 if(v.substr(0, 1) == "#"){
9593                     if(v.length == 4) {
9594                         for(var i = 1; i < 4; i++){
9595                             var c = v.charAt(i);
9596                             color +=  c + c;
9597                         }
9598                     }else if(v.length == 7){
9599                         color += v.substr(1);
9600                     }
9601                 }
9602             }
9603             return(color.length > 5 ? color.toLowerCase() : defaultValue);
9604         },
9605
9606         /**
9607          * Wraps the specified element with a special markup/CSS block that renders by default as a gray container with a
9608          * gradient background, rounded corners and a 4-way shadow.
9609          * @param {String} class (optional) A base CSS class to apply to the containing wrapper element (defaults to 'x-box').
9610          * Note that there are a number of CSS rules that are dependent on this name to make the overall effect work,
9611          * so if you supply an alternate base class, make sure you also supply all of the necessary rules.
9612          * @return {Roo.Element} this
9613          */
9614         boxWrap : function(cls){
9615             cls = cls || 'x-box';
9616             var el = Roo.get(this.insertHtml('beforeBegin', String.format('<div class="{0}">'+El.boxMarkup+'</div>', cls)));
9617             el.child('.'+cls+'-mc').dom.appendChild(this.dom);
9618             return el;
9619         },
9620
9621         /**
9622          * Returns the value of a namespaced attribute from the element's underlying DOM node.
9623          * @param {String} namespace The namespace in which to look for the attribute
9624          * @param {String} name The attribute name
9625          * @return {String} The attribute value
9626          */
9627         getAttributeNS : Roo.isIE ? function(ns, name){
9628             var d = this.dom;
9629             var type = typeof d[ns+":"+name];
9630             if(type != 'undefined' && type != 'unknown'){
9631                 return d[ns+":"+name];
9632             }
9633             return d[name];
9634         } : function(ns, name){
9635             var d = this.dom;
9636             return d.getAttributeNS(ns, name) || d.getAttribute(ns+":"+name) || d.getAttribute(name) || d[name];
9637         },
9638         
9639         
9640         /**
9641          * Sets or Returns the value the dom attribute value
9642          * @param {String|Object} name The attribute name (or object to set multiple attributes)
9643          * @param {String} value (optional) The value to set the attribute to
9644          * @return {String} The attribute value
9645          */
9646         attr : function(name){
9647             if (arguments.length > 1) {
9648                 this.dom.setAttribute(name, arguments[1]);
9649                 return arguments[1];
9650             }
9651             if (typeof(name) == 'object') {
9652                 for(var i in name) {
9653                     this.attr(i, name[i]);
9654                 }
9655                 return name;
9656             }
9657             
9658             
9659             if (!this.dom.hasAttribute(name)) {
9660                 return undefined;
9661             }
9662             return this.dom.getAttribute(name);
9663         }
9664         
9665         
9666         
9667     };
9668
9669     var ep = El.prototype;
9670
9671     /**
9672      * Appends an event handler (Shorthand for addListener)
9673      * @param {String}   eventName     The type of event to append
9674      * @param {Function} fn        The method the event invokes
9675      * @param {Object} scope       (optional) The scope (this object) of the fn
9676      * @param {Object}   options   (optional)An object with standard {@link Roo.EventManager#addListener} options
9677      * @method
9678      */
9679     ep.on = ep.addListener;
9680         // backwards compat
9681     ep.mon = ep.addListener;
9682
9683     /**
9684      * Removes an event handler from this element (shorthand for removeListener)
9685      * @param {String} eventName the type of event to remove
9686      * @param {Function} fn the method the event invokes
9687      * @return {Roo.Element} this
9688      * @method
9689      */
9690     ep.un = ep.removeListener;
9691
9692     /**
9693      * true to automatically adjust width and height settings for box-model issues (default to true)
9694      */
9695     ep.autoBoxAdjust = true;
9696
9697     // private
9698     El.unitPattern = /\d+(px|em|%|en|ex|pt|in|cm|mm|pc)$/i;
9699
9700     // private
9701     El.addUnits = function(v, defaultUnit){
9702         if(v === "" || v == "auto"){
9703             return v;
9704         }
9705         if(v === undefined){
9706             return '';
9707         }
9708         if(typeof v == "number" || !El.unitPattern.test(v)){
9709             return v + (defaultUnit || 'px');
9710         }
9711         return v;
9712     };
9713
9714     // special markup used throughout Roo when box wrapping elements
9715     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>';
9716     /**
9717      * Visibility mode constant - Use visibility to hide element
9718      * @static
9719      * @type Number
9720      */
9721     El.VISIBILITY = 1;
9722     /**
9723      * Visibility mode constant - Use display to hide element
9724      * @static
9725      * @type Number
9726      */
9727     El.DISPLAY = 2;
9728
9729     El.borders = {l: "border-left-width", r: "border-right-width", t: "border-top-width", b: "border-bottom-width"};
9730     El.paddings = {l: "padding-left", r: "padding-right", t: "padding-top", b: "padding-bottom"};
9731     El.margins = {l: "margin-left", r: "margin-right", t: "margin-top", b: "margin-bottom"};
9732
9733
9734
9735     /**
9736      * @private
9737      */
9738     El.cache = {};
9739
9740     var docEl;
9741
9742     /**
9743      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9744      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9745      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9746      * @return {Element} The Element object
9747      * @static
9748      */
9749     El.get = function(el){
9750         var ex, elm, id;
9751         if(!el){ return null; }
9752         if(typeof el == "string"){ // element id
9753             if(!(elm = document.getElementById(el))){
9754                 return null;
9755             }
9756             if(ex = El.cache[el]){
9757                 ex.dom = elm;
9758             }else{
9759                 ex = El.cache[el] = new El(elm);
9760             }
9761             return ex;
9762         }else if(el.tagName){ // dom element
9763             if(!(id = el.id)){
9764                 id = Roo.id(el);
9765             }
9766             if(ex = El.cache[id]){
9767                 ex.dom = el;
9768             }else{
9769                 ex = El.cache[id] = new El(el);
9770             }
9771             return ex;
9772         }else if(el instanceof El){
9773             if(el != docEl){
9774                 el.dom = document.getElementById(el.id) || el.dom; // refresh dom element in case no longer valid,
9775                                                               // catch case where it hasn't been appended
9776                 El.cache[el.id] = el; // in case it was created directly with Element(), let's cache it
9777             }
9778             return el;
9779         }else if(el.isComposite){
9780             return el;
9781         }else if(el instanceof Array){
9782             return El.select(el);
9783         }else if(el == document){
9784             // create a bogus element object representing the document object
9785             if(!docEl){
9786                 var f = function(){};
9787                 f.prototype = El.prototype;
9788                 docEl = new f();
9789                 docEl.dom = document;
9790             }
9791             return docEl;
9792         }
9793         return null;
9794     };
9795
9796     // private
9797     El.uncache = function(el){
9798         for(var i = 0, a = arguments, len = a.length; i < len; i++) {
9799             if(a[i]){
9800                 delete El.cache[a[i].id || a[i]];
9801             }
9802         }
9803     };
9804
9805     // private
9806     // Garbage collection - uncache elements/purge listeners on orphaned elements
9807     // so we don't hold a reference and cause the browser to retain them
9808     El.garbageCollect = function(){
9809         if(!Roo.enableGarbageCollector){
9810             clearInterval(El.collectorThread);
9811             return;
9812         }
9813         for(var eid in El.cache){
9814             var el = El.cache[eid], d = el.dom;
9815             // -------------------------------------------------------
9816             // Determining what is garbage:
9817             // -------------------------------------------------------
9818             // !d
9819             // dom node is null, definitely garbage
9820             // -------------------------------------------------------
9821             // !d.parentNode
9822             // no parentNode == direct orphan, definitely garbage
9823             // -------------------------------------------------------
9824             // !d.offsetParent && !document.getElementById(eid)
9825             // display none elements have no offsetParent so we will
9826             // also try to look it up by it's id. However, check
9827             // offsetParent first so we don't do unneeded lookups.
9828             // This enables collection of elements that are not orphans
9829             // directly, but somewhere up the line they have an orphan
9830             // parent.
9831             // -------------------------------------------------------
9832             if(!d || !d.parentNode || (!d.offsetParent && !document.getElementById(eid))){
9833                 delete El.cache[eid];
9834                 if(d && Roo.enableListenerCollection){
9835                     E.purgeElement(d);
9836                 }
9837             }
9838         }
9839     }
9840     El.collectorThreadId = setInterval(El.garbageCollect, 30000);
9841
9842
9843     // dom is optional
9844     El.Flyweight = function(dom){
9845         this.dom = dom;
9846     };
9847     El.Flyweight.prototype = El.prototype;
9848
9849     El._flyweights = {};
9850     /**
9851      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9852      * the dom node can be overwritten by other code.
9853      * @param {String/HTMLElement} el The dom node or id
9854      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9855      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9856      * @static
9857      * @return {Element} The shared Element object
9858      */
9859     El.fly = function(el, named){
9860         named = named || '_global';
9861         el = Roo.getDom(el);
9862         if(!el){
9863             return null;
9864         }
9865         if(!El._flyweights[named]){
9866             El._flyweights[named] = new El.Flyweight();
9867         }
9868         El._flyweights[named].dom = el;
9869         return El._flyweights[named];
9870     };
9871
9872     /**
9873      * Static method to retrieve Element objects. Uses simple caching to consistently return the same object.
9874      * Automatically fixes if an object was recreated with the same id via AJAX or DOM.
9875      * Shorthand of {@link Roo.Element#get}
9876      * @param {String/HTMLElement/Element} el The id of the node, a DOM Node or an existing Element.
9877      * @return {Element} The Element object
9878      * @member Roo
9879      * @method get
9880      */
9881     Roo.get = El.get;
9882     /**
9883      * Gets the globally shared flyweight Element, with the passed node as the active element. Do not store a reference to this element -
9884      * the dom node can be overwritten by other code.
9885      * Shorthand of {@link Roo.Element#fly}
9886      * @param {String/HTMLElement} el The dom node or id
9887      * @param {String} named (optional) Allows for creation of named reusable flyweights to
9888      *                                  prevent conflicts (e.g. internally Roo uses "_internal")
9889      * @static
9890      * @return {Element} The shared Element object
9891      * @member Roo
9892      * @method fly
9893      */
9894     Roo.fly = El.fly;
9895
9896     // speedy lookup for elements never to box adjust
9897     var noBoxAdjust = Roo.isStrict ? {
9898         select:1
9899     } : {
9900         input:1, select:1, textarea:1
9901     };
9902     if(Roo.isIE || Roo.isGecko){
9903         noBoxAdjust['button'] = 1;
9904     }
9905
9906
9907     Roo.EventManager.on(window, 'unload', function(){
9908         delete El.cache;
9909         delete El._flyweights;
9910     });
9911 })();
9912
9913
9914
9915
9916 if(Roo.DomQuery){
9917     Roo.Element.selectorFunction = Roo.DomQuery.select;
9918 }
9919
9920 Roo.Element.select = function(selector, unique, root){
9921     var els;
9922     if(typeof selector == "string"){
9923         els = Roo.Element.selectorFunction(selector, root);
9924     }else if(selector.length !== undefined){
9925         els = selector;
9926     }else{
9927         throw "Invalid selector";
9928     }
9929     if(unique === true){
9930         return new Roo.CompositeElement(els);
9931     }else{
9932         return new Roo.CompositeElementLite(els);
9933     }
9934 };
9935 /**
9936  * Selects elements based on the passed CSS selector to enable working on them as 1.
9937  * @param {String/Array} selector The CSS selector or an array of elements
9938  * @param {Boolean} unique (optional) true to create a unique Roo.Element for each element (defaults to a shared flyweight object)
9939  * @param {HTMLElement/String} root (optional) The root element of the query or id of the root
9940  * @return {CompositeElementLite/CompositeElement}
9941  * @member Roo
9942  * @method select
9943  */
9944 Roo.select = Roo.Element.select;
9945
9946
9947
9948
9949
9950
9951
9952
9953
9954
9955
9956
9957
9958
9959 /*
9960  * Based on:
9961  * Ext JS Library 1.1.1
9962  * Copyright(c) 2006-2007, Ext JS, LLC.
9963  *
9964  * Originally Released Under LGPL - original licence link has changed is not relivant.
9965  *
9966  * Fork - LGPL
9967  * <script type="text/javascript">
9968  */
9969
9970
9971
9972 //Notifies Element that fx methods are available
9973 Roo.enableFx = true;
9974
9975 /**
9976  * @class Roo.Fx
9977  * <p>A class to provide basic animation and visual effects support.  <b>Note:</b> This class is automatically applied
9978  * to the {@link Roo.Element} interface when included, so all effects calls should be performed via Element.
9979  * Conversely, since the effects are not actually defined in Element, Roo.Fx <b>must</b> be included in order for the 
9980  * Element effects to work.</p><br/>
9981  *
9982  * <p>It is important to note that although the Fx methods and many non-Fx Element methods support "method chaining" in that
9983  * they return the Element object itself as the method return value, it is not always possible to mix the two in a single
9984  * method chain.  The Fx methods use an internal effects queue so that each effect can be properly timed and sequenced.
9985  * Non-Fx methods, on the other hand, have no such internal queueing and will always execute immediately.  For this reason,
9986  * while it may be possible to mix certain Fx and non-Fx method calls in a single chain, it may not always provide the
9987  * expected results and should be done with care.</p><br/>
9988  *
9989  * <p>Motion effects support 8-way anchoring, meaning that you can choose one of 8 different anchor points on the Element
9990  * that will serve as either the start or end point of the animation.  Following are all of the supported anchor positions:</p>
9991 <pre>
9992 Value  Description
9993 -----  -----------------------------
9994 tl     The top left corner
9995 t      The center of the top edge
9996 tr     The top right corner
9997 l      The center of the left edge
9998 r      The center of the right edge
9999 bl     The bottom left corner
10000 b      The center of the bottom edge
10001 br     The bottom right corner
10002 </pre>
10003  * <b>Although some Fx methods accept specific custom config parameters, the ones shown in the Config Options section
10004  * below are common options that can be passed to any Fx method.</b>
10005  * @cfg {Function} callback A function called when the effect is finished
10006  * @cfg {Object} scope The scope of the effect function
10007  * @cfg {String} easing A valid Easing value for the effect
10008  * @cfg {String} afterCls A css class to apply after the effect
10009  * @cfg {Number} duration The length of time (in seconds) that the effect should last
10010  * @cfg {Boolean} remove Whether the Element should be removed from the DOM and destroyed after the effect finishes
10011  * @cfg {Boolean} useDisplay Whether to use the <i>display</i> CSS property instead of <i>visibility</i> when hiding Elements (only applies to 
10012  * effects that end with the element being visually hidden, ignored otherwise)
10013  * @cfg {String/Object/Function} afterStyle A style specification string, e.g. "width:100px", or an object in the form {width:"100px"}, or
10014  * a function which returns such a specification that will be applied to the Element after the effect finishes
10015  * @cfg {Boolean} block Whether the effect should block other effects from queueing while it runs
10016  * @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
10017  * @cfg {Boolean} stopFx Whether subsequent effects should be stopped and removed after the current effect finishes
10018  */
10019 Roo.Fx = {
10020         /**
10021          * Slides the element into view.  An anchor point can be optionally passed to set the point of
10022          * origin for the slide effect.  This function automatically handles wrapping the element with
10023          * a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10024          * Usage:
10025          *<pre><code>
10026 // default: slide the element in from the top
10027 el.slideIn();
10028
10029 // custom: slide the element in from the right with a 2-second duration
10030 el.slideIn('r', { duration: 2 });
10031
10032 // common config options shown with default values
10033 el.slideIn('t', {
10034     easing: 'easeOut',
10035     duration: .5
10036 });
10037 </code></pre>
10038          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10039          * @param {Object} options (optional) Object literal with any of the Fx config options
10040          * @return {Roo.Element} The Element
10041          */
10042     slideIn : function(anchor, o){
10043         var el = this.getFxEl();
10044         o = o || {};
10045
10046         el.queueFx(o, function(){
10047
10048             anchor = anchor || "t";
10049
10050             // fix display to visibility
10051             this.fixDisplay();
10052
10053             // restore values after effect
10054             var r = this.getFxRestore();
10055             var b = this.getBox();
10056             // fixed size for slide
10057             this.setSize(b);
10058
10059             // wrap if needed
10060             var wrap = this.fxWrap(r.pos, o, "hidden");
10061
10062             var st = this.dom.style;
10063             st.visibility = "visible";
10064             st.position = "absolute";
10065
10066             // clear out temp styles after slide and unwrap
10067             var after = function(){
10068                 el.fxUnwrap(wrap, r.pos, o);
10069                 st.width = r.width;
10070                 st.height = r.height;
10071                 el.afterFx(o);
10072             };
10073             // time to calc the positions
10074             var a, pt = {to: [b.x, b.y]}, bw = {to: b.width}, bh = {to: b.height};
10075
10076             switch(anchor.toLowerCase()){
10077                 case "t":
10078                     wrap.setSize(b.width, 0);
10079                     st.left = st.bottom = "0";
10080                     a = {height: bh};
10081                 break;
10082                 case "l":
10083                     wrap.setSize(0, b.height);
10084                     st.right = st.top = "0";
10085                     a = {width: bw};
10086                 break;
10087                 case "r":
10088                     wrap.setSize(0, b.height);
10089                     wrap.setX(b.right);
10090                     st.left = st.top = "0";
10091                     a = {width: bw, points: pt};
10092                 break;
10093                 case "b":
10094                     wrap.setSize(b.width, 0);
10095                     wrap.setY(b.bottom);
10096                     st.left = st.top = "0";
10097                     a = {height: bh, points: pt};
10098                 break;
10099                 case "tl":
10100                     wrap.setSize(0, 0);
10101                     st.right = st.bottom = "0";
10102                     a = {width: bw, height: bh};
10103                 break;
10104                 case "bl":
10105                     wrap.setSize(0, 0);
10106                     wrap.setY(b.y+b.height);
10107                     st.right = st.top = "0";
10108                     a = {width: bw, height: bh, points: pt};
10109                 break;
10110                 case "br":
10111                     wrap.setSize(0, 0);
10112                     wrap.setXY([b.right, b.bottom]);
10113                     st.left = st.top = "0";
10114                     a = {width: bw, height: bh, points: pt};
10115                 break;
10116                 case "tr":
10117                     wrap.setSize(0, 0);
10118                     wrap.setX(b.x+b.width);
10119                     st.left = st.bottom = "0";
10120                     a = {width: bw, height: bh, points: pt};
10121                 break;
10122             }
10123             this.dom.style.visibility = "visible";
10124             wrap.show();
10125
10126             arguments.callee.anim = wrap.fxanim(a,
10127                 o,
10128                 'motion',
10129                 .5,
10130                 'easeOut', after);
10131         });
10132         return this;
10133     },
10134     
10135         /**
10136          * Slides the element out of view.  An anchor point can be optionally passed to set the end point
10137          * for the slide effect.  When the effect is completed, the element will be hidden (visibility = 
10138          * 'hidden') but block elements will still take up space in the document.  The element must be removed
10139          * from the DOM using the 'remove' config option if desired.  This function automatically handles 
10140          * wrapping the element with a fixed-size container if needed.  See the Fx class overview for valid anchor point options.
10141          * Usage:
10142          *<pre><code>
10143 // default: slide the element out to the top
10144 el.slideOut();
10145
10146 // custom: slide the element out to the right with a 2-second duration
10147 el.slideOut('r', { duration: 2 });
10148
10149 // common config options shown with default values
10150 el.slideOut('t', {
10151     easing: 'easeOut',
10152     duration: .5,
10153     remove: false,
10154     useDisplay: false
10155 });
10156 </code></pre>
10157          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to top: 't')
10158          * @param {Object} options (optional) Object literal with any of the Fx config options
10159          * @return {Roo.Element} The Element
10160          */
10161     slideOut : function(anchor, o){
10162         var el = this.getFxEl();
10163         o = o || {};
10164
10165         el.queueFx(o, function(){
10166
10167             anchor = anchor || "t";
10168
10169             // restore values after effect
10170             var r = this.getFxRestore();
10171             
10172             var b = this.getBox();
10173             // fixed size for slide
10174             this.setSize(b);
10175
10176             // wrap if needed
10177             var wrap = this.fxWrap(r.pos, o, "visible");
10178
10179             var st = this.dom.style;
10180             st.visibility = "visible";
10181             st.position = "absolute";
10182
10183             wrap.setSize(b);
10184
10185             var after = function(){
10186                 if(o.useDisplay){
10187                     el.setDisplayed(false);
10188                 }else{
10189                     el.hide();
10190                 }
10191
10192                 el.fxUnwrap(wrap, r.pos, o);
10193
10194                 st.width = r.width;
10195                 st.height = r.height;
10196
10197                 el.afterFx(o);
10198             };
10199
10200             var a, zero = {to: 0};
10201             switch(anchor.toLowerCase()){
10202                 case "t":
10203                     st.left = st.bottom = "0";
10204                     a = {height: zero};
10205                 break;
10206                 case "l":
10207                     st.right = st.top = "0";
10208                     a = {width: zero};
10209                 break;
10210                 case "r":
10211                     st.left = st.top = "0";
10212                     a = {width: zero, points: {to:[b.right, b.y]}};
10213                 break;
10214                 case "b":
10215                     st.left = st.top = "0";
10216                     a = {height: zero, points: {to:[b.x, b.bottom]}};
10217                 break;
10218                 case "tl":
10219                     st.right = st.bottom = "0";
10220                     a = {width: zero, height: zero};
10221                 break;
10222                 case "bl":
10223                     st.right = st.top = "0";
10224                     a = {width: zero, height: zero, points: {to:[b.x, b.bottom]}};
10225                 break;
10226                 case "br":
10227                     st.left = st.top = "0";
10228                     a = {width: zero, height: zero, points: {to:[b.x+b.width, b.bottom]}};
10229                 break;
10230                 case "tr":
10231                     st.left = st.bottom = "0";
10232                     a = {width: zero, height: zero, points: {to:[b.right, b.y]}};
10233                 break;
10234             }
10235
10236             arguments.callee.anim = wrap.fxanim(a,
10237                 o,
10238                 'motion',
10239                 .5,
10240                 "easeOut", after);
10241         });
10242         return this;
10243     },
10244
10245         /**
10246          * Fades the element out while slowly expanding it in all directions.  When the effect is completed, the 
10247          * element will be hidden (visibility = 'hidden') but block elements will still take up space in the document. 
10248          * The element must be removed from the DOM using the 'remove' config option if desired.
10249          * Usage:
10250          *<pre><code>
10251 // default
10252 el.puff();
10253
10254 // common config options shown with default values
10255 el.puff({
10256     easing: 'easeOut',
10257     duration: .5,
10258     remove: false,
10259     useDisplay: false
10260 });
10261 </code></pre>
10262          * @param {Object} options (optional) Object literal with any of the Fx config options
10263          * @return {Roo.Element} The Element
10264          */
10265     puff : function(o){
10266         var el = this.getFxEl();
10267         o = o || {};
10268
10269         el.queueFx(o, function(){
10270             this.clearOpacity();
10271             this.show();
10272
10273             // restore values after effect
10274             var r = this.getFxRestore();
10275             var st = this.dom.style;
10276
10277             var after = function(){
10278                 if(o.useDisplay){
10279                     el.setDisplayed(false);
10280                 }else{
10281                     el.hide();
10282                 }
10283
10284                 el.clearOpacity();
10285
10286                 el.setPositioning(r.pos);
10287                 st.width = r.width;
10288                 st.height = r.height;
10289                 st.fontSize = '';
10290                 el.afterFx(o);
10291             };
10292
10293             var width = this.getWidth();
10294             var height = this.getHeight();
10295
10296             arguments.callee.anim = this.fxanim({
10297                     width : {to: this.adjustWidth(width * 2)},
10298                     height : {to: this.adjustHeight(height * 2)},
10299                     points : {by: [-(width * .5), -(height * .5)]},
10300                     opacity : {to: 0},
10301                     fontSize: {to:200, unit: "%"}
10302                 },
10303                 o,
10304                 'motion',
10305                 .5,
10306                 "easeOut", after);
10307         });
10308         return this;
10309     },
10310
10311         /**
10312          * Blinks the element as if it was clicked and then collapses on its center (similar to switching off a television).
10313          * When the effect is completed, the element will be hidden (visibility = 'hidden') but block elements will still 
10314          * take up space in the document. The element must be removed from the DOM using the 'remove' config option if desired.
10315          * Usage:
10316          *<pre><code>
10317 // default
10318 el.switchOff();
10319
10320 // all config options shown with default values
10321 el.switchOff({
10322     easing: 'easeIn',
10323     duration: .3,
10324     remove: false,
10325     useDisplay: false
10326 });
10327 </code></pre>
10328          * @param {Object} options (optional) Object literal with any of the Fx config options
10329          * @return {Roo.Element} The Element
10330          */
10331     switchOff : function(o){
10332         var el = this.getFxEl();
10333         o = o || {};
10334
10335         el.queueFx(o, function(){
10336             this.clearOpacity();
10337             this.clip();
10338
10339             // restore values after effect
10340             var r = this.getFxRestore();
10341             var st = this.dom.style;
10342
10343             var after = function(){
10344                 if(o.useDisplay){
10345                     el.setDisplayed(false);
10346                 }else{
10347                     el.hide();
10348                 }
10349
10350                 el.clearOpacity();
10351                 el.setPositioning(r.pos);
10352                 st.width = r.width;
10353                 st.height = r.height;
10354
10355                 el.afterFx(o);
10356             };
10357
10358             this.fxanim({opacity:{to:0.3}}, null, null, .1, null, function(){
10359                 this.clearOpacity();
10360                 (function(){
10361                     this.fxanim({
10362                         height:{to:1},
10363                         points:{by:[0, this.getHeight() * .5]}
10364                     }, o, 'motion', 0.3, 'easeIn', after);
10365                 }).defer(100, this);
10366             });
10367         });
10368         return this;
10369     },
10370
10371     /**
10372      * Highlights the Element by setting a color (applies to the background-color by default, but can be
10373      * changed using the "attr" config option) and then fading back to the original color. If no original
10374      * color is available, you should provide the "endColor" config option which will be cleared after the animation.
10375      * Usage:
10376 <pre><code>
10377 // default: highlight background to yellow
10378 el.highlight();
10379
10380 // custom: highlight foreground text to blue for 2 seconds
10381 el.highlight("0000ff", { attr: 'color', duration: 2 });
10382
10383 // common config options shown with default values
10384 el.highlight("ffff9c", {
10385     attr: "background-color", //can be any valid CSS property (attribute) that supports a color value
10386     endColor: (current color) or "ffffff",
10387     easing: 'easeIn',
10388     duration: 1
10389 });
10390 </code></pre>
10391      * @param {String} color (optional) The highlight color. Should be a 6 char hex color without the leading # (defaults to yellow: 'ffff9c')
10392      * @param {Object} options (optional) Object literal with any of the Fx config options
10393      * @return {Roo.Element} The Element
10394      */ 
10395     highlight : function(color, o){
10396         var el = this.getFxEl();
10397         o = o || {};
10398
10399         el.queueFx(o, function(){
10400             color = color || "ffff9c";
10401             attr = o.attr || "backgroundColor";
10402
10403             this.clearOpacity();
10404             this.show();
10405
10406             var origColor = this.getColor(attr);
10407             var restoreColor = this.dom.style[attr];
10408             endColor = (o.endColor || origColor) || "ffffff";
10409
10410             var after = function(){
10411                 el.dom.style[attr] = restoreColor;
10412                 el.afterFx(o);
10413             };
10414
10415             var a = {};
10416             a[attr] = {from: color, to: endColor};
10417             arguments.callee.anim = this.fxanim(a,
10418                 o,
10419                 'color',
10420                 1,
10421                 'easeIn', after);
10422         });
10423         return this;
10424     },
10425
10426    /**
10427     * Shows a ripple of exploding, attenuating borders to draw attention to an Element.
10428     * Usage:
10429 <pre><code>
10430 // default: a single light blue ripple
10431 el.frame();
10432
10433 // custom: 3 red ripples lasting 3 seconds total
10434 el.frame("ff0000", 3, { duration: 3 });
10435
10436 // common config options shown with default values
10437 el.frame("C3DAF9", 1, {
10438     duration: 1 //duration of entire animation (not each individual ripple)
10439     // Note: Easing is not configurable and will be ignored if included
10440 });
10441 </code></pre>
10442     * @param {String} color (optional) The color of the border.  Should be a 6 char hex color without the leading # (defaults to light blue: 'C3DAF9').
10443     * @param {Number} count (optional) The number of ripples to display (defaults to 1)
10444     * @param {Object} options (optional) Object literal with any of the Fx config options
10445     * @return {Roo.Element} The Element
10446     */
10447     frame : function(color, count, o){
10448         var el = this.getFxEl();
10449         o = o || {};
10450
10451         el.queueFx(o, function(){
10452             color = color || "#C3DAF9";
10453             if(color.length == 6){
10454                 color = "#" + color;
10455             }
10456             count = count || 1;
10457             duration = o.duration || 1;
10458             this.show();
10459
10460             var b = this.getBox();
10461             var animFn = function(){
10462                 var proxy = this.createProxy({
10463
10464                      style:{
10465                         visbility:"hidden",
10466                         position:"absolute",
10467                         "z-index":"35000", // yee haw
10468                         border:"0px solid " + color
10469                      }
10470                   });
10471                 var scale = Roo.isBorderBox ? 2 : 1;
10472                 proxy.animate({
10473                     top:{from:b.y, to:b.y - 20},
10474                     left:{from:b.x, to:b.x - 20},
10475                     borderWidth:{from:0, to:10},
10476                     opacity:{from:1, to:0},
10477                     height:{from:b.height, to:(b.height + (20*scale))},
10478                     width:{from:b.width, to:(b.width + (20*scale))}
10479                 }, duration, function(){
10480                     proxy.remove();
10481                 });
10482                 if(--count > 0){
10483                      animFn.defer((duration/2)*1000, this);
10484                 }else{
10485                     el.afterFx(o);
10486                 }
10487             };
10488             animFn.call(this);
10489         });
10490         return this;
10491     },
10492
10493    /**
10494     * Creates a pause before any subsequent queued effects begin.  If there are
10495     * no effects queued after the pause it will have no effect.
10496     * Usage:
10497 <pre><code>
10498 el.pause(1);
10499 </code></pre>
10500     * @param {Number} seconds The length of time to pause (in seconds)
10501     * @return {Roo.Element} The Element
10502     */
10503     pause : function(seconds){
10504         var el = this.getFxEl();
10505         var o = {};
10506
10507         el.queueFx(o, function(){
10508             setTimeout(function(){
10509                 el.afterFx(o);
10510             }, seconds * 1000);
10511         });
10512         return this;
10513     },
10514
10515    /**
10516     * Fade an element in (from transparent to opaque).  The ending opacity can be specified
10517     * using the "endOpacity" config option.
10518     * Usage:
10519 <pre><code>
10520 // default: fade in from opacity 0 to 100%
10521 el.fadeIn();
10522
10523 // custom: fade in from opacity 0 to 75% over 2 seconds
10524 el.fadeIn({ endOpacity: .75, duration: 2});
10525
10526 // common config options shown with default values
10527 el.fadeIn({
10528     endOpacity: 1, //can be any value between 0 and 1 (e.g. .5)
10529     easing: 'easeOut',
10530     duration: .5
10531 });
10532 </code></pre>
10533     * @param {Object} options (optional) Object literal with any of the Fx config options
10534     * @return {Roo.Element} The Element
10535     */
10536     fadeIn : function(o){
10537         var el = this.getFxEl();
10538         o = o || {};
10539         el.queueFx(o, function(){
10540             this.setOpacity(0);
10541             this.fixDisplay();
10542             this.dom.style.visibility = 'visible';
10543             var to = o.endOpacity || 1;
10544             arguments.callee.anim = this.fxanim({opacity:{to:to}},
10545                 o, null, .5, "easeOut", function(){
10546                 if(to == 1){
10547                     this.clearOpacity();
10548                 }
10549                 el.afterFx(o);
10550             });
10551         });
10552         return this;
10553     },
10554
10555    /**
10556     * Fade an element out (from opaque to transparent).  The ending opacity can be specified
10557     * using the "endOpacity" config option.
10558     * Usage:
10559 <pre><code>
10560 // default: fade out from the element's current opacity to 0
10561 el.fadeOut();
10562
10563 // custom: fade out from the element's current opacity to 25% over 2 seconds
10564 el.fadeOut({ endOpacity: .25, duration: 2});
10565
10566 // common config options shown with default values
10567 el.fadeOut({
10568     endOpacity: 0, //can be any value between 0 and 1 (e.g. .5)
10569     easing: 'easeOut',
10570     duration: .5
10571     remove: false,
10572     useDisplay: false
10573 });
10574 </code></pre>
10575     * @param {Object} options (optional) Object literal with any of the Fx config options
10576     * @return {Roo.Element} The Element
10577     */
10578     fadeOut : function(o){
10579         var el = this.getFxEl();
10580         o = o || {};
10581         el.queueFx(o, function(){
10582             arguments.callee.anim = this.fxanim({opacity:{to:o.endOpacity || 0}},
10583                 o, null, .5, "easeOut", function(){
10584                 if(this.visibilityMode == Roo.Element.DISPLAY || o.useDisplay){
10585                      this.dom.style.display = "none";
10586                 }else{
10587                      this.dom.style.visibility = "hidden";
10588                 }
10589                 this.clearOpacity();
10590                 el.afterFx(o);
10591             });
10592         });
10593         return this;
10594     },
10595
10596    /**
10597     * Animates the transition of an element's dimensions from a starting height/width
10598     * to an ending height/width.
10599     * Usage:
10600 <pre><code>
10601 // change height and width to 100x100 pixels
10602 el.scale(100, 100);
10603
10604 // common config options shown with default values.  The height and width will default to
10605 // the element's existing values if passed as null.
10606 el.scale(
10607     [element's width],
10608     [element's height], {
10609     easing: 'easeOut',
10610     duration: .35
10611 });
10612 </code></pre>
10613     * @param {Number} width  The new width (pass undefined to keep the original width)
10614     * @param {Number} height  The new height (pass undefined to keep the original height)
10615     * @param {Object} options (optional) Object literal with any of the Fx config options
10616     * @return {Roo.Element} The Element
10617     */
10618     scale : function(w, h, o){
10619         this.shift(Roo.apply({}, o, {
10620             width: w,
10621             height: h
10622         }));
10623         return this;
10624     },
10625
10626    /**
10627     * Animates the transition of any combination of an element's dimensions, xy position and/or opacity.
10628     * Any of these properties not specified in the config object will not be changed.  This effect 
10629     * requires that at least one new dimension, position or opacity setting must be passed in on
10630     * the config object in order for the function to have any effect.
10631     * Usage:
10632 <pre><code>
10633 // slide the element horizontally to x position 200 while changing the height and opacity
10634 el.shift({ x: 200, height: 50, opacity: .8 });
10635
10636 // common config options shown with default values.
10637 el.shift({
10638     width: [element's width],
10639     height: [element's height],
10640     x: [element's x position],
10641     y: [element's y position],
10642     opacity: [element's opacity],
10643     easing: 'easeOut',
10644     duration: .35
10645 });
10646 </code></pre>
10647     * @param {Object} options  Object literal with any of the Fx config options
10648     * @return {Roo.Element} The Element
10649     */
10650     shift : function(o){
10651         var el = this.getFxEl();
10652         o = o || {};
10653         el.queueFx(o, function(){
10654             var a = {}, w = o.width, h = o.height, x = o.x, y = o.y,  op = o.opacity;
10655             if(w !== undefined){
10656                 a.width = {to: this.adjustWidth(w)};
10657             }
10658             if(h !== undefined){
10659                 a.height = {to: this.adjustHeight(h)};
10660             }
10661             if(x !== undefined || y !== undefined){
10662                 a.points = {to: [
10663                     x !== undefined ? x : this.getX(),
10664                     y !== undefined ? y : this.getY()
10665                 ]};
10666             }
10667             if(op !== undefined){
10668                 a.opacity = {to: op};
10669             }
10670             if(o.xy !== undefined){
10671                 a.points = {to: o.xy};
10672             }
10673             arguments.callee.anim = this.fxanim(a,
10674                 o, 'motion', .35, "easeOut", function(){
10675                 el.afterFx(o);
10676             });
10677         });
10678         return this;
10679     },
10680
10681         /**
10682          * Slides the element while fading it out of view.  An anchor point can be optionally passed to set the 
10683          * ending point of the effect.
10684          * Usage:
10685          *<pre><code>
10686 // default: slide the element downward while fading out
10687 el.ghost();
10688
10689 // custom: slide the element out to the right with a 2-second duration
10690 el.ghost('r', { duration: 2 });
10691
10692 // common config options shown with default values
10693 el.ghost('b', {
10694     easing: 'easeOut',
10695     duration: .5
10696     remove: false,
10697     useDisplay: false
10698 });
10699 </code></pre>
10700          * @param {String} anchor (optional) One of the valid Fx anchor positions (defaults to bottom: 'b')
10701          * @param {Object} options (optional) Object literal with any of the Fx config options
10702          * @return {Roo.Element} The Element
10703          */
10704     ghost : function(anchor, o){
10705         var el = this.getFxEl();
10706         o = o || {};
10707
10708         el.queueFx(o, function(){
10709             anchor = anchor || "b";
10710
10711             // restore values after effect
10712             var r = this.getFxRestore();
10713             var w = this.getWidth(),
10714                 h = this.getHeight();
10715
10716             var st = this.dom.style;
10717
10718             var after = function(){
10719                 if(o.useDisplay){
10720                     el.setDisplayed(false);
10721                 }else{
10722                     el.hide();
10723                 }
10724
10725                 el.clearOpacity();
10726                 el.setPositioning(r.pos);
10727                 st.width = r.width;
10728                 st.height = r.height;
10729
10730                 el.afterFx(o);
10731             };
10732
10733             var a = {opacity: {to: 0}, points: {}}, pt = a.points;
10734             switch(anchor.toLowerCase()){
10735                 case "t":
10736                     pt.by = [0, -h];
10737                 break;
10738                 case "l":
10739                     pt.by = [-w, 0];
10740                 break;
10741                 case "r":
10742                     pt.by = [w, 0];
10743                 break;
10744                 case "b":
10745                     pt.by = [0, h];
10746                 break;
10747                 case "tl":
10748                     pt.by = [-w, -h];
10749                 break;
10750                 case "bl":
10751                     pt.by = [-w, h];
10752                 break;
10753                 case "br":
10754                     pt.by = [w, h];
10755                 break;
10756                 case "tr":
10757                     pt.by = [w, -h];
10758                 break;
10759             }
10760
10761             arguments.callee.anim = this.fxanim(a,
10762                 o,
10763                 'motion',
10764                 .5,
10765                 "easeOut", after);
10766         });
10767         return this;
10768     },
10769
10770         /**
10771          * Ensures that all effects queued after syncFx is called on the element are
10772          * run concurrently.  This is the opposite of {@link #sequenceFx}.
10773          * @return {Roo.Element} The Element
10774          */
10775     syncFx : function(){
10776         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10777             block : false,
10778             concurrent : true,
10779             stopFx : false
10780         });
10781         return this;
10782     },
10783
10784         /**
10785          * Ensures that all effects queued after sequenceFx is called on the element are
10786          * run in sequence.  This is the opposite of {@link #syncFx}.
10787          * @return {Roo.Element} The Element
10788          */
10789     sequenceFx : function(){
10790         this.fxDefaults = Roo.apply(this.fxDefaults || {}, {
10791             block : false,
10792             concurrent : false,
10793             stopFx : false
10794         });
10795         return this;
10796     },
10797
10798         /* @private */
10799     nextFx : function(){
10800         var ef = this.fxQueue[0];
10801         if(ef){
10802             ef.call(this);
10803         }
10804     },
10805
10806         /**
10807          * Returns true if the element has any effects actively running or queued, else returns false.
10808          * @return {Boolean} True if element has active effects, else false
10809          */
10810     hasActiveFx : function(){
10811         return this.fxQueue && this.fxQueue[0];
10812     },
10813
10814         /**
10815          * Stops any running effects and clears the element's internal effects queue if it contains
10816          * any additional effects that haven't started yet.
10817          * @return {Roo.Element} The Element
10818          */
10819     stopFx : function(){
10820         if(this.hasActiveFx()){
10821             var cur = this.fxQueue[0];
10822             if(cur && cur.anim && cur.anim.isAnimated()){
10823                 this.fxQueue = [cur]; // clear out others
10824                 cur.anim.stop(true);
10825             }
10826         }
10827         return this;
10828     },
10829
10830         /* @private */
10831     beforeFx : function(o){
10832         if(this.hasActiveFx() && !o.concurrent){
10833            if(o.stopFx){
10834                this.stopFx();
10835                return true;
10836            }
10837            return false;
10838         }
10839         return true;
10840     },
10841
10842         /**
10843          * Returns true if the element is currently blocking so that no other effect can be queued
10844          * until this effect is finished, else returns false if blocking is not set.  This is commonly
10845          * used to ensure that an effect initiated by a user action runs to completion prior to the
10846          * same effect being restarted (e.g., firing only one effect even if the user clicks several times).
10847          * @return {Boolean} True if blocking, else false
10848          */
10849     hasFxBlock : function(){
10850         var q = this.fxQueue;
10851         return q && q[0] && q[0].block;
10852     },
10853
10854         /* @private */
10855     queueFx : function(o, fn){
10856         if(!this.fxQueue){
10857             this.fxQueue = [];
10858         }
10859         if(!this.hasFxBlock()){
10860             Roo.applyIf(o, this.fxDefaults);
10861             if(!o.concurrent){
10862                 var run = this.beforeFx(o);
10863                 fn.block = o.block;
10864                 this.fxQueue.push(fn);
10865                 if(run){
10866                     this.nextFx();
10867                 }
10868             }else{
10869                 fn.call(this);
10870             }
10871         }
10872         return this;
10873     },
10874
10875         /* @private */
10876     fxWrap : function(pos, o, vis){
10877         var wrap;
10878         if(!o.wrap || !(wrap = Roo.get(o.wrap))){
10879             var wrapXY;
10880             if(o.fixPosition){
10881                 wrapXY = this.getXY();
10882             }
10883             var div = document.createElement("div");
10884             div.style.visibility = vis;
10885             wrap = Roo.get(this.dom.parentNode.insertBefore(div, this.dom));
10886             wrap.setPositioning(pos);
10887             if(wrap.getStyle("position") == "static"){
10888                 wrap.position("relative");
10889             }
10890             this.clearPositioning('auto');
10891             wrap.clip();
10892             wrap.dom.appendChild(this.dom);
10893             if(wrapXY){
10894                 wrap.setXY(wrapXY);
10895             }
10896         }
10897         return wrap;
10898     },
10899
10900         /* @private */
10901     fxUnwrap : function(wrap, pos, o){
10902         this.clearPositioning();
10903         this.setPositioning(pos);
10904         if(!o.wrap){
10905             wrap.dom.parentNode.insertBefore(this.dom, wrap.dom);
10906             wrap.remove();
10907         }
10908     },
10909
10910         /* @private */
10911     getFxRestore : function(){
10912         var st = this.dom.style;
10913         return {pos: this.getPositioning(), width: st.width, height : st.height};
10914     },
10915
10916         /* @private */
10917     afterFx : function(o){
10918         if(o.afterStyle){
10919             this.applyStyles(o.afterStyle);
10920         }
10921         if(o.afterCls){
10922             this.addClass(o.afterCls);
10923         }
10924         if(o.remove === true){
10925             this.remove();
10926         }
10927         Roo.callback(o.callback, o.scope, [this]);
10928         if(!o.concurrent){
10929             this.fxQueue.shift();
10930             this.nextFx();
10931         }
10932     },
10933
10934         /* @private */
10935     getFxEl : function(){ // support for composite element fx
10936         return Roo.get(this.dom);
10937     },
10938
10939         /* @private */
10940     fxanim : function(args, opt, animType, defaultDur, defaultEase, cb){
10941         animType = animType || 'run';
10942         opt = opt || {};
10943         var anim = Roo.lib.Anim[animType](
10944             this.dom, args,
10945             (opt.duration || defaultDur) || .35,
10946             (opt.easing || defaultEase) || 'easeOut',
10947             function(){
10948                 Roo.callback(cb, this);
10949             },
10950             this
10951         );
10952         opt.anim = anim;
10953         return anim;
10954     }
10955 };
10956
10957 // backwords compat
10958 Roo.Fx.resize = Roo.Fx.scale;
10959
10960 //When included, Roo.Fx is automatically applied to Element so that all basic
10961 //effects are available directly via the Element API
10962 Roo.apply(Roo.Element.prototype, Roo.Fx);/*
10963  * Based on:
10964  * Ext JS Library 1.1.1
10965  * Copyright(c) 2006-2007, Ext JS, LLC.
10966  *
10967  * Originally Released Under LGPL - original licence link has changed is not relivant.
10968  *
10969  * Fork - LGPL
10970  * <script type="text/javascript">
10971  */
10972
10973
10974 /**
10975  * @class Roo.CompositeElement
10976  * Standard composite class. Creates a Roo.Element for every element in the collection.
10977  * <br><br>
10978  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
10979  * actions will be performed on all the elements in this collection.</b>
10980  * <br><br>
10981  * All methods return <i>this</i> and can be chained.
10982  <pre><code>
10983  var els = Roo.select("#some-el div.some-class", true);
10984  // or select directly from an existing element
10985  var el = Roo.get('some-el');
10986  el.select('div.some-class', true);
10987
10988  els.setWidth(100); // all elements become 100 width
10989  els.hide(true); // all elements fade out and hide
10990  // or
10991  els.setWidth(100).hide(true);
10992  </code></pre>
10993  */
10994 Roo.CompositeElement = function(els){
10995     this.elements = [];
10996     this.addElements(els);
10997 };
10998 Roo.CompositeElement.prototype = {
10999     isComposite: true,
11000     addElements : function(els){
11001         if(!els) return this;
11002         if(typeof els == "string"){
11003             els = Roo.Element.selectorFunction(els);
11004         }
11005         var yels = this.elements;
11006         var index = yels.length-1;
11007         for(var i = 0, len = els.length; i < len; i++) {
11008                 yels[++index] = Roo.get(els[i]);
11009         }
11010         return this;
11011     },
11012
11013     /**
11014     * Clears this composite and adds the elements returned by the passed selector.
11015     * @param {String/Array} els A string CSS selector, an array of elements or an element
11016     * @return {CompositeElement} this
11017     */
11018     fill : function(els){
11019         this.elements = [];
11020         this.add(els);
11021         return this;
11022     },
11023
11024     /**
11025     * Filters this composite to only elements that match the passed selector.
11026     * @param {String} selector A string CSS selector
11027     * @param {Boolean} inverse return inverse filter (not matches)
11028     * @return {CompositeElement} this
11029     */
11030     filter : function(selector, inverse){
11031         var els = [];
11032         inverse = inverse || false;
11033         this.each(function(el){
11034             var match = inverse ? !el.is(selector) : el.is(selector);
11035             if(match){
11036                 els[els.length] = el.dom;
11037             }
11038         });
11039         this.fill(els);
11040         return this;
11041     },
11042
11043     invoke : function(fn, args){
11044         var els = this.elements;
11045         for(var i = 0, len = els.length; i < len; i++) {
11046                 Roo.Element.prototype[fn].apply(els[i], args);
11047         }
11048         return this;
11049     },
11050     /**
11051     * Adds elements to this composite.
11052     * @param {String/Array} els A string CSS selector, an array of elements or an element
11053     * @return {CompositeElement} this
11054     */
11055     add : function(els){
11056         if(typeof els == "string"){
11057             this.addElements(Roo.Element.selectorFunction(els));
11058         }else if(els.length !== undefined){
11059             this.addElements(els);
11060         }else{
11061             this.addElements([els]);
11062         }
11063         return this;
11064     },
11065     /**
11066     * Calls the passed function passing (el, this, index) for each element in this composite.
11067     * @param {Function} fn The function to call
11068     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11069     * @return {CompositeElement} this
11070     */
11071     each : function(fn, scope){
11072         var els = this.elements;
11073         for(var i = 0, len = els.length; i < len; i++){
11074             if(fn.call(scope || els[i], els[i], this, i) === false) {
11075                 break;
11076             }
11077         }
11078         return this;
11079     },
11080
11081     /**
11082      * Returns the Element object at the specified index
11083      * @param {Number} index
11084      * @return {Roo.Element}
11085      */
11086     item : function(index){
11087         return this.elements[index] || null;
11088     },
11089
11090     /**
11091      * Returns the first Element
11092      * @return {Roo.Element}
11093      */
11094     first : function(){
11095         return this.item(0);
11096     },
11097
11098     /**
11099      * Returns the last Element
11100      * @return {Roo.Element}
11101      */
11102     last : function(){
11103         return this.item(this.elements.length-1);
11104     },
11105
11106     /**
11107      * Returns the number of elements in this composite
11108      * @return Number
11109      */
11110     getCount : function(){
11111         return this.elements.length;
11112     },
11113
11114     /**
11115      * Returns true if this composite contains the passed element
11116      * @return Boolean
11117      */
11118     contains : function(el){
11119         return this.indexOf(el) !== -1;
11120     },
11121
11122     /**
11123      * Returns true if this composite contains the passed element
11124      * @return Boolean
11125      */
11126     indexOf : function(el){
11127         return this.elements.indexOf(Roo.get(el));
11128     },
11129
11130
11131     /**
11132     * Removes the specified element(s).
11133     * @param {Mixed} el The id of an element, the Element itself, the index of the element in this composite
11134     * or an array of any of those.
11135     * @param {Boolean} removeDom (optional) True to also remove the element from the document
11136     * @return {CompositeElement} this
11137     */
11138     removeElement : function(el, removeDom){
11139         if(el instanceof Array){
11140             for(var i = 0, len = el.length; i < len; i++){
11141                 this.removeElement(el[i]);
11142             }
11143             return this;
11144         }
11145         var index = typeof el == 'number' ? el : this.indexOf(el);
11146         if(index !== -1){
11147             if(removeDom){
11148                 var d = this.elements[index];
11149                 if(d.dom){
11150                     d.remove();
11151                 }else{
11152                     d.parentNode.removeChild(d);
11153                 }
11154             }
11155             this.elements.splice(index, 1);
11156         }
11157         return this;
11158     },
11159
11160     /**
11161     * Replaces the specified element with the passed element.
11162     * @param {String/HTMLElement/Element/Number} el The id of an element, the Element itself, the index of the element in this composite
11163     * to replace.
11164     * @param {String/HTMLElement/Element} replacement The id of an element or the Element itself.
11165     * @param {Boolean} domReplace (Optional) True to remove and replace the element in the document too.
11166     * @return {CompositeElement} this
11167     */
11168     replaceElement : function(el, replacement, domReplace){
11169         var index = typeof el == 'number' ? el : this.indexOf(el);
11170         if(index !== -1){
11171             if(domReplace){
11172                 this.elements[index].replaceWith(replacement);
11173             }else{
11174                 this.elements.splice(index, 1, Roo.get(replacement))
11175             }
11176         }
11177         return this;
11178     },
11179
11180     /**
11181      * Removes all elements.
11182      */
11183     clear : function(){
11184         this.elements = [];
11185     }
11186 };
11187 (function(){
11188     Roo.CompositeElement.createCall = function(proto, fnName){
11189         if(!proto[fnName]){
11190             proto[fnName] = function(){
11191                 return this.invoke(fnName, arguments);
11192             };
11193         }
11194     };
11195     for(var fnName in Roo.Element.prototype){
11196         if(typeof Roo.Element.prototype[fnName] == "function"){
11197             Roo.CompositeElement.createCall(Roo.CompositeElement.prototype, fnName);
11198         }
11199     };
11200 })();
11201 /*
11202  * Based on:
11203  * Ext JS Library 1.1.1
11204  * Copyright(c) 2006-2007, Ext JS, LLC.
11205  *
11206  * Originally Released Under LGPL - original licence link has changed is not relivant.
11207  *
11208  * Fork - LGPL
11209  * <script type="text/javascript">
11210  */
11211
11212 /**
11213  * @class Roo.CompositeElementLite
11214  * @extends Roo.CompositeElement
11215  * Flyweight composite class. Reuses the same Roo.Element for element operations.
11216  <pre><code>
11217  var els = Roo.select("#some-el div.some-class");
11218  // or select directly from an existing element
11219  var el = Roo.get('some-el');
11220  el.select('div.some-class');
11221
11222  els.setWidth(100); // all elements become 100 width
11223  els.hide(true); // all elements fade out and hide
11224  // or
11225  els.setWidth(100).hide(true);
11226  </code></pre><br><br>
11227  * <b>NOTE: Although they are not listed, this class supports all of the set/update methods of Roo.Element. All Roo.Element
11228  * actions will be performed on all the elements in this collection.</b>
11229  */
11230 Roo.CompositeElementLite = function(els){
11231     Roo.CompositeElementLite.superclass.constructor.call(this, els);
11232     this.el = new Roo.Element.Flyweight();
11233 };
11234 Roo.extend(Roo.CompositeElementLite, Roo.CompositeElement, {
11235     addElements : function(els){
11236         if(els){
11237             if(els instanceof Array){
11238                 this.elements = this.elements.concat(els);
11239             }else{
11240                 var yels = this.elements;
11241                 var index = yels.length-1;
11242                 for(var i = 0, len = els.length; i < len; i++) {
11243                     yels[++index] = els[i];
11244                 }
11245             }
11246         }
11247         return this;
11248     },
11249     invoke : function(fn, args){
11250         var els = this.elements;
11251         var el = this.el;
11252         for(var i = 0, len = els.length; i < len; i++) {
11253             el.dom = els[i];
11254                 Roo.Element.prototype[fn].apply(el, args);
11255         }
11256         return this;
11257     },
11258     /**
11259      * Returns a flyweight Element of the dom element object at the specified index
11260      * @param {Number} index
11261      * @return {Roo.Element}
11262      */
11263     item : function(index){
11264         if(!this.elements[index]){
11265             return null;
11266         }
11267         this.el.dom = this.elements[index];
11268         return this.el;
11269     },
11270
11271     // fixes scope with flyweight
11272     addListener : function(eventName, handler, scope, opt){
11273         var els = this.elements;
11274         for(var i = 0, len = els.length; i < len; i++) {
11275             Roo.EventManager.on(els[i], eventName, handler, scope || els[i], opt);
11276         }
11277         return this;
11278     },
11279
11280     /**
11281     * Calls the passed function passing (el, this, index) for each element in this composite. <b>The element
11282     * passed is the flyweight (shared) Roo.Element instance, so if you require a
11283     * a reference to the dom node, use el.dom.</b>
11284     * @param {Function} fn The function to call
11285     * @param {Object} scope (optional) The <i>this</i> object (defaults to the element)
11286     * @return {CompositeElement} this
11287     */
11288     each : function(fn, scope){
11289         var els = this.elements;
11290         var el = this.el;
11291         for(var i = 0, len = els.length; i < len; i++){
11292             el.dom = els[i];
11293                 if(fn.call(scope || el, el, this, i) === false){
11294                 break;
11295             }
11296         }
11297         return this;
11298     },
11299
11300     indexOf : function(el){
11301         return this.elements.indexOf(Roo.getDom(el));
11302     },
11303
11304     replaceElement : function(el, replacement, domReplace){
11305         var index = typeof el == 'number' ? el : this.indexOf(el);
11306         if(index !== -1){
11307             replacement = Roo.getDom(replacement);
11308             if(domReplace){
11309                 var d = this.elements[index];
11310                 d.parentNode.insertBefore(replacement, d);
11311                 d.parentNode.removeChild(d);
11312             }
11313             this.elements.splice(index, 1, replacement);
11314         }
11315         return this;
11316     }
11317 });
11318 Roo.CompositeElementLite.prototype.on = Roo.CompositeElementLite.prototype.addListener;
11319
11320 /*
11321  * Based on:
11322  * Ext JS Library 1.1.1
11323  * Copyright(c) 2006-2007, Ext JS, LLC.
11324  *
11325  * Originally Released Under LGPL - original licence link has changed is not relivant.
11326  *
11327  * Fork - LGPL
11328  * <script type="text/javascript">
11329  */
11330
11331  
11332
11333 /**
11334  * @class Roo.data.Connection
11335  * @extends Roo.util.Observable
11336  * The class encapsulates a connection to the page's originating domain, allowing requests to be made
11337  * either to a configured URL, or to a URL specified at request time.<br><br>
11338  * <p>
11339  * Requests made by this class are asynchronous, and will return immediately. No data from
11340  * the server will be available to the statement immediately following the {@link #request} call.
11341  * To process returned data, use a callback in the request options object, or an event listener.</p><br>
11342  * <p>
11343  * Note: If you are doing a file upload, you will not get a normal response object sent back to
11344  * your callback or event handler.  Since the upload is handled via in IFRAME, there is no XMLHttpRequest.
11345  * The response object is created using the innerHTML of the IFRAME's document as the responseText
11346  * property and, if present, the IFRAME's XML document as the responseXML property.</p><br>
11347  * This means that a valid XML or HTML document must be returned. If JSON data is required, it is suggested
11348  * that it be placed either inside a &lt;textarea> in an HTML document and retrieved from the responseText
11349  * using a regex, or inside a CDATA section in an XML document and retrieved from the responseXML using
11350  * standard DOM methods.
11351  * @constructor
11352  * @param {Object} config a configuration object.
11353  */
11354 Roo.data.Connection = function(config){
11355     Roo.apply(this, config);
11356     this.addEvents({
11357         /**
11358          * @event beforerequest
11359          * Fires before a network request is made to retrieve a data object.
11360          * @param {Connection} conn This Connection object.
11361          * @param {Object} options The options config object passed to the {@link #request} method.
11362          */
11363         "beforerequest" : true,
11364         /**
11365          * @event requestcomplete
11366          * Fires if the request was successfully completed.
11367          * @param {Connection} conn This Connection object.
11368          * @param {Object} response The XHR object containing the response data.
11369          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11370          * @param {Object} options The options config object passed to the {@link #request} method.
11371          */
11372         "requestcomplete" : true,
11373         /**
11374          * @event requestexception
11375          * Fires if an error HTTP status was returned from the server.
11376          * See {@link http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html} for details of HTTP status codes.
11377          * @param {Connection} conn This Connection object.
11378          * @param {Object} response The XHR object containing the response data.
11379          * See {@link http://www.w3.org/TR/XMLHttpRequest/} for details.
11380          * @param {Object} options The options config object passed to the {@link #request} method.
11381          */
11382         "requestexception" : true
11383     });
11384     Roo.data.Connection.superclass.constructor.call(this);
11385 };
11386
11387 Roo.extend(Roo.data.Connection, Roo.util.Observable, {
11388     /**
11389      * @cfg {String} url (Optional) The default URL to be used for requests to the server. (defaults to undefined)
11390      */
11391     /**
11392      * @cfg {Object} extraParams (Optional) An object containing properties which are used as
11393      * extra parameters to each request made by this object. (defaults to undefined)
11394      */
11395     /**
11396      * @cfg {Object} defaultHeaders (Optional) An object containing request headers which are added
11397      *  to each request made by this object. (defaults to undefined)
11398      */
11399     /**
11400      * @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)
11401      */
11402     /**
11403      * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11404      */
11405     timeout : 30000,
11406     /**
11407      * @cfg {Boolean} autoAbort (Optional) Whether this request should abort any pending requests. (defaults to false)
11408      * @type Boolean
11409      */
11410     autoAbort:false,
11411
11412     /**
11413      * @cfg {Boolean} disableCaching (Optional) True to add a unique cache-buster param to GET requests. (defaults to true)
11414      * @type Boolean
11415      */
11416     disableCaching: true,
11417
11418     /**
11419      * Sends an HTTP request to a remote server.
11420      * @param {Object} options An object which may contain the following properties:<ul>
11421      * <li><b>url</b> {String} (Optional) The URL to which to send the request. Defaults to configured URL</li>
11422      * <li><b>params</b> {Object/String/Function} (Optional) An object containing properties which are used as parameters to the
11423      * request, a url encoded string or a function to call to get either.</li>
11424      * <li><b>method</b> {String} (Optional) The HTTP method to use for the request. Defaults to the configured method, or
11425      * if no method was configured, "GET" if no parameters are being sent, and "POST" if parameters are being sent.</li>
11426      * <li><b>callback</b> {Function} (Optional) The function to be called upon receipt of the HTTP response.
11427      * The callback is called regardless of success or failure and is passed the following parameters:<ul>
11428      * <li>options {Object} The parameter to the request call.</li>
11429      * <li>success {Boolean} True if the request succeeded.</li>
11430      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11431      * </ul></li>
11432      * <li><b>success</b> {Function} (Optional) The function to be called upon success of the request.
11433      * The callback is passed the following parameters:<ul>
11434      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11435      * <li>options {Object} The parameter to the request call.</li>
11436      * </ul></li>
11437      * <li><b>failure</b> {Function} (Optional) The function to be called upon failure of the request.
11438      * The callback is passed the following parameters:<ul>
11439      * <li>response {Object} The XMLHttpRequest object containing the response data.</li>
11440      * <li>options {Object} The parameter to the request call.</li>
11441      * </ul></li>
11442      * <li><b>scope</b> {Object} (Optional) The scope in which to execute the callbacks: The "this" object
11443      * for the callback function. Defaults to the browser window.</li>
11444      * <li><b>form</b> {Object/String} (Optional) A form object or id to pull parameters from.</li>
11445      * <li><b>isUpload</b> {Boolean} (Optional) True if the form object is a file upload (will usually be automatically detected).</li>
11446      * <li><b>headers</b> {Object} (Optional) Request headers to set for the request.</li>
11447      * <li><b>xmlData</b> {Object} (Optional) XML document to use for the post. Note: This will be used instead of
11448      * params for the post data. Any params will be appended to the URL.</li>
11449      * <li><b>disableCaching</b> {Boolean} (Optional) True to add a unique cache-buster param to GET requests.</li>
11450      * </ul>
11451      * @return {Number} transactionId
11452      */
11453     request : function(o){
11454         if(this.fireEvent("beforerequest", this, o) !== false){
11455             var p = o.params;
11456
11457             if(typeof p == "function"){
11458                 p = p.call(o.scope||window, o);
11459             }
11460             if(typeof p == "object"){
11461                 p = Roo.urlEncode(o.params);
11462             }
11463             if(this.extraParams){
11464                 var extras = Roo.urlEncode(this.extraParams);
11465                 p = p ? (p + '&' + extras) : extras;
11466             }
11467
11468             var url = o.url || this.url;
11469             if(typeof url == 'function'){
11470                 url = url.call(o.scope||window, o);
11471             }
11472
11473             if(o.form){
11474                 var form = Roo.getDom(o.form);
11475                 url = url || form.action;
11476
11477                 var enctype = form.getAttribute("enctype");
11478                 if(o.isUpload || (enctype && enctype.toLowerCase() == 'multipart/form-data')){
11479                     return this.doFormUpload(o, p, url);
11480                 }
11481                 var f = Roo.lib.Ajax.serializeForm(form);
11482                 p = p ? (p + '&' + f) : f;
11483             }
11484
11485             var hs = o.headers;
11486             if(this.defaultHeaders){
11487                 hs = Roo.apply(hs || {}, this.defaultHeaders);
11488                 if(!o.headers){
11489                     o.headers = hs;
11490                 }
11491             }
11492
11493             var cb = {
11494                 success: this.handleResponse,
11495                 failure: this.handleFailure,
11496                 scope: this,
11497                 argument: {options: o},
11498                 timeout : o.timeout || this.timeout
11499             };
11500
11501             var method = o.method||this.method||(p ? "POST" : "GET");
11502
11503             if(method == 'GET' && (this.disableCaching && o.disableCaching !== false) || o.disableCaching === true){
11504                 url += (url.indexOf('?') != -1 ? '&' : '?') + '_dc=' + (new Date().getTime());
11505             }
11506
11507             if(typeof o.autoAbort == 'boolean'){ // options gets top priority
11508                 if(o.autoAbort){
11509                     this.abort();
11510                 }
11511             }else if(this.autoAbort !== false){
11512                 this.abort();
11513             }
11514
11515             if((method == 'GET' && p) || o.xmlData){
11516                 url += (url.indexOf('?') != -1 ? '&' : '?') + p;
11517                 p = '';
11518             }
11519             this.transId = Roo.lib.Ajax.request(method, url, cb, p, o);
11520             return this.transId;
11521         }else{
11522             Roo.callback(o.callback, o.scope, [o, null, null]);
11523             return null;
11524         }
11525     },
11526
11527     /**
11528      * Determine whether this object has a request outstanding.
11529      * @param {Number} transactionId (Optional) defaults to the last transaction
11530      * @return {Boolean} True if there is an outstanding request.
11531      */
11532     isLoading : function(transId){
11533         if(transId){
11534             return Roo.lib.Ajax.isCallInProgress(transId);
11535         }else{
11536             return this.transId ? true : false;
11537         }
11538     },
11539
11540     /**
11541      * Aborts any outstanding request.
11542      * @param {Number} transactionId (Optional) defaults to the last transaction
11543      */
11544     abort : function(transId){
11545         if(transId || this.isLoading()){
11546             Roo.lib.Ajax.abort(transId || this.transId);
11547         }
11548     },
11549
11550     // private
11551     handleResponse : function(response){
11552         this.transId = false;
11553         var options = response.argument.options;
11554         response.argument = options ? options.argument : null;
11555         this.fireEvent("requestcomplete", this, response, options);
11556         Roo.callback(options.success, options.scope, [response, options]);
11557         Roo.callback(options.callback, options.scope, [options, true, response]);
11558     },
11559
11560     // private
11561     handleFailure : function(response, e){
11562         this.transId = false;
11563         var options = response.argument.options;
11564         response.argument = options ? options.argument : null;
11565         this.fireEvent("requestexception", this, response, options, e);
11566         Roo.callback(options.failure, options.scope, [response, options]);
11567         Roo.callback(options.callback, options.scope, [options, false, response]);
11568     },
11569
11570     // private
11571     doFormUpload : function(o, ps, url){
11572         var id = Roo.id();
11573         var frame = document.createElement('iframe');
11574         frame.id = id;
11575         frame.name = id;
11576         frame.className = 'x-hidden';
11577         if(Roo.isIE){
11578             frame.src = Roo.SSL_SECURE_URL;
11579         }
11580         document.body.appendChild(frame);
11581
11582         if(Roo.isIE){
11583            document.frames[id].name = id;
11584         }
11585
11586         var form = Roo.getDom(o.form);
11587         form.target = id;
11588         form.method = 'POST';
11589         form.enctype = form.encoding = 'multipart/form-data';
11590         if(url){
11591             form.action = url;
11592         }
11593
11594         var hiddens, hd;
11595         if(ps){ // add dynamic params
11596             hiddens = [];
11597             ps = Roo.urlDecode(ps, false);
11598             for(var k in ps){
11599                 if(ps.hasOwnProperty(k)){
11600                     hd = document.createElement('input');
11601                     hd.type = 'hidden';
11602                     hd.name = k;
11603                     hd.value = ps[k];
11604                     form.appendChild(hd);
11605                     hiddens.push(hd);
11606                 }
11607             }
11608         }
11609
11610         function cb(){
11611             var r = {  // bogus response object
11612                 responseText : '',
11613                 responseXML : null
11614             };
11615
11616             r.argument = o ? o.argument : null;
11617
11618             try { //
11619                 var doc;
11620                 if(Roo.isIE){
11621                     doc = frame.contentWindow.document;
11622                 }else {
11623                     doc = (frame.contentDocument || window.frames[id].document);
11624                 }
11625                 if(doc && doc.body){
11626                     r.responseText = doc.body.innerHTML;
11627                 }
11628                 if(doc && doc.XMLDocument){
11629                     r.responseXML = doc.XMLDocument;
11630                 }else {
11631                     r.responseXML = doc;
11632                 }
11633             }
11634             catch(e) {
11635                 // ignore
11636             }
11637
11638             Roo.EventManager.removeListener(frame, 'load', cb, this);
11639
11640             this.fireEvent("requestcomplete", this, r, o);
11641             Roo.callback(o.success, o.scope, [r, o]);
11642             Roo.callback(o.callback, o.scope, [o, true, r]);
11643
11644             setTimeout(function(){document.body.removeChild(frame);}, 100);
11645         }
11646
11647         Roo.EventManager.on(frame, 'load', cb, this);
11648         form.submit();
11649
11650         if(hiddens){ // remove dynamic params
11651             for(var i = 0, len = hiddens.length; i < len; i++){
11652                 form.removeChild(hiddens[i]);
11653             }
11654         }
11655     }
11656 });
11657 /*
11658  * Based on:
11659  * Ext JS Library 1.1.1
11660  * Copyright(c) 2006-2007, Ext JS, LLC.
11661  *
11662  * Originally Released Under LGPL - original licence link has changed is not relivant.
11663  *
11664  * Fork - LGPL
11665  * <script type="text/javascript">
11666  */
11667  
11668 /**
11669  * Global Ajax request class.
11670  * 
11671  * @class Roo.Ajax
11672  * @extends Roo.data.Connection
11673  * @static
11674  * 
11675  * @cfg {String} url  The default URL to be used for requests to the server. (defaults to undefined)
11676  * @cfg {Object} extraParams  An object containing properties which are used as extra parameters to each request made by this object. (defaults to undefined)
11677  * @cfg {Object} defaultHeaders  An object containing request headers which are added to each request made by this object. (defaults to undefined)
11678  * @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)
11679  * @cfg {Number} timeout (Optional) The timeout in milliseconds to be used for requests. (defaults to 30000)
11680  * @cfg {Boolean} autoAbort (Optional) Whether a new request should abort any pending requests. (defaults to false)
11681  * @cfg {Boolean} disableCaching (Optional)   True to add a unique cache-buster param to GET requests. (defaults to true)
11682  */
11683 Roo.Ajax = new Roo.data.Connection({
11684     // fix up the docs
11685     /**
11686      * @scope Roo.Ajax
11687      * @type {Boolear} 
11688      */
11689     autoAbort : false,
11690
11691     /**
11692      * Serialize the passed form into a url encoded string
11693      * @scope Roo.Ajax
11694      * @param {String/HTMLElement} form
11695      * @return {String}
11696      */
11697     serializeForm : function(form){
11698         return Roo.lib.Ajax.serializeForm(form);
11699     }
11700 });/*
11701  * Based on:
11702  * Ext JS Library 1.1.1
11703  * Copyright(c) 2006-2007, Ext JS, LLC.
11704  *
11705  * Originally Released Under LGPL - original licence link has changed is not relivant.
11706  *
11707  * Fork - LGPL
11708  * <script type="text/javascript">
11709  */
11710
11711  
11712 /**
11713  * @class Roo.UpdateManager
11714  * @extends Roo.util.Observable
11715  * Provides AJAX-style update for Element object.<br><br>
11716  * Usage:<br>
11717  * <pre><code>
11718  * // Get it from a Roo.Element object
11719  * var el = Roo.get("foo");
11720  * var mgr = el.getUpdateManager();
11721  * mgr.update("http://myserver.com/index.php", "param1=1&amp;param2=2");
11722  * ...
11723  * mgr.formUpdate("myFormId", "http://myserver.com/index.php");
11724  * <br>
11725  * // or directly (returns the same UpdateManager instance)
11726  * var mgr = new Roo.UpdateManager("myElementId");
11727  * mgr.startAutoRefresh(60, "http://myserver.com/index.php");
11728  * mgr.on("update", myFcnNeedsToKnow);
11729  * <br>
11730    // short handed call directly from the element object
11731    Roo.get("foo").load({
11732         url: "bar.php",
11733         scripts:true,
11734         params: "for=bar",
11735         text: "Loading Foo..."
11736    });
11737  * </code></pre>
11738  * @constructor
11739  * Create new UpdateManager directly.
11740  * @param {String/HTMLElement/Roo.Element} el The element to update
11741  * @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).
11742  */
11743 Roo.UpdateManager = function(el, forceNew){
11744     el = Roo.get(el);
11745     if(!forceNew && el.updateManager){
11746         return el.updateManager;
11747     }
11748     /**
11749      * The Element object
11750      * @type Roo.Element
11751      */
11752     this.el = el;
11753     /**
11754      * Cached url to use for refreshes. Overwritten every time update() is called unless "discardUrl" param is set to true.
11755      * @type String
11756      */
11757     this.defaultUrl = null;
11758
11759     this.addEvents({
11760         /**
11761          * @event beforeupdate
11762          * Fired before an update is made, return false from your handler and the update is cancelled.
11763          * @param {Roo.Element} el
11764          * @param {String/Object/Function} url
11765          * @param {String/Object} params
11766          */
11767         "beforeupdate": true,
11768         /**
11769          * @event update
11770          * Fired after successful update is made.
11771          * @param {Roo.Element} el
11772          * @param {Object} oResponseObject The response Object
11773          */
11774         "update": true,
11775         /**
11776          * @event failure
11777          * Fired on update failure.
11778          * @param {Roo.Element} el
11779          * @param {Object} oResponseObject The response Object
11780          */
11781         "failure": true
11782     });
11783     var d = Roo.UpdateManager.defaults;
11784     /**
11785      * Blank page URL to use with SSL file uploads (Defaults to Roo.UpdateManager.defaults.sslBlankUrl or "about:blank").
11786      * @type String
11787      */
11788     this.sslBlankUrl = d.sslBlankUrl;
11789     /**
11790      * Whether to append unique parameter on get request to disable caching (Defaults to Roo.UpdateManager.defaults.disableCaching or false).
11791      * @type Boolean
11792      */
11793     this.disableCaching = d.disableCaching;
11794     /**
11795      * Text for loading indicator (Defaults to Roo.UpdateManager.defaults.indicatorText or '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
11796      * @type String
11797      */
11798     this.indicatorText = d.indicatorText;
11799     /**
11800      * Whether to show indicatorText when loading (Defaults to Roo.UpdateManager.defaults.showLoadIndicator or true).
11801      * @type String
11802      */
11803     this.showLoadIndicator = d.showLoadIndicator;
11804     /**
11805      * Timeout for requests or form posts in seconds (Defaults to Roo.UpdateManager.defaults.timeout or 30 seconds).
11806      * @type Number
11807      */
11808     this.timeout = d.timeout;
11809
11810     /**
11811      * True to process scripts in the output (Defaults to Roo.UpdateManager.defaults.loadScripts (false)).
11812      * @type Boolean
11813      */
11814     this.loadScripts = d.loadScripts;
11815
11816     /**
11817      * Transaction object of current executing transaction
11818      */
11819     this.transaction = null;
11820
11821     /**
11822      * @private
11823      */
11824     this.autoRefreshProcId = null;
11825     /**
11826      * Delegate for refresh() prebound to "this", use myUpdater.refreshDelegate.createCallback(arg1, arg2) to bind arguments
11827      * @type Function
11828      */
11829     this.refreshDelegate = this.refresh.createDelegate(this);
11830     /**
11831      * Delegate for update() prebound to "this", use myUpdater.updateDelegate.createCallback(arg1, arg2) to bind arguments
11832      * @type Function
11833      */
11834     this.updateDelegate = this.update.createDelegate(this);
11835     /**
11836      * Delegate for formUpdate() prebound to "this", use myUpdater.formUpdateDelegate.createCallback(arg1, arg2) to bind arguments
11837      * @type Function
11838      */
11839     this.formUpdateDelegate = this.formUpdate.createDelegate(this);
11840     /**
11841      * @private
11842      */
11843     this.successDelegate = this.processSuccess.createDelegate(this);
11844     /**
11845      * @private
11846      */
11847     this.failureDelegate = this.processFailure.createDelegate(this);
11848
11849     if(!this.renderer){
11850      /**
11851       * The renderer for this UpdateManager. Defaults to {@link Roo.UpdateManager.BasicRenderer}.
11852       */
11853     this.renderer = new Roo.UpdateManager.BasicRenderer();
11854     }
11855     
11856     Roo.UpdateManager.superclass.constructor.call(this);
11857 };
11858
11859 Roo.extend(Roo.UpdateManager, Roo.util.Observable, {
11860     /**
11861      * Get the Element this UpdateManager is bound to
11862      * @return {Roo.Element} The element
11863      */
11864     getEl : function(){
11865         return this.el;
11866     },
11867     /**
11868      * Performs an async request, updating this element with the response. If params are specified it uses POST, otherwise it uses GET.
11869      * @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:
11870 <pre><code>
11871 um.update({<br/>
11872     url: "your-url.php",<br/>
11873     params: {param1: "foo", param2: "bar"}, // or a URL encoded string<br/>
11874     callback: yourFunction,<br/>
11875     scope: yourObject, //(optional scope)  <br/>
11876     discardUrl: false, <br/>
11877     nocache: false,<br/>
11878     text: "Loading...",<br/>
11879     timeout: 30,<br/>
11880     scripts: false<br/>
11881 });
11882 </code></pre>
11883      * The only required property is url. The optional properties nocache, text and scripts
11884      * are shorthand for disableCaching, indicatorText and loadScripts and are used to set their associated property on this UpdateManager instance.
11885      * @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}
11886      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11887      * @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.
11888      */
11889     update : function(url, params, callback, discardUrl){
11890         if(this.fireEvent("beforeupdate", this.el, url, params) !== false){
11891             var method = this.method,
11892                 cfg;
11893             if(typeof url == "object"){ // must be config object
11894                 cfg = url;
11895                 url = cfg.url;
11896                 params = params || cfg.params;
11897                 callback = callback || cfg.callback;
11898                 discardUrl = discardUrl || cfg.discardUrl;
11899                 if(callback && cfg.scope){
11900                     callback = callback.createDelegate(cfg.scope);
11901                 }
11902                 if(typeof cfg.method != "undefined"){method = cfg.method;};
11903                 if(typeof cfg.nocache != "undefined"){this.disableCaching = cfg.nocache;};
11904                 if(typeof cfg.text != "undefined"){this.indicatorText = '<div class="loading-indicator">'+cfg.text+"</div>";};
11905                 if(typeof cfg.scripts != "undefined"){this.loadScripts = cfg.scripts;};
11906                 if(typeof cfg.timeout != "undefined"){this.timeout = cfg.timeout;};
11907             }
11908             this.showLoading();
11909             if(!discardUrl){
11910                 this.defaultUrl = url;
11911             }
11912             if(typeof url == "function"){
11913                 url = url.call(this);
11914             }
11915
11916             method = method || (params ? "POST" : "GET");
11917             if(method == "GET"){
11918                 url = this.prepareUrl(url);
11919             }
11920
11921             var o = Roo.apply(cfg ||{}, {
11922                 url : url,
11923                 params: params,
11924                 success: this.successDelegate,
11925                 failure: this.failureDelegate,
11926                 callback: undefined,
11927                 timeout: (this.timeout*1000),
11928                 argument: {"url": url, "form": null, "callback": callback, "params": params}
11929             });
11930             Roo.log("updated manager called with timeout of " + o.timeout);
11931             this.transaction = Roo.Ajax.request(o);
11932         }
11933     },
11934
11935     /**
11936      * 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.
11937      * Uses this.sslBlankUrl for SSL file uploads to prevent IE security warning.
11938      * @param {String/HTMLElement} form The form Id or form element
11939      * @param {String} url (optional) The url to pass the form to. If omitted the action attribute on the form will be used.
11940      * @param {Boolean} reset (optional) Whether to try to reset the form after the update
11941      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess, oResponse)
11942      */
11943     formUpdate : function(form, url, reset, callback){
11944         if(this.fireEvent("beforeupdate", this.el, form, url) !== false){
11945             if(typeof url == "function"){
11946                 url = url.call(this);
11947             }
11948             form = Roo.getDom(form);
11949             this.transaction = Roo.Ajax.request({
11950                 form: form,
11951                 url:url,
11952                 success: this.successDelegate,
11953                 failure: this.failureDelegate,
11954                 timeout: (this.timeout*1000),
11955                 argument: {"url": url, "form": form, "callback": callback, "reset": reset}
11956             });
11957             this.showLoading.defer(1, this);
11958         }
11959     },
11960
11961     /**
11962      * Refresh the element with the last used url or defaultUrl. If there is no url, it returns immediately
11963      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11964      */
11965     refresh : function(callback){
11966         if(this.defaultUrl == null){
11967             return;
11968         }
11969         this.update(this.defaultUrl, null, callback, true);
11970     },
11971
11972     /**
11973      * Set this element to auto refresh.
11974      * @param {Number} interval How often to update (in seconds).
11975      * @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)
11976      * @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}
11977      * @param {Function} callback (optional) Callback when transaction is complete - called with signature (oElement, bSuccess)
11978      * @param {Boolean} refreshNow (optional) Whether to execute the refresh now, or wait the interval
11979      */
11980     startAutoRefresh : function(interval, url, params, callback, refreshNow){
11981         if(refreshNow){
11982             this.update(url || this.defaultUrl, params, callback, true);
11983         }
11984         if(this.autoRefreshProcId){
11985             clearInterval(this.autoRefreshProcId);
11986         }
11987         this.autoRefreshProcId = setInterval(this.update.createDelegate(this, [url || this.defaultUrl, params, callback, true]), interval*1000);
11988     },
11989
11990     /**
11991      * Stop auto refresh on this element.
11992      */
11993      stopAutoRefresh : function(){
11994         if(this.autoRefreshProcId){
11995             clearInterval(this.autoRefreshProcId);
11996             delete this.autoRefreshProcId;
11997         }
11998     },
11999
12000     isAutoRefreshing : function(){
12001        return this.autoRefreshProcId ? true : false;
12002     },
12003     /**
12004      * Called to update the element to "Loading" state. Override to perform custom action.
12005      */
12006     showLoading : function(){
12007         if(this.showLoadIndicator){
12008             this.el.update(this.indicatorText);
12009         }
12010     },
12011
12012     /**
12013      * Adds unique parameter to query string if disableCaching = true
12014      * @private
12015      */
12016     prepareUrl : function(url){
12017         if(this.disableCaching){
12018             var append = "_dc=" + (new Date().getTime());
12019             if(url.indexOf("?") !== -1){
12020                 url += "&" + append;
12021             }else{
12022                 url += "?" + append;
12023             }
12024         }
12025         return url;
12026     },
12027
12028     /**
12029      * @private
12030      */
12031     processSuccess : function(response){
12032         this.transaction = null;
12033         if(response.argument.form && response.argument.reset){
12034             try{ // put in try/catch since some older FF releases had problems with this
12035                 response.argument.form.reset();
12036             }catch(e){}
12037         }
12038         if(this.loadScripts){
12039             this.renderer.render(this.el, response, this,
12040                 this.updateComplete.createDelegate(this, [response]));
12041         }else{
12042             this.renderer.render(this.el, response, this);
12043             this.updateComplete(response);
12044         }
12045     },
12046
12047     updateComplete : function(response){
12048         this.fireEvent("update", this.el, response);
12049         if(typeof response.argument.callback == "function"){
12050             response.argument.callback(this.el, true, response);
12051         }
12052     },
12053
12054     /**
12055      * @private
12056      */
12057     processFailure : function(response){
12058         this.transaction = null;
12059         this.fireEvent("failure", this.el, response);
12060         if(typeof response.argument.callback == "function"){
12061             response.argument.callback(this.el, false, response);
12062         }
12063     },
12064
12065     /**
12066      * Set the content renderer for this UpdateManager. See {@link Roo.UpdateManager.BasicRenderer#render} for more details.
12067      * @param {Object} renderer The object implementing the render() method
12068      */
12069     setRenderer : function(renderer){
12070         this.renderer = renderer;
12071     },
12072
12073     getRenderer : function(){
12074        return this.renderer;
12075     },
12076
12077     /**
12078      * Set the defaultUrl used for updates
12079      * @param {String/Function} defaultUrl The url or a function to call to get the url
12080      */
12081     setDefaultUrl : function(defaultUrl){
12082         this.defaultUrl = defaultUrl;
12083     },
12084
12085     /**
12086      * Aborts the executing transaction
12087      */
12088     abort : function(){
12089         if(this.transaction){
12090             Roo.Ajax.abort(this.transaction);
12091         }
12092     },
12093
12094     /**
12095      * Returns true if an update is in progress
12096      * @return {Boolean}
12097      */
12098     isUpdating : function(){
12099         if(this.transaction){
12100             return Roo.Ajax.isLoading(this.transaction);
12101         }
12102         return false;
12103     }
12104 });
12105
12106 /**
12107  * @class Roo.UpdateManager.defaults
12108  * @static (not really - but it helps the doc tool)
12109  * The defaults collection enables customizing the default properties of UpdateManager
12110  */
12111    Roo.UpdateManager.defaults = {
12112        /**
12113          * Timeout for requests or form posts in seconds (Defaults 30 seconds).
12114          * @type Number
12115          */
12116          timeout : 30,
12117
12118          /**
12119          * True to process scripts by default (Defaults to false).
12120          * @type Boolean
12121          */
12122         loadScripts : false,
12123
12124         /**
12125         * Blank page URL to use with SSL file uploads (Defaults to "javascript:false").
12126         * @type String
12127         */
12128         sslBlankUrl : (Roo.SSL_SECURE_URL || "javascript:false"),
12129         /**
12130          * Whether to append unique parameter on get request to disable caching (Defaults to false).
12131          * @type Boolean
12132          */
12133         disableCaching : false,
12134         /**
12135          * Whether to show indicatorText when loading (Defaults to true).
12136          * @type Boolean
12137          */
12138         showLoadIndicator : true,
12139         /**
12140          * Text for loading indicator (Defaults to '&lt;div class="loading-indicator"&gt;Loading...&lt;/div&gt;').
12141          * @type String
12142          */
12143         indicatorText : '<div class="loading-indicator">Loading...</div>'
12144    };
12145
12146 /**
12147  * Static convenience method. This method is deprecated in favor of el.load({url:'foo.php', ...}).
12148  *Usage:
12149  * <pre><code>Roo.UpdateManager.updateElement("my-div", "stuff.php");</code></pre>
12150  * @param {String/HTMLElement/Roo.Element} el The element to update
12151  * @param {String} url The url
12152  * @param {String/Object} params (optional) Url encoded param string or an object of name/value pairs
12153  * @param {Object} options (optional) A config object with any of the UpdateManager properties you want to set - for example: {disableCaching:true, indicatorText: "Loading data..."}
12154  * @static
12155  * @deprecated
12156  * @member Roo.UpdateManager
12157  */
12158 Roo.UpdateManager.updateElement = function(el, url, params, options){
12159     var um = Roo.get(el, true).getUpdateManager();
12160     Roo.apply(um, options);
12161     um.update(url, params, options ? options.callback : null);
12162 };
12163 // alias for backwards compat
12164 Roo.UpdateManager.update = Roo.UpdateManager.updateElement;
12165 /**
12166  * @class Roo.UpdateManager.BasicRenderer
12167  * Default Content renderer. Updates the elements innerHTML with the responseText.
12168  */
12169 Roo.UpdateManager.BasicRenderer = function(){};
12170
12171 Roo.UpdateManager.BasicRenderer.prototype = {
12172     /**
12173      * This is called when the transaction is completed and it's time to update the element - The BasicRenderer
12174      * updates the elements innerHTML with the responseText - To perform a custom render (i.e. XML or JSON processing),
12175      * create an object with a "render(el, response)" method and pass it to setRenderer on the UpdateManager.
12176      * @param {Roo.Element} el The element being rendered
12177      * @param {Object} response The YUI Connect response object
12178      * @param {UpdateManager} updateManager The calling update manager
12179      * @param {Function} callback A callback that will need to be called if loadScripts is true on the UpdateManager
12180      */
12181      render : function(el, response, updateManager, callback){
12182         el.update(response.responseText, updateManager.loadScripts, callback);
12183     }
12184 };
12185 /*
12186  * Based on:
12187  * Roo JS
12188  * (c)) Alan Knowles
12189  * Licence : LGPL
12190  */
12191
12192
12193 /**
12194  * @class Roo.DomTemplate
12195  * @extends Roo.Template
12196  * An effort at a dom based template engine..
12197  *
12198  * Similar to XTemplate, except it uses dom parsing to create the template..
12199  *
12200  * Supported features:
12201  *
12202  *  Tags:
12203
12204 <pre><code>
12205       {a_variable} - output encoded.
12206       {a_variable.format:("Y-m-d")} - call a method on the variable
12207       {a_variable:raw} - unencoded output
12208       {a_variable:toFixed(1,2)} - Roo.util.Format."toFixed"
12209       {a_variable:this.method_on_template(...)} - call a method on the template object.
12210  
12211 </code></pre>
12212  *  The tpl tag:
12213 <pre><code>
12214         &lt;div roo-for="a_variable or condition.."&gt;&lt;/div&gt;
12215         &lt;div roo-if="a_variable or condition"&gt;&lt;/div&gt;
12216         &lt;div roo-exec="some javascript"&gt;&lt;/div&gt;
12217         &lt;div roo-name="named_template"&gt;&lt;/div&gt; 
12218   
12219 </code></pre>
12220  *      
12221  */
12222 Roo.DomTemplate = function()
12223 {
12224      Roo.DomTemplate.superclass.constructor.apply(this, arguments);
12225      if (this.html) {
12226         this.compile();
12227      }
12228 };
12229
12230
12231 Roo.extend(Roo.DomTemplate, Roo.Template, {
12232     /**
12233      * id counter for sub templates.
12234      */
12235     id : 0,
12236     /**
12237      * flag to indicate if dom parser is inside a pre,
12238      * it will strip whitespace if not.
12239      */
12240     inPre : false,
12241     
12242     /**
12243      * The various sub templates
12244      */
12245     tpls : false,
12246     
12247     
12248     
12249     /**
12250      *
12251      * basic tag replacing syntax
12252      * WORD:WORD()
12253      *
12254      * // you can fake an object call by doing this
12255      *  x.t:(test,tesT) 
12256      * 
12257      */
12258     re : /(\{|\%7B)([\w-\.]+)(?:\:([\w\.]*)(?:\(([^)]*?)?\))?)?(\}|\%7D)/g,
12259     //re : /\{([\w-\.]+)(?:\:([\w\.]*)(?:\((.*?)?\))?)?\}/g,
12260     
12261     iterChild : function (node, method) {
12262         
12263         var oldPre = this.inPre;
12264         if (node.tagName == 'PRE') {
12265             this.inPre = true;
12266         }
12267         for( var i = 0; i < node.childNodes.length; i++) {
12268             method.call(this, node.childNodes[i]);
12269         }
12270         this.inPre = oldPre;
12271     },
12272     
12273     
12274     
12275     /**
12276      * compile the template
12277      *
12278      * This is not recursive, so I'm not sure how nested templates are really going to be handled..
12279      *
12280      */
12281     compile: function()
12282     {
12283         var s = this.html;
12284         
12285         // covert the html into DOM...
12286         var doc = false;
12287         var div =false;
12288         try {
12289             doc = document.implementation.createHTMLDocument("");
12290             doc.documentElement.innerHTML =   this.html  ;
12291             div = doc.documentElement;
12292         } catch (e) {
12293             // old IE... - nasty -- it causes all sorts of issues.. with
12294             // images getting pulled from server..
12295             div = document.createElement('div');
12296             div.innerHTML = this.html;
12297         }
12298         //doc.documentElement.innerHTML = htmlBody
12299          
12300         
12301         
12302         this.tpls = [];
12303         var _t = this;
12304         this.iterChild(div, function(n) {_t.compileNode(n, true); });
12305         
12306         var tpls = this.tpls;
12307         
12308         // create a top level template from the snippet..
12309         
12310         //Roo.log(div.innerHTML);
12311         
12312         var tpl = {
12313             uid : 'master',
12314             id : this.id++,
12315             attr : false,
12316             value : false,
12317             body : div.innerHTML,
12318             
12319             forCall : false,
12320             execCall : false,
12321             dom : div,
12322             isTop : true
12323             
12324         };
12325         tpls.unshift(tpl);
12326         
12327         
12328         // compile them...
12329         this.tpls = [];
12330         Roo.each(tpls, function(tp){
12331             this.compileTpl(tp);
12332             this.tpls[tp.id] = tp;
12333         }, this);
12334         
12335         this.master = tpls[0];
12336         return this;
12337         
12338         
12339     },
12340     
12341     compileNode : function(node, istop) {
12342         // test for
12343         //Roo.log(node);
12344         
12345         
12346         // skip anything not a tag..
12347         if (node.nodeType != 1) {
12348             if (node.nodeType == 3 && !this.inPre) {
12349                 // reduce white space..
12350                 node.nodeValue = node.nodeValue.replace(/\s+/g, ' '); 
12351                 
12352             }
12353             return;
12354         }
12355         
12356         var tpl = {
12357             uid : false,
12358             id : false,
12359             attr : false,
12360             value : false,
12361             body : '',
12362             
12363             forCall : false,
12364             execCall : false,
12365             dom : false,
12366             isTop : istop
12367             
12368             
12369         };
12370         
12371         
12372         switch(true) {
12373             case (node.hasAttribute('roo-for')): tpl.attr = 'for'; break;
12374             case (node.hasAttribute('roo-if')): tpl.attr = 'if'; break;
12375             case (node.hasAttribute('roo-name')): tpl.attr = 'name'; break;
12376             case (node.hasAttribute('roo-exec')): tpl.attr = 'exec'; break;
12377             // no default..
12378         }
12379         
12380         
12381         if (!tpl.attr) {
12382             // just itterate children..
12383             this.iterChild(node,this.compileNode);
12384             return;
12385         }
12386         tpl.uid = this.id++;
12387         tpl.value = node.getAttribute('roo-' +  tpl.attr);
12388         node.removeAttribute('roo-'+ tpl.attr);
12389         if (tpl.attr != 'name') {
12390             var placeholder = document.createTextNode('{domtpl' + tpl.uid + '}');
12391             node.parentNode.replaceChild(placeholder,  node);
12392         } else {
12393             
12394             var placeholder =  document.createElement('span');
12395             placeholder.className = 'roo-tpl-' + tpl.value;
12396             node.parentNode.replaceChild(placeholder,  node);
12397         }
12398         
12399         // parent now sees '{domtplXXXX}
12400         this.iterChild(node,this.compileNode);
12401         
12402         // we should now have node body...
12403         var div = document.createElement('div');
12404         div.appendChild(node);
12405         tpl.dom = node;
12406         // this has the unfortunate side effect of converting tagged attributes
12407         // eg. href="{...}" into %7C...%7D
12408         // this has been fixed by searching for those combo's although it's a bit hacky..
12409         
12410         
12411         tpl.body = div.innerHTML;
12412         
12413         
12414          
12415         tpl.id = tpl.uid;
12416         switch(tpl.attr) {
12417             case 'for' :
12418                 switch (tpl.value) {
12419                     case '.':  tpl.forCall = new Function('values', 'parent', 'with(values){ return values; }'); break;
12420                     case '..': tpl.forCall= new Function('values', 'parent', 'with(values){ return parent; }'); break;
12421                     default:   tpl.forCall= new Function('values', 'parent', 'with(values){ return '+tpl.value+'; }');
12422                 }
12423                 break;
12424             
12425             case 'exec':
12426                 tpl.execCall = new Function('values', 'parent', 'with(values){ '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12427                 break;
12428             
12429             case 'if':     
12430                 tpl.ifCall = new Function('values', 'parent', 'with(values){ return '+(Roo.util.Format.htmlDecode(tpl.value))+'; }');
12431                 break;
12432             
12433             case 'name':
12434                 tpl.id  = tpl.value; // replace non characters???
12435                 break;
12436             
12437         }
12438         
12439         
12440         this.tpls.push(tpl);
12441         
12442         
12443         
12444     },
12445     
12446     
12447     
12448     
12449     /**
12450      * Compile a segment of the template into a 'sub-template'
12451      *
12452      * 
12453      * 
12454      *
12455      */
12456     compileTpl : function(tpl)
12457     {
12458         var fm = Roo.util.Format;
12459         var useF = this.disableFormats !== true;
12460         
12461         var sep = Roo.isGecko ? "+\n" : ",\n";
12462         
12463         var undef = function(str) {
12464             Roo.debug && Roo.log("Property not found :"  + str);
12465             return '';
12466         };
12467           
12468         //Roo.log(tpl.body);
12469         
12470         
12471         
12472         var fn = function(m, lbrace, name, format, args)
12473         {
12474             //Roo.log("ARGS");
12475             //Roo.log(arguments);
12476             args = args ? args.replace(/\\'/g,"'") : args;
12477             //["{TEST:(a,b,c)}", "TEST", "", "a,b,c", 0, "{TEST:(a,b,c)}"]
12478             if (typeof(format) == 'undefined') {
12479                 format =  'htmlEncode'; 
12480             }
12481             if (format == 'raw' ) {
12482                 format = false;
12483             }
12484             
12485             if(name.substr(0, 6) == 'domtpl'){
12486                 return "'"+ sep +'this.applySubTemplate('+name.substr(6)+', values, parent)'+sep+"'";
12487             }
12488             
12489             // build an array of options to determine if value is undefined..
12490             
12491             // basically get 'xxxx.yyyy' then do
12492             // (typeof(xxxx) == 'undefined' || typeof(xxx.yyyy) == 'undefined') ?
12493             //    (function () { Roo.log("Property not found"); return ''; })() :
12494             //    ......
12495             
12496             var udef_ar = [];
12497             var lookfor = '';
12498             Roo.each(name.split('.'), function(st) {
12499                 lookfor += (lookfor.length ? '.': '') + st;
12500                 udef_ar.push(  "(typeof(" + lookfor + ") == 'undefined')"  );
12501             });
12502             
12503             var udef_st = '((' + udef_ar.join(" || ") +") ? undef('" + name + "') : "; // .. needs )
12504             
12505             
12506             if(format && useF){
12507                 
12508                 args = args ? ',' + args : "";
12509                  
12510                 if(format.substr(0, 5) != "this."){
12511                     format = "fm." + format + '(';
12512                 }else{
12513                     format = 'this.call("'+ format.substr(5) + '", ';
12514                     args = ", values";
12515                 }
12516                 
12517                 return "'"+ sep +   udef_st   +    format + name + args + "))"+sep+"'";
12518             }
12519              
12520             if (args && args.length) {
12521                 // called with xxyx.yuu:(test,test)
12522                 // change to ()
12523                 return "'"+ sep + udef_st  + name + '(' +  args + "))"+sep+"'";
12524             }
12525             // raw.. - :raw modifier..
12526             return "'"+ sep + udef_st  + name + ")"+sep+"'";
12527             
12528         };
12529         var body;
12530         // branched to use + in gecko and [].join() in others
12531         if(Roo.isGecko){
12532             body = "tpl.compiled = function(values, parent){  with(values) { return '" +
12533                    tpl.body.replace(/(\r\n|\n)/g, '\\n').replace(/'/g, "\\'").replace(this.re, fn) +
12534                     "';};};";
12535         }else{
12536             body = ["tpl.compiled = function(values, parent){  with (values) { return ['"];
12537             body.push(tpl.body.replace(/(\r\n|\n)/g,
12538                             '\\n').replace(/'/g, "\\'").replace(this.re, fn));
12539             body.push("'].join('');};};");
12540             body = body.join('');
12541         }
12542         
12543         Roo.debug && Roo.log(body.replace(/\\n/,'\n'));
12544        
12545         /** eval:var:tpl eval:var:fm eval:var:useF eval:var:undef  */
12546         eval(body);
12547         
12548         return this;
12549     },
12550      
12551     /**
12552      * same as applyTemplate, except it's done to one of the subTemplates
12553      * when using named templates, you can do:
12554      *
12555      * var str = pl.applySubTemplate('your-name', values);
12556      *
12557      * 
12558      * @param {Number} id of the template
12559      * @param {Object} values to apply to template
12560      * @param {Object} parent (normaly the instance of this object)
12561      */
12562     applySubTemplate : function(id, values, parent)
12563     {
12564         
12565         
12566         var t = this.tpls[id];
12567         
12568         
12569         try { 
12570             if(t.ifCall && !t.ifCall.call(this, values, parent)){
12571                 Roo.debug && Roo.log('if call on ' + t.value + ' return false');
12572                 return '';
12573             }
12574         } catch(e) {
12575             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-if="' + t.value + '" - ' + e.toString());
12576             Roo.log(values);
12577           
12578             return '';
12579         }
12580         try { 
12581             
12582             if(t.execCall && t.execCall.call(this, values, parent)){
12583                 return '';
12584             }
12585         } catch(e) {
12586             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12587             Roo.log(values);
12588             return '';
12589         }
12590         
12591         try {
12592             var vs = t.forCall ? t.forCall.call(this, values, parent) : values;
12593             parent = t.target ? values : parent;
12594             if(t.forCall && vs instanceof Array){
12595                 var buf = [];
12596                 for(var i = 0, len = vs.length; i < len; i++){
12597                     try {
12598                         buf[buf.length] = t.compiled.call(this, vs[i], parent);
12599                     } catch (e) {
12600                         Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12601                         Roo.log(e.body);
12602                         //Roo.log(t.compiled);
12603                         Roo.log(vs[i]);
12604                     }   
12605                 }
12606                 return buf.join('');
12607             }
12608         } catch (e) {
12609             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on roo-for="' + t.value + '" - ' + e.toString());
12610             Roo.log(values);
12611             return '';
12612         }
12613         try {
12614             return t.compiled.call(this, vs, parent);
12615         } catch (e) {
12616             Roo.log('Xtemplate.applySubTemplate('+ id+ '): Exception thrown on body="' + t.value + '" - ' + e.toString());
12617             Roo.log(e.body);
12618             //Roo.log(t.compiled);
12619             Roo.log(values);
12620             return '';
12621         }
12622     },
12623
12624    
12625
12626     applyTemplate : function(values){
12627         return this.master.compiled.call(this, values, {});
12628         //var s = this.subs;
12629     },
12630
12631     apply : function(){
12632         return this.applyTemplate.apply(this, arguments);
12633     }
12634
12635  });
12636
12637 Roo.DomTemplate.from = function(el){
12638     el = Roo.getDom(el);
12639     return new Roo.Domtemplate(el.value || el.innerHTML);
12640 };/*
12641  * Based on:
12642  * Ext JS Library 1.1.1
12643  * Copyright(c) 2006-2007, Ext JS, LLC.
12644  *
12645  * Originally Released Under LGPL - original licence link has changed is not relivant.
12646  *
12647  * Fork - LGPL
12648  * <script type="text/javascript">
12649  */
12650
12651 /**
12652  * @class Roo.util.DelayedTask
12653  * Provides a convenient method of performing setTimeout where a new
12654  * timeout cancels the old timeout. An example would be performing validation on a keypress.
12655  * You can use this class to buffer
12656  * the keypress events for a certain number of milliseconds, and perform only if they stop
12657  * for that amount of time.
12658  * @constructor The parameters to this constructor serve as defaults and are not required.
12659  * @param {Function} fn (optional) The default function to timeout
12660  * @param {Object} scope (optional) The default scope of that timeout
12661  * @param {Array} args (optional) The default Array of arguments
12662  */
12663 Roo.util.DelayedTask = function(fn, scope, args){
12664     var id = null, d, t;
12665
12666     var call = function(){
12667         var now = new Date().getTime();
12668         if(now - t >= d){
12669             clearInterval(id);
12670             id = null;
12671             fn.apply(scope, args || []);
12672         }
12673     };
12674     /**
12675      * Cancels any pending timeout and queues a new one
12676      * @param {Number} delay The milliseconds to delay
12677      * @param {Function} newFn (optional) Overrides function passed to constructor
12678      * @param {Object} newScope (optional) Overrides scope passed to constructor
12679      * @param {Array} newArgs (optional) Overrides args passed to constructor
12680      */
12681     this.delay = function(delay, newFn, newScope, newArgs){
12682         if(id && delay != d){
12683             this.cancel();
12684         }
12685         d = delay;
12686         t = new Date().getTime();
12687         fn = newFn || fn;
12688         scope = newScope || scope;
12689         args = newArgs || args;
12690         if(!id){
12691             id = setInterval(call, d);
12692         }
12693     };
12694
12695     /**
12696      * Cancel the last queued timeout
12697      */
12698     this.cancel = function(){
12699         if(id){
12700             clearInterval(id);
12701             id = null;
12702         }
12703     };
12704 };/*
12705  * Based on:
12706  * Ext JS Library 1.1.1
12707  * Copyright(c) 2006-2007, Ext JS, LLC.
12708  *
12709  * Originally Released Under LGPL - original licence link has changed is not relivant.
12710  *
12711  * Fork - LGPL
12712  * <script type="text/javascript">
12713  */
12714  
12715  
12716 Roo.util.TaskRunner = function(interval){
12717     interval = interval || 10;
12718     var tasks = [], removeQueue = [];
12719     var id = 0;
12720     var running = false;
12721
12722     var stopThread = function(){
12723         running = false;
12724         clearInterval(id);
12725         id = 0;
12726     };
12727
12728     var startThread = function(){
12729         if(!running){
12730             running = true;
12731             id = setInterval(runTasks, interval);
12732         }
12733     };
12734
12735     var removeTask = function(task){
12736         removeQueue.push(task);
12737         if(task.onStop){
12738             task.onStop();
12739         }
12740     };
12741
12742     var runTasks = function(){
12743         if(removeQueue.length > 0){
12744             for(var i = 0, len = removeQueue.length; i < len; i++){
12745                 tasks.remove(removeQueue[i]);
12746             }
12747             removeQueue = [];
12748             if(tasks.length < 1){
12749                 stopThread();
12750                 return;
12751             }
12752         }
12753         var now = new Date().getTime();
12754         for(var i = 0, len = tasks.length; i < len; ++i){
12755             var t = tasks[i];
12756             var itime = now - t.taskRunTime;
12757             if(t.interval <= itime){
12758                 var rt = t.run.apply(t.scope || t, t.args || [++t.taskRunCount]);
12759                 t.taskRunTime = now;
12760                 if(rt === false || t.taskRunCount === t.repeat){
12761                     removeTask(t);
12762                     return;
12763                 }
12764             }
12765             if(t.duration && t.duration <= (now - t.taskStartTime)){
12766                 removeTask(t);
12767             }
12768         }
12769     };
12770
12771     /**
12772      * Queues a new task.
12773      * @param {Object} task
12774      */
12775     this.start = function(task){
12776         tasks.push(task);
12777         task.taskStartTime = new Date().getTime();
12778         task.taskRunTime = 0;
12779         task.taskRunCount = 0;
12780         startThread();
12781         return task;
12782     };
12783
12784     this.stop = function(task){
12785         removeTask(task);
12786         return task;
12787     };
12788
12789     this.stopAll = function(){
12790         stopThread();
12791         for(var i = 0, len = tasks.length; i < len; i++){
12792             if(tasks[i].onStop){
12793                 tasks[i].onStop();
12794             }
12795         }
12796         tasks = [];
12797         removeQueue = [];
12798     };
12799 };
12800
12801 Roo.TaskMgr = new Roo.util.TaskRunner();/*
12802  * Based on:
12803  * Ext JS Library 1.1.1
12804  * Copyright(c) 2006-2007, Ext JS, LLC.
12805  *
12806  * Originally Released Under LGPL - original licence link has changed is not relivant.
12807  *
12808  * Fork - LGPL
12809  * <script type="text/javascript">
12810  */
12811
12812  
12813 /**
12814  * @class Roo.util.MixedCollection
12815  * @extends Roo.util.Observable
12816  * A Collection class that maintains both numeric indexes and keys and exposes events.
12817  * @constructor
12818  * @param {Boolean} allowFunctions True if the addAll function should add function references to the
12819  * collection (defaults to false)
12820  * @param {Function} keyFn A function that can accept an item of the type(s) stored in this MixedCollection
12821  * and return the key value for that item.  This is used when available to look up the key on items that
12822  * were passed without an explicit key parameter to a MixedCollection method.  Passing this parameter is
12823  * equivalent to providing an implementation for the {@link #getKey} method.
12824  */
12825 Roo.util.MixedCollection = function(allowFunctions, keyFn){
12826     this.items = [];
12827     this.map = {};
12828     this.keys = [];
12829     this.length = 0;
12830     this.addEvents({
12831         /**
12832          * @event clear
12833          * Fires when the collection is cleared.
12834          */
12835         "clear" : true,
12836         /**
12837          * @event add
12838          * Fires when an item is added to the collection.
12839          * @param {Number} index The index at which the item was added.
12840          * @param {Object} o The item added.
12841          * @param {String} key The key associated with the added item.
12842          */
12843         "add" : true,
12844         /**
12845          * @event replace
12846          * Fires when an item is replaced in the collection.
12847          * @param {String} key he key associated with the new added.
12848          * @param {Object} old The item being replaced.
12849          * @param {Object} new The new item.
12850          */
12851         "replace" : true,
12852         /**
12853          * @event remove
12854          * Fires when an item is removed from the collection.
12855          * @param {Object} o The item being removed.
12856          * @param {String} key (optional) The key associated with the removed item.
12857          */
12858         "remove" : true,
12859         "sort" : true
12860     });
12861     this.allowFunctions = allowFunctions === true;
12862     if(keyFn){
12863         this.getKey = keyFn;
12864     }
12865     Roo.util.MixedCollection.superclass.constructor.call(this);
12866 };
12867
12868 Roo.extend(Roo.util.MixedCollection, Roo.util.Observable, {
12869     allowFunctions : false,
12870     
12871 /**
12872  * Adds an item to the collection.
12873  * @param {String} key The key to associate with the item
12874  * @param {Object} o The item to add.
12875  * @return {Object} The item added.
12876  */
12877     add : function(key, o){
12878         if(arguments.length == 1){
12879             o = arguments[0];
12880             key = this.getKey(o);
12881         }
12882         if(typeof key == "undefined" || key === null){
12883             this.length++;
12884             this.items.push(o);
12885             this.keys.push(null);
12886         }else{
12887             var old = this.map[key];
12888             if(old){
12889                 return this.replace(key, o);
12890             }
12891             this.length++;
12892             this.items.push(o);
12893             this.map[key] = o;
12894             this.keys.push(key);
12895         }
12896         this.fireEvent("add", this.length-1, o, key);
12897         return o;
12898     },
12899        
12900 /**
12901   * MixedCollection has a generic way to fetch keys if you implement getKey.
12902 <pre><code>
12903 // normal way
12904 var mc = new Roo.util.MixedCollection();
12905 mc.add(someEl.dom.id, someEl);
12906 mc.add(otherEl.dom.id, otherEl);
12907 //and so on
12908
12909 // using getKey
12910 var mc = new Roo.util.MixedCollection();
12911 mc.getKey = function(el){
12912    return el.dom.id;
12913 };
12914 mc.add(someEl);
12915 mc.add(otherEl);
12916
12917 // or via the constructor
12918 var mc = new Roo.util.MixedCollection(false, function(el){
12919    return el.dom.id;
12920 });
12921 mc.add(someEl);
12922 mc.add(otherEl);
12923 </code></pre>
12924  * @param o {Object} The item for which to find the key.
12925  * @return {Object} The key for the passed item.
12926  */
12927     getKey : function(o){
12928          return o.id; 
12929     },
12930    
12931 /**
12932  * Replaces an item in the collection.
12933  * @param {String} key The key associated with the item to replace, or the item to replace.
12934  * @param o {Object} o (optional) If the first parameter passed was a key, the item to associate with that key.
12935  * @return {Object}  The new item.
12936  */
12937     replace : function(key, o){
12938         if(arguments.length == 1){
12939             o = arguments[0];
12940             key = this.getKey(o);
12941         }
12942         var old = this.item(key);
12943         if(typeof key == "undefined" || key === null || typeof old == "undefined"){
12944              return this.add(key, o);
12945         }
12946         var index = this.indexOfKey(key);
12947         this.items[index] = o;
12948         this.map[key] = o;
12949         this.fireEvent("replace", key, old, o);
12950         return o;
12951     },
12952    
12953 /**
12954  * Adds all elements of an Array or an Object to the collection.
12955  * @param {Object/Array} objs An Object containing properties which will be added to the collection, or
12956  * an Array of values, each of which are added to the collection.
12957  */
12958     addAll : function(objs){
12959         if(arguments.length > 1 || objs instanceof Array){
12960             var args = arguments.length > 1 ? arguments : objs;
12961             for(var i = 0, len = args.length; i < len; i++){
12962                 this.add(args[i]);
12963             }
12964         }else{
12965             for(var key in objs){
12966                 if(this.allowFunctions || typeof objs[key] != "function"){
12967                     this.add(key, objs[key]);
12968                 }
12969             }
12970         }
12971     },
12972    
12973 /**
12974  * Executes the specified function once for every item in the collection, passing each
12975  * item as the first and only parameter. returning false from the function will stop the iteration.
12976  * @param {Function} fn The function to execute for each item.
12977  * @param {Object} scope (optional) The scope in which to execute the function.
12978  */
12979     each : function(fn, scope){
12980         var items = [].concat(this.items); // each safe for removal
12981         for(var i = 0, len = items.length; i < len; i++){
12982             if(fn.call(scope || items[i], items[i], i, len) === false){
12983                 break;
12984             }
12985         }
12986     },
12987    
12988 /**
12989  * Executes the specified function once for every key in the collection, passing each
12990  * key, and its associated item as the first two parameters.
12991  * @param {Function} fn The function to execute for each item.
12992  * @param {Object} scope (optional) The scope in which to execute the function.
12993  */
12994     eachKey : function(fn, scope){
12995         for(var i = 0, len = this.keys.length; i < len; i++){
12996             fn.call(scope || window, this.keys[i], this.items[i], i, len);
12997         }
12998     },
12999    
13000 /**
13001  * Returns the first item in the collection which elicits a true return value from the
13002  * passed selection function.
13003  * @param {Function} fn The selection function to execute for each item.
13004  * @param {Object} scope (optional) The scope in which to execute the function.
13005  * @return {Object} The first item in the collection which returned true from the selection function.
13006  */
13007     find : function(fn, scope){
13008         for(var i = 0, len = this.items.length; i < len; i++){
13009             if(fn.call(scope || window, this.items[i], this.keys[i])){
13010                 return this.items[i];
13011             }
13012         }
13013         return null;
13014     },
13015    
13016 /**
13017  * Inserts an item at the specified index in the collection.
13018  * @param {Number} index The index to insert the item at.
13019  * @param {String} key The key to associate with the new item, or the item itself.
13020  * @param {Object} o  (optional) If the second parameter was a key, the new item.
13021  * @return {Object} The item inserted.
13022  */
13023     insert : function(index, key, o){
13024         if(arguments.length == 2){
13025             o = arguments[1];
13026             key = this.getKey(o);
13027         }
13028         if(index >= this.length){
13029             return this.add(key, o);
13030         }
13031         this.length++;
13032         this.items.splice(index, 0, o);
13033         if(typeof key != "undefined" && key != null){
13034             this.map[key] = o;
13035         }
13036         this.keys.splice(index, 0, key);
13037         this.fireEvent("add", index, o, key);
13038         return o;
13039     },
13040    
13041 /**
13042  * Removed an item from the collection.
13043  * @param {Object} o The item to remove.
13044  * @return {Object} The item removed.
13045  */
13046     remove : function(o){
13047         return this.removeAt(this.indexOf(o));
13048     },
13049    
13050 /**
13051  * Remove an item from a specified index in the collection.
13052  * @param {Number} index The index within the collection of the item to remove.
13053  */
13054     removeAt : function(index){
13055         if(index < this.length && index >= 0){
13056             this.length--;
13057             var o = this.items[index];
13058             this.items.splice(index, 1);
13059             var key = this.keys[index];
13060             if(typeof key != "undefined"){
13061                 delete this.map[key];
13062             }
13063             this.keys.splice(index, 1);
13064             this.fireEvent("remove", o, key);
13065         }
13066     },
13067    
13068 /**
13069  * Removed an item associated with the passed key fom the collection.
13070  * @param {String} key The key of the item to remove.
13071  */
13072     removeKey : function(key){
13073         return this.removeAt(this.indexOfKey(key));
13074     },
13075    
13076 /**
13077  * Returns the number of items in the collection.
13078  * @return {Number} the number of items in the collection.
13079  */
13080     getCount : function(){
13081         return this.length; 
13082     },
13083    
13084 /**
13085  * Returns index within the collection of the passed Object.
13086  * @param {Object} o The item to find the index of.
13087  * @return {Number} index of the item.
13088  */
13089     indexOf : function(o){
13090         if(!this.items.indexOf){
13091             for(var i = 0, len = this.items.length; i < len; i++){
13092                 if(this.items[i] == o) return i;
13093             }
13094             return -1;
13095         }else{
13096             return this.items.indexOf(o);
13097         }
13098     },
13099    
13100 /**
13101  * Returns index within the collection of the passed key.
13102  * @param {String} key The key to find the index of.
13103  * @return {Number} index of the key.
13104  */
13105     indexOfKey : function(key){
13106         if(!this.keys.indexOf){
13107             for(var i = 0, len = this.keys.length; i < len; i++){
13108                 if(this.keys[i] == key) return i;
13109             }
13110             return -1;
13111         }else{
13112             return this.keys.indexOf(key);
13113         }
13114     },
13115    
13116 /**
13117  * Returns the item associated with the passed key OR index. Key has priority over index.
13118  * @param {String/Number} key The key or index of the item.
13119  * @return {Object} The item associated with the passed key.
13120  */
13121     item : function(key){
13122         var item = typeof this.map[key] != "undefined" ? this.map[key] : this.items[key];
13123         return typeof item != 'function' || this.allowFunctions ? item : null; // for prototype!
13124     },
13125     
13126 /**
13127  * Returns the item at the specified index.
13128  * @param {Number} index The index of the item.
13129  * @return {Object}
13130  */
13131     itemAt : function(index){
13132         return this.items[index];
13133     },
13134     
13135 /**
13136  * Returns the item associated with the passed key.
13137  * @param {String/Number} key The key of the item.
13138  * @return {Object} The item associated with the passed key.
13139  */
13140     key : function(key){
13141         return this.map[key];
13142     },
13143    
13144 /**
13145  * Returns true if the collection contains the passed Object as an item.
13146  * @param {Object} o  The Object to look for in the collection.
13147  * @return {Boolean} True if the collection contains the Object as an item.
13148  */
13149     contains : function(o){
13150         return this.indexOf(o) != -1;
13151     },
13152    
13153 /**
13154  * Returns true if the collection contains the passed Object as a key.
13155  * @param {String} key The key to look for in the collection.
13156  * @return {Boolean} True if the collection contains the Object as a key.
13157  */
13158     containsKey : function(key){
13159         return typeof this.map[key] != "undefined";
13160     },
13161    
13162 /**
13163  * Removes all items from the collection.
13164  */
13165     clear : function(){
13166         this.length = 0;
13167         this.items = [];
13168         this.keys = [];
13169         this.map = {};
13170         this.fireEvent("clear");
13171     },
13172    
13173 /**
13174  * Returns the first item in the collection.
13175  * @return {Object} the first item in the collection..
13176  */
13177     first : function(){
13178         return this.items[0]; 
13179     },
13180    
13181 /**
13182  * Returns the last item in the collection.
13183  * @return {Object} the last item in the collection..
13184  */
13185     last : function(){
13186         return this.items[this.length-1];   
13187     },
13188     
13189     _sort : function(property, dir, fn){
13190         var dsc = String(dir).toUpperCase() == "DESC" ? -1 : 1;
13191         fn = fn || function(a, b){
13192             return a-b;
13193         };
13194         var c = [], k = this.keys, items = this.items;
13195         for(var i = 0, len = items.length; i < len; i++){
13196             c[c.length] = {key: k[i], value: items[i], index: i};
13197         }
13198         c.sort(function(a, b){
13199             var v = fn(a[property], b[property]) * dsc;
13200             if(v == 0){
13201                 v = (a.index < b.index ? -1 : 1);
13202             }
13203             return v;
13204         });
13205         for(var i = 0, len = c.length; i < len; i++){
13206             items[i] = c[i].value;
13207             k[i] = c[i].key;
13208         }
13209         this.fireEvent("sort", this);
13210     },
13211     
13212     /**
13213      * Sorts this collection with the passed comparison function
13214      * @param {String} direction (optional) "ASC" or "DESC"
13215      * @param {Function} fn (optional) comparison function
13216      */
13217     sort : function(dir, fn){
13218         this._sort("value", dir, fn);
13219     },
13220     
13221     /**
13222      * Sorts this collection by keys
13223      * @param {String} direction (optional) "ASC" or "DESC"
13224      * @param {Function} fn (optional) a comparison function (defaults to case insensitive string)
13225      */
13226     keySort : function(dir, fn){
13227         this._sort("key", dir, fn || function(a, b){
13228             return String(a).toUpperCase()-String(b).toUpperCase();
13229         });
13230     },
13231     
13232     /**
13233      * Returns a range of items in this collection
13234      * @param {Number} startIndex (optional) defaults to 0
13235      * @param {Number} endIndex (optional) default to the last item
13236      * @return {Array} An array of items
13237      */
13238     getRange : function(start, end){
13239         var items = this.items;
13240         if(items.length < 1){
13241             return [];
13242         }
13243         start = start || 0;
13244         end = Math.min(typeof end == "undefined" ? this.length-1 : end, this.length-1);
13245         var r = [];
13246         if(start <= end){
13247             for(var i = start; i <= end; i++) {
13248                     r[r.length] = items[i];
13249             }
13250         }else{
13251             for(var i = start; i >= end; i--) {
13252                     r[r.length] = items[i];
13253             }
13254         }
13255         return r;
13256     },
13257         
13258     /**
13259      * Filter the <i>objects</i> in this collection by a specific property. 
13260      * Returns a new collection that has been filtered.
13261      * @param {String} property A property on your objects
13262      * @param {String/RegExp} value Either string that the property values 
13263      * should start with or a RegExp to test against the property
13264      * @return {MixedCollection} The new filtered collection
13265      */
13266     filter : function(property, value){
13267         if(!value.exec){ // not a regex
13268             value = String(value);
13269             if(value.length == 0){
13270                 return this.clone();
13271             }
13272             value = new RegExp("^" + Roo.escapeRe(value), "i");
13273         }
13274         return this.filterBy(function(o){
13275             return o && value.test(o[property]);
13276         });
13277         },
13278     
13279     /**
13280      * Filter by a function. * Returns a new collection that has been filtered.
13281      * The passed function will be called with each 
13282      * object in the collection. If the function returns true, the value is included 
13283      * otherwise it is filtered.
13284      * @param {Function} fn The function to be called, it will receive the args o (the object), k (the key)
13285      * @param {Object} scope (optional) The scope of the function (defaults to this) 
13286      * @return {MixedCollection} The new filtered collection
13287      */
13288     filterBy : function(fn, scope){
13289         var r = new Roo.util.MixedCollection();
13290         r.getKey = this.getKey;
13291         var k = this.keys, it = this.items;
13292         for(var i = 0, len = it.length; i < len; i++){
13293             if(fn.call(scope||this, it[i], k[i])){
13294                                 r.add(k[i], it[i]);
13295                         }
13296         }
13297         return r;
13298     },
13299     
13300     /**
13301      * Creates a duplicate of this collection
13302      * @return {MixedCollection}
13303      */
13304     clone : function(){
13305         var r = new Roo.util.MixedCollection();
13306         var k = this.keys, it = this.items;
13307         for(var i = 0, len = it.length; i < len; i++){
13308             r.add(k[i], it[i]);
13309         }
13310         r.getKey = this.getKey;
13311         return r;
13312     }
13313 });
13314 /**
13315  * Returns the item associated with the passed key or index.
13316  * @method
13317  * @param {String/Number} key The key or index of the item.
13318  * @return {Object} The item associated with the passed key.
13319  */
13320 Roo.util.MixedCollection.prototype.get = Roo.util.MixedCollection.prototype.item;/*
13321  * Based on:
13322  * Ext JS Library 1.1.1
13323  * Copyright(c) 2006-2007, Ext JS, LLC.
13324  *
13325  * Originally Released Under LGPL - original licence link has changed is not relivant.
13326  *
13327  * Fork - LGPL
13328  * <script type="text/javascript">
13329  */
13330 /**
13331  * @class Roo.util.JSON
13332  * Modified version of Douglas Crockford"s json.js that doesn"t
13333  * mess with the Object prototype 
13334  * http://www.json.org/js.html
13335  * @singleton
13336  */
13337 Roo.util.JSON = new (function(){
13338     var useHasOwn = {}.hasOwnProperty ? true : false;
13339     
13340     // crashes Safari in some instances
13341     //var validRE = /^("(\\.|[^"\\\n\r])*?"|[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t])+?$/;
13342     
13343     var pad = function(n) {
13344         return n < 10 ? "0" + n : n;
13345     };
13346     
13347     var m = {
13348         "\b": '\\b',
13349         "\t": '\\t',
13350         "\n": '\\n',
13351         "\f": '\\f',
13352         "\r": '\\r',
13353         '"' : '\\"',
13354         "\\": '\\\\'
13355     };
13356
13357     var encodeString = function(s){
13358         if (/["\\\x00-\x1f]/.test(s)) {
13359             return '"' + s.replace(/([\x00-\x1f\\"])/g, function(a, b) {
13360                 var c = m[b];
13361                 if(c){
13362                     return c;
13363                 }
13364                 c = b.charCodeAt();
13365                 return "\\u00" +
13366                     Math.floor(c / 16).toString(16) +
13367                     (c % 16).toString(16);
13368             }) + '"';
13369         }
13370         return '"' + s + '"';
13371     };
13372     
13373     var encodeArray = function(o){
13374         var a = ["["], b, i, l = o.length, v;
13375             for (i = 0; i < l; i += 1) {
13376                 v = o[i];
13377                 switch (typeof v) {
13378                     case "undefined":
13379                     case "function":
13380                     case "unknown":
13381                         break;
13382                     default:
13383                         if (b) {
13384                             a.push(',');
13385                         }
13386                         a.push(v === null ? "null" : Roo.util.JSON.encode(v));
13387                         b = true;
13388                 }
13389             }
13390             a.push("]");
13391             return a.join("");
13392     };
13393     
13394     var encodeDate = function(o){
13395         return '"' + o.getFullYear() + "-" +
13396                 pad(o.getMonth() + 1) + "-" +
13397                 pad(o.getDate()) + "T" +
13398                 pad(o.getHours()) + ":" +
13399                 pad(o.getMinutes()) + ":" +
13400                 pad(o.getSeconds()) + '"';
13401     };
13402     
13403     /**
13404      * Encodes an Object, Array or other value
13405      * @param {Mixed} o The variable to encode
13406      * @return {String} The JSON string
13407      */
13408     this.encode = function(o)
13409     {
13410         // should this be extended to fully wrap stringify..
13411         
13412         if(typeof o == "undefined" || o === null){
13413             return "null";
13414         }else if(o instanceof Array){
13415             return encodeArray(o);
13416         }else if(o instanceof Date){
13417             return encodeDate(o);
13418         }else if(typeof o == "string"){
13419             return encodeString(o);
13420         }else if(typeof o == "number"){
13421             return isFinite(o) ? String(o) : "null";
13422         }else if(typeof o == "boolean"){
13423             return String(o);
13424         }else {
13425             var a = ["{"], b, i, v;
13426             for (i in o) {
13427                 if(!useHasOwn || o.hasOwnProperty(i)) {
13428                     v = o[i];
13429                     switch (typeof v) {
13430                     case "undefined":
13431                     case "function":
13432                     case "unknown":
13433                         break;
13434                     default:
13435                         if(b){
13436                             a.push(',');
13437                         }
13438                         a.push(this.encode(i), ":",
13439                                 v === null ? "null" : this.encode(v));
13440                         b = true;
13441                     }
13442                 }
13443             }
13444             a.push("}");
13445             return a.join("");
13446         }
13447     };
13448     
13449     /**
13450      * Decodes (parses) a JSON string to an object. If the JSON is invalid, this function throws a SyntaxError.
13451      * @param {String} json The JSON string
13452      * @return {Object} The resulting object
13453      */
13454     this.decode = function(json){
13455         
13456         return  /** eval:var:json */ eval("(" + json + ')');
13457     };
13458 })();
13459 /** 
13460  * Shorthand for {@link Roo.util.JSON#encode}
13461  * @member Roo encode 
13462  * @method */
13463 Roo.encode = typeof(JSON) != 'undefined' && JSON.stringify ? JSON.stringify : Roo.util.JSON.encode;
13464 /** 
13465  * Shorthand for {@link Roo.util.JSON#decode}
13466  * @member Roo decode 
13467  * @method */
13468 Roo.decode = typeof(JSON) != 'undefined' && JSON.parse ? JSON.parse : Roo.util.JSON.decode;
13469 /*
13470  * Based on:
13471  * Ext JS Library 1.1.1
13472  * Copyright(c) 2006-2007, Ext JS, LLC.
13473  *
13474  * Originally Released Under LGPL - original licence link has changed is not relivant.
13475  *
13476  * Fork - LGPL
13477  * <script type="text/javascript">
13478  */
13479  
13480 /**
13481  * @class Roo.util.Format
13482  * Reusable data formatting functions
13483  * @singleton
13484  */
13485 Roo.util.Format = function(){
13486     var trimRe = /^\s+|\s+$/g;
13487     return {
13488         /**
13489          * Truncate a string and add an ellipsis ('...') to the end if it exceeds the specified length
13490          * @param {String} value The string to truncate
13491          * @param {Number} length The maximum length to allow before truncating
13492          * @return {String} The converted text
13493          */
13494         ellipsis : function(value, len){
13495             if(value && value.length > len){
13496                 return value.substr(0, len-3)+"...";
13497             }
13498             return value;
13499         },
13500
13501         /**
13502          * Checks a reference and converts it to empty string if it is undefined
13503          * @param {Mixed} value Reference to check
13504          * @return {Mixed} Empty string if converted, otherwise the original value
13505          */
13506         undef : function(value){
13507             return typeof value != "undefined" ? value : "";
13508         },
13509
13510         /**
13511          * Convert certain characters (&, <, >, and ') to their HTML character equivalents for literal display in web pages.
13512          * @param {String} value The string to encode
13513          * @return {String} The encoded text
13514          */
13515         htmlEncode : function(value){
13516             return !value ? value : String(value).replace(/&/g, "&amp;").replace(/>/g, "&gt;").replace(/</g, "&lt;").replace(/"/g, "&quot;");
13517         },
13518
13519         /**
13520          * Convert certain characters (&, <, >, and ') from their HTML character equivalents.
13521          * @param {String} value The string to decode
13522          * @return {String} The decoded text
13523          */
13524         htmlDecode : function(value){
13525             return !value ? value : String(value).replace(/&amp;/g, "&").replace(/&gt;/g, ">").replace(/&lt;/g, "<").replace(/&quot;/g, '"');
13526         },
13527
13528         /**
13529          * Trims any whitespace from either side of a string
13530          * @param {String} value The text to trim
13531          * @return {String} The trimmed text
13532          */
13533         trim : function(value){
13534             return String(value).replace(trimRe, "");
13535         },
13536
13537         /**
13538          * Returns a substring from within an original string
13539          * @param {String} value The original text
13540          * @param {Number} start The start index of the substring
13541          * @param {Number} length The length of the substring
13542          * @return {String} The substring
13543          */
13544         substr : function(value, start, length){
13545             return String(value).substr(start, length);
13546         },
13547
13548         /**
13549          * Converts a string to all lower case letters
13550          * @param {String} value The text to convert
13551          * @return {String} The converted text
13552          */
13553         lowercase : function(value){
13554             return String(value).toLowerCase();
13555         },
13556
13557         /**
13558          * Converts a string to all upper case letters
13559          * @param {String} value The text to convert
13560          * @return {String} The converted text
13561          */
13562         uppercase : function(value){
13563             return String(value).toUpperCase();
13564         },
13565
13566         /**
13567          * Converts the first character only of a string to upper case
13568          * @param {String} value The text to convert
13569          * @return {String} The converted text
13570          */
13571         capitalize : function(value){
13572             return !value ? value : value.charAt(0).toUpperCase() + value.substr(1).toLowerCase();
13573         },
13574
13575         // private
13576         call : function(value, fn){
13577             if(arguments.length > 2){
13578                 var args = Array.prototype.slice.call(arguments, 2);
13579                 args.unshift(value);
13580                  
13581                 return /** eval:var:value */  eval(fn).apply(window, args);
13582             }else{
13583                 /** eval:var:value */
13584                 return /** eval:var:value */ eval(fn).call(window, value);
13585             }
13586         },
13587
13588        
13589         /**
13590          * safer version of Math.toFixed..??/
13591          * @param {Number/String} value The numeric value to format
13592          * @param {Number/String} value Decimal places 
13593          * @return {String} The formatted currency string
13594          */
13595         toFixed : function(v, n)
13596         {
13597             // why not use to fixed - precision is buggered???
13598             if (!n) {
13599                 return Math.round(v-0);
13600             }
13601             var fact = Math.pow(10,n+1);
13602             v = (Math.round((v-0)*fact))/fact;
13603             var z = (''+fact).substring(2);
13604             if (v == Math.floor(v)) {
13605                 return Math.floor(v) + '.' + z;
13606             }
13607             
13608             // now just padd decimals..
13609             var ps = String(v).split('.');
13610             var fd = (ps[1] + z);
13611             var r = fd.substring(0,n); 
13612             var rm = fd.substring(n); 
13613             if (rm < 5) {
13614                 return ps[0] + '.' + r;
13615             }
13616             r*=1; // turn it into a number;
13617             r++;
13618             if (String(r).length != n) {
13619                 ps[0]*=1;
13620                 ps[0]++;
13621                 r = String(r).substring(1); // chop the end off.
13622             }
13623             
13624             return ps[0] + '.' + r;
13625              
13626         },
13627         
13628         /**
13629          * Format a number as US currency
13630          * @param {Number/String} value The numeric value to format
13631          * @return {String} The formatted currency string
13632          */
13633         usMoney : function(v){
13634             return '$' + Roo.util.Format.number(v);
13635         },
13636         
13637         /**
13638          * Format a number
13639          * eventually this should probably emulate php's number_format
13640          * @param {Number/String} value The numeric value to format
13641          * @param {Number} decimals number of decimal places
13642          * @return {String} The formatted currency string
13643          */
13644         number : function(v,decimals)
13645         {
13646             // multiply and round.
13647             decimals = typeof(decimals) == 'undefined' ? 2 : decimals;
13648             var mul = Math.pow(10, decimals);
13649             var zero = String(mul).substring(1);
13650             v = (Math.round((v-0)*mul))/mul;
13651             
13652             // if it's '0' number.. then
13653             
13654             //v = (v == Math.floor(v)) ? v + "." + zero : ((v*10 == Math.floor(v*10)) ? v + "0" : v);
13655             v = String(v);
13656             var ps = v.split('.');
13657             var whole = ps[0];
13658             
13659             
13660             var r = /(\d+)(\d{3})/;
13661             // add comma's
13662             while (r.test(whole)) {
13663                 whole = whole.replace(r, '$1' + ',' + '$2');
13664             }
13665             
13666             
13667             var sub = ps[1] ?
13668                     // has decimals..
13669                     (decimals ?  ('.'+ ps[1] + zero.substring(ps[1].length)) : '') :
13670                     // does not have decimals
13671                     (decimals ? ('.' + zero) : '');
13672             
13673             
13674             return whole + sub ;
13675         },
13676         
13677         /**
13678          * Parse a value into a formatted date using the specified format pattern.
13679          * @param {Mixed} value The value to format
13680          * @param {String} format (optional) Any valid date format string (defaults to 'm/d/Y')
13681          * @return {String} The formatted date string
13682          */
13683         date : function(v, format){
13684             if(!v){
13685                 return "";
13686             }
13687             if(!(v instanceof Date)){
13688                 v = new Date(Date.parse(v));
13689             }
13690             return v.dateFormat(format || Roo.util.Format.defaults.date);
13691         },
13692
13693         /**
13694          * Returns a date rendering function that can be reused to apply a date format multiple times efficiently
13695          * @param {String} format Any valid date format string
13696          * @return {Function} The date formatting function
13697          */
13698         dateRenderer : function(format){
13699             return function(v){
13700                 return Roo.util.Format.date(v, format);  
13701             };
13702         },
13703
13704         // private
13705         stripTagsRE : /<\/?[^>]+>/gi,
13706         
13707         /**
13708          * Strips all HTML tags
13709          * @param {Mixed} value The text from which to strip tags
13710          * @return {String} The stripped text
13711          */
13712         stripTags : function(v){
13713             return !v ? v : String(v).replace(this.stripTagsRE, "");
13714         }
13715     };
13716 }();
13717 Roo.util.Format.defaults = {
13718     date : 'd/M/Y'
13719 };/*
13720  * Based on:
13721  * Ext JS Library 1.1.1
13722  * Copyright(c) 2006-2007, Ext JS, LLC.
13723  *
13724  * Originally Released Under LGPL - original licence link has changed is not relivant.
13725  *
13726  * Fork - LGPL
13727  * <script type="text/javascript">
13728  */
13729
13730
13731  
13732
13733 /**
13734  * @class Roo.MasterTemplate
13735  * @extends Roo.Template
13736  * Provides a template that can have child templates. The syntax is:
13737 <pre><code>
13738 var t = new Roo.MasterTemplate(
13739         '&lt;select name="{name}"&gt;',
13740                 '&lt;tpl name="options"&gt;&lt;option value="{value:trim}"&gt;{text:ellipsis(10)}&lt;/option&gt;&lt;/tpl&gt;',
13741         '&lt;/select&gt;'
13742 );
13743 t.add('options', {value: 'foo', text: 'bar'});
13744 // or you can add multiple child elements in one shot
13745 t.addAll('options', [
13746     {value: 'foo', text: 'bar'},
13747     {value: 'foo2', text: 'bar2'},
13748     {value: 'foo3', text: 'bar3'}
13749 ]);
13750 // then append, applying the master template values
13751 t.append('my-form', {name: 'my-select'});
13752 </code></pre>
13753 * A name attribute for the child template is not required if you have only one child
13754 * template or you want to refer to them by index.
13755  */
13756 Roo.MasterTemplate = function(){
13757     Roo.MasterTemplate.superclass.constructor.apply(this, arguments);
13758     this.originalHtml = this.html;
13759     var st = {};
13760     var m, re = this.subTemplateRe;
13761     re.lastIndex = 0;
13762     var subIndex = 0;
13763     while(m = re.exec(this.html)){
13764         var name = m[1], content = m[2];
13765         st[subIndex] = {
13766             name: name,
13767             index: subIndex,
13768             buffer: [],
13769             tpl : new Roo.Template(content)
13770         };
13771         if(name){
13772             st[name] = st[subIndex];
13773         }
13774         st[subIndex].tpl.compile();
13775         st[subIndex].tpl.call = this.call.createDelegate(this);
13776         subIndex++;
13777     }
13778     this.subCount = subIndex;
13779     this.subs = st;
13780 };
13781 Roo.extend(Roo.MasterTemplate, Roo.Template, {
13782     /**
13783     * The regular expression used to match sub templates
13784     * @type RegExp
13785     * @property
13786     */
13787     subTemplateRe : /<tpl(?:\sname="([\w-]+)")?>((?:.|\n)*?)<\/tpl>/gi,
13788
13789     /**
13790      * Applies the passed values to a child template.
13791      * @param {String/Number} name (optional) The name or index of the child template
13792      * @param {Array/Object} values The values to be applied to the template
13793      * @return {MasterTemplate} this
13794      */
13795      add : function(name, values){
13796         if(arguments.length == 1){
13797             values = arguments[0];
13798             name = 0;
13799         }
13800         var s = this.subs[name];
13801         s.buffer[s.buffer.length] = s.tpl.apply(values);
13802         return this;
13803     },
13804
13805     /**
13806      * Applies all the passed values to a child template.
13807      * @param {String/Number} name (optional) The name or index of the child template
13808      * @param {Array} values The values to be applied to the template, this should be an array of objects.
13809      * @param {Boolean} reset (optional) True to reset the template first
13810      * @return {MasterTemplate} this
13811      */
13812     fill : function(name, values, reset){
13813         var a = arguments;
13814         if(a.length == 1 || (a.length == 2 && typeof a[1] == "boolean")){
13815             values = a[0];
13816             name = 0;
13817             reset = a[1];
13818         }
13819         if(reset){
13820             this.reset();
13821         }
13822         for(var i = 0, len = values.length; i < len; i++){
13823             this.add(name, values[i]);
13824         }
13825         return this;
13826     },
13827
13828     /**
13829      * Resets the template for reuse
13830      * @return {MasterTemplate} this
13831      */
13832      reset : function(){
13833         var s = this.subs;
13834         for(var i = 0; i < this.subCount; i++){
13835             s[i].buffer = [];
13836         }
13837         return this;
13838     },
13839
13840     applyTemplate : function(values){
13841         var s = this.subs;
13842         var replaceIndex = -1;
13843         this.html = this.originalHtml.replace(this.subTemplateRe, function(m, name){
13844             return s[++replaceIndex].buffer.join("");
13845         });
13846         return Roo.MasterTemplate.superclass.applyTemplate.call(this, values);
13847     },
13848
13849     apply : function(){
13850         return this.applyTemplate.apply(this, arguments);
13851     },
13852
13853     compile : function(){return this;}
13854 });
13855
13856 /**
13857  * Alias for fill().
13858  * @method
13859  */
13860 Roo.MasterTemplate.prototype.addAll = Roo.MasterTemplate.prototype.fill;
13861  /**
13862  * Creates a template from the passed element's value (display:none textarea, preferred) or innerHTML. e.g.
13863  * var tpl = Roo.MasterTemplate.from('element-id');
13864  * @param {String/HTMLElement} el
13865  * @param {Object} config
13866  * @static
13867  */
13868 Roo.MasterTemplate.from = function(el, config){
13869     el = Roo.getDom(el);
13870     return new Roo.MasterTemplate(el.value || el.innerHTML, config || '');
13871 };/*
13872  * Based on:
13873  * Ext JS Library 1.1.1
13874  * Copyright(c) 2006-2007, Ext JS, LLC.
13875  *
13876  * Originally Released Under LGPL - original licence link has changed is not relivant.
13877  *
13878  * Fork - LGPL
13879  * <script type="text/javascript">
13880  */
13881
13882  
13883 /**
13884  * @class Roo.util.CSS
13885  * Utility class for manipulating CSS rules
13886  * @singleton
13887  */
13888 Roo.util.CSS = function(){
13889         var rules = null;
13890         var doc = document;
13891
13892     var camelRe = /(-[a-z])/gi;
13893     var camelFn = function(m, a){ return a.charAt(1).toUpperCase(); };
13894
13895    return {
13896    /**
13897     * Very simple dynamic creation of stylesheets from a text blob of rules.  The text will wrapped in a style
13898     * tag and appended to the HEAD of the document.
13899     * @param {String|Object} cssText The text containing the css rules
13900     * @param {String} id An id to add to the stylesheet for later removal
13901     * @return {StyleSheet}
13902     */
13903     createStyleSheet : function(cssText, id){
13904         var ss;
13905         var head = doc.getElementsByTagName("head")[0];
13906         var nrules = doc.createElement("style");
13907         nrules.setAttribute("type", "text/css");
13908         if(id){
13909             nrules.setAttribute("id", id);
13910         }
13911         if (typeof(cssText) != 'string') {
13912             // support object maps..
13913             // not sure if this a good idea.. 
13914             // perhaps it should be merged with the general css handling
13915             // and handle js style props.
13916             var cssTextNew = [];
13917             for(var n in cssText) {
13918                 var citems = [];
13919                 for(var k in cssText[n]) {
13920                     citems.push( k + ' : ' +cssText[n][k] + ';' );
13921                 }
13922                 cssTextNew.push( n + ' { ' + citems.join(' ') + '} ');
13923                 
13924             }
13925             cssText = cssTextNew.join("\n");
13926             
13927         }
13928        
13929        
13930        if(Roo.isIE){
13931            head.appendChild(nrules);
13932            ss = nrules.styleSheet;
13933            ss.cssText = cssText;
13934        }else{
13935            try{
13936                 nrules.appendChild(doc.createTextNode(cssText));
13937            }catch(e){
13938                nrules.cssText = cssText; 
13939            }
13940            head.appendChild(nrules);
13941            ss = nrules.styleSheet ? nrules.styleSheet : (nrules.sheet || doc.styleSheets[doc.styleSheets.length-1]);
13942        }
13943        this.cacheStyleSheet(ss);
13944        return ss;
13945    },
13946
13947    /**
13948     * Removes a style or link tag by id
13949     * @param {String} id The id of the tag
13950     */
13951    removeStyleSheet : function(id){
13952        var existing = doc.getElementById(id);
13953        if(existing){
13954            existing.parentNode.removeChild(existing);
13955        }
13956    },
13957
13958    /**
13959     * Dynamically swaps an existing stylesheet reference for a new one
13960     * @param {String} id The id of an existing link tag to remove
13961     * @param {String} url The href of the new stylesheet to include
13962     */
13963    swapStyleSheet : function(id, url){
13964        this.removeStyleSheet(id);
13965        var ss = doc.createElement("link");
13966        ss.setAttribute("rel", "stylesheet");
13967        ss.setAttribute("type", "text/css");
13968        ss.setAttribute("id", id);
13969        ss.setAttribute("href", url);
13970        doc.getElementsByTagName("head")[0].appendChild(ss);
13971    },
13972    
13973    /**
13974     * Refresh the rule cache if you have dynamically added stylesheets
13975     * @return {Object} An object (hash) of rules indexed by selector
13976     */
13977    refreshCache : function(){
13978        return this.getRules(true);
13979    },
13980
13981    // private
13982    cacheStyleSheet : function(stylesheet){
13983        if(!rules){
13984            rules = {};
13985        }
13986        try{// try catch for cross domain access issue
13987            var ssRules = stylesheet.cssRules || stylesheet.rules;
13988            for(var j = ssRules.length-1; j >= 0; --j){
13989                rules[ssRules[j].selectorText] = ssRules[j];
13990            }
13991        }catch(e){}
13992    },
13993    
13994    /**
13995     * Gets all css rules for the document
13996     * @param {Boolean} refreshCache true to refresh the internal cache
13997     * @return {Object} An object (hash) of rules indexed by selector
13998     */
13999    getRules : function(refreshCache){
14000                 if(rules == null || refreshCache){
14001                         rules = {};
14002                         var ds = doc.styleSheets;
14003                         for(var i =0, len = ds.length; i < len; i++){
14004                             try{
14005                         this.cacheStyleSheet(ds[i]);
14006                     }catch(e){} 
14007                 }
14008                 }
14009                 return rules;
14010         },
14011         
14012         /**
14013     * Gets an an individual CSS rule by selector(s)
14014     * @param {String/Array} selector The CSS selector or an array of selectors to try. The first selector that is found is returned.
14015     * @param {Boolean} refreshCache true to refresh the internal cache if you have recently updated any rules or added styles dynamically
14016     * @return {CSSRule} The CSS rule or null if one is not found
14017     */
14018    getRule : function(selector, refreshCache){
14019                 var rs = this.getRules(refreshCache);
14020                 if(!(selector instanceof Array)){
14021                     return rs[selector];
14022                 }
14023                 for(var i = 0; i < selector.length; i++){
14024                         if(rs[selector[i]]){
14025                                 return rs[selector[i]];
14026                         }
14027                 }
14028                 return null;
14029         },
14030         
14031         
14032         /**
14033     * Updates a rule property
14034     * @param {String/Array} selector If it's an array it tries each selector until it finds one. Stops immediately once one is found.
14035     * @param {String} property The css property
14036     * @param {String} value The new value for the property
14037     * @return {Boolean} true If a rule was found and updated
14038     */
14039    updateRule : function(selector, property, value){
14040                 if(!(selector instanceof Array)){
14041                         var rule = this.getRule(selector);
14042                         if(rule){
14043                                 rule.style[property.replace(camelRe, camelFn)] = value;
14044                                 return true;
14045                         }
14046                 }else{
14047                         for(var i = 0; i < selector.length; i++){
14048                                 if(this.updateRule(selector[i], property, value)){
14049                                         return true;
14050                                 }
14051                         }
14052                 }
14053                 return false;
14054         }
14055    };   
14056 }();/*
14057  * Based on:
14058  * Ext JS Library 1.1.1
14059  * Copyright(c) 2006-2007, Ext JS, LLC.
14060  *
14061  * Originally Released Under LGPL - original licence link has changed is not relivant.
14062  *
14063  * Fork - LGPL
14064  * <script type="text/javascript">
14065  */
14066
14067  
14068
14069 /**
14070  * @class Roo.util.ClickRepeater
14071  * @extends Roo.util.Observable
14072  * 
14073  * A wrapper class which can be applied to any element. Fires a "click" event while the
14074  * mouse is pressed. The interval between firings may be specified in the config but
14075  * defaults to 10 milliseconds.
14076  * 
14077  * Optionally, a CSS class may be applied to the element during the time it is pressed.
14078  * 
14079  * @cfg {String/HTMLElement/Element} el The element to act as a button.
14080  * @cfg {Number} delay The initial delay before the repeating event begins firing.
14081  * Similar to an autorepeat key delay.
14082  * @cfg {Number} interval The interval between firings of the "click" event. Default 10 ms.
14083  * @cfg {String} pressClass A CSS class name to be applied to the element while pressed.
14084  * @cfg {Boolean} accelerate True if autorepeating should start slowly and accelerate.
14085  *           "interval" and "delay" are ignored. "immediate" is honored.
14086  * @cfg {Boolean} preventDefault True to prevent the default click event
14087  * @cfg {Boolean} stopDefault True to stop the default click event
14088  * 
14089  * @history
14090  *     2007-02-02 jvs Original code contributed by Nige "Animal" White
14091  *     2007-02-02 jvs Renamed to ClickRepeater
14092  *   2007-02-03 jvs Modifications for FF Mac and Safari 
14093  *
14094  *  @constructor
14095  * @param {String/HTMLElement/Element} el The element to listen on
14096  * @param {Object} config
14097  **/
14098 Roo.util.ClickRepeater = function(el, config)
14099 {
14100     this.el = Roo.get(el);
14101     this.el.unselectable();
14102
14103     Roo.apply(this, config);
14104
14105     this.addEvents({
14106     /**
14107      * @event mousedown
14108      * Fires when the mouse button is depressed.
14109      * @param {Roo.util.ClickRepeater} this
14110      */
14111         "mousedown" : true,
14112     /**
14113      * @event click
14114      * Fires on a specified interval during the time the element is pressed.
14115      * @param {Roo.util.ClickRepeater} this
14116      */
14117         "click" : true,
14118     /**
14119      * @event mouseup
14120      * Fires when the mouse key is released.
14121      * @param {Roo.util.ClickRepeater} this
14122      */
14123         "mouseup" : true
14124     });
14125
14126     this.el.on("mousedown", this.handleMouseDown, this);
14127     if(this.preventDefault || this.stopDefault){
14128         this.el.on("click", function(e){
14129             if(this.preventDefault){
14130                 e.preventDefault();
14131             }
14132             if(this.stopDefault){
14133                 e.stopEvent();
14134             }
14135         }, this);
14136     }
14137
14138     // allow inline handler
14139     if(this.handler){
14140         this.on("click", this.handler,  this.scope || this);
14141     }
14142
14143     Roo.util.ClickRepeater.superclass.constructor.call(this);
14144 };
14145
14146 Roo.extend(Roo.util.ClickRepeater, Roo.util.Observable, {
14147     interval : 20,
14148     delay: 250,
14149     preventDefault : true,
14150     stopDefault : false,
14151     timer : 0,
14152
14153     // private
14154     handleMouseDown : function(){
14155         clearTimeout(this.timer);
14156         this.el.blur();
14157         if(this.pressClass){
14158             this.el.addClass(this.pressClass);
14159         }
14160         this.mousedownTime = new Date();
14161
14162         Roo.get(document).on("mouseup", this.handleMouseUp, this);
14163         this.el.on("mouseout", this.handleMouseOut, this);
14164
14165         this.fireEvent("mousedown", this);
14166         this.fireEvent("click", this);
14167         
14168         this.timer = this.click.defer(this.delay || this.interval, this);
14169     },
14170
14171     // private
14172     click : function(){
14173         this.fireEvent("click", this);
14174         this.timer = this.click.defer(this.getInterval(), this);
14175     },
14176
14177     // private
14178     getInterval: function(){
14179         if(!this.accelerate){
14180             return this.interval;
14181         }
14182         var pressTime = this.mousedownTime.getElapsed();
14183         if(pressTime < 500){
14184             return 400;
14185         }else if(pressTime < 1700){
14186             return 320;
14187         }else if(pressTime < 2600){
14188             return 250;
14189         }else if(pressTime < 3500){
14190             return 180;
14191         }else if(pressTime < 4400){
14192             return 140;
14193         }else if(pressTime < 5300){
14194             return 80;
14195         }else if(pressTime < 6200){
14196             return 50;
14197         }else{
14198             return 10;
14199         }
14200     },
14201
14202     // private
14203     handleMouseOut : function(){
14204         clearTimeout(this.timer);
14205         if(this.pressClass){
14206             this.el.removeClass(this.pressClass);
14207         }
14208         this.el.on("mouseover", this.handleMouseReturn, this);
14209     },
14210
14211     // private
14212     handleMouseReturn : function(){
14213         this.el.un("mouseover", this.handleMouseReturn);
14214         if(this.pressClass){
14215             this.el.addClass(this.pressClass);
14216         }
14217         this.click();
14218     },
14219
14220     // private
14221     handleMouseUp : function(){
14222         clearTimeout(this.timer);
14223         this.el.un("mouseover", this.handleMouseReturn);
14224         this.el.un("mouseout", this.handleMouseOut);
14225         Roo.get(document).un("mouseup", this.handleMouseUp);
14226         this.el.removeClass(this.pressClass);
14227         this.fireEvent("mouseup", this);
14228     }
14229 });/*
14230  * Based on:
14231  * Ext JS Library 1.1.1
14232  * Copyright(c) 2006-2007, Ext JS, LLC.
14233  *
14234  * Originally Released Under LGPL - original licence link has changed is not relivant.
14235  *
14236  * Fork - LGPL
14237  * <script type="text/javascript">
14238  */
14239
14240  
14241 /**
14242  * @class Roo.KeyNav
14243  * <p>Provides a convenient wrapper for normalized keyboard navigation.  KeyNav allows you to bind
14244  * navigation keys to function calls that will get called when the keys are pressed, providing an easy
14245  * way to implement custom navigation schemes for any UI component.</p>
14246  * <p>The following are all of the possible keys that can be implemented: enter, left, right, up, down, tab, esc,
14247  * pageUp, pageDown, del, home, end.  Usage:</p>
14248  <pre><code>
14249 var nav = new Roo.KeyNav("my-element", {
14250     "left" : function(e){
14251         this.moveLeft(e.ctrlKey);
14252     },
14253     "right" : function(e){
14254         this.moveRight(e.ctrlKey);
14255     },
14256     "enter" : function(e){
14257         this.save();
14258     },
14259     scope : this
14260 });
14261 </code></pre>
14262  * @constructor
14263  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14264  * @param {Object} config The config
14265  */
14266 Roo.KeyNav = function(el, config){
14267     this.el = Roo.get(el);
14268     Roo.apply(this, config);
14269     if(!this.disabled){
14270         this.disabled = true;
14271         this.enable();
14272     }
14273 };
14274
14275 Roo.KeyNav.prototype = {
14276     /**
14277      * @cfg {Boolean} disabled
14278      * True to disable this KeyNav instance (defaults to false)
14279      */
14280     disabled : false,
14281     /**
14282      * @cfg {String} defaultEventAction
14283      * The method to call on the {@link Roo.EventObject} after this KeyNav intercepts a key.  Valid values are
14284      * {@link Roo.EventObject#stopEvent}, {@link Roo.EventObject#preventDefault} and
14285      * {@link Roo.EventObject#stopPropagation} (defaults to 'stopEvent')
14286      */
14287     defaultEventAction: "stopEvent",
14288     /**
14289      * @cfg {Boolean} forceKeyDown
14290      * Handle the keydown event instead of keypress (defaults to false).  KeyNav automatically does this for IE since
14291      * IE does not propagate special keys on keypress, but setting this to true will force other browsers to also
14292      * handle keydown instead of keypress.
14293      */
14294     forceKeyDown : false,
14295
14296     // private
14297     prepareEvent : function(e){
14298         var k = e.getKey();
14299         var h = this.keyToHandler[k];
14300         //if(h && this[h]){
14301         //    e.stopPropagation();
14302         //}
14303         if(Roo.isSafari && h && k >= 37 && k <= 40){
14304             e.stopEvent();
14305         }
14306     },
14307
14308     // private
14309     relay : function(e){
14310         var k = e.getKey();
14311         var h = this.keyToHandler[k];
14312         if(h && this[h]){
14313             if(this.doRelay(e, this[h], h) !== true){
14314                 e[this.defaultEventAction]();
14315             }
14316         }
14317     },
14318
14319     // private
14320     doRelay : function(e, h, hname){
14321         return h.call(this.scope || this, e);
14322     },
14323
14324     // possible handlers
14325     enter : false,
14326     left : false,
14327     right : false,
14328     up : false,
14329     down : false,
14330     tab : false,
14331     esc : false,
14332     pageUp : false,
14333     pageDown : false,
14334     del : false,
14335     home : false,
14336     end : false,
14337
14338     // quick lookup hash
14339     keyToHandler : {
14340         37 : "left",
14341         39 : "right",
14342         38 : "up",
14343         40 : "down",
14344         33 : "pageUp",
14345         34 : "pageDown",
14346         46 : "del",
14347         36 : "home",
14348         35 : "end",
14349         13 : "enter",
14350         27 : "esc",
14351         9  : "tab"
14352     },
14353
14354         /**
14355          * Enable this KeyNav
14356          */
14357         enable: function(){
14358                 if(this.disabled){
14359             // ie won't do special keys on keypress, no one else will repeat keys with keydown
14360             // the EventObject will normalize Safari automatically
14361             if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14362                 this.el.on("keydown", this.relay,  this);
14363             }else{
14364                 this.el.on("keydown", this.prepareEvent,  this);
14365                 this.el.on("keypress", this.relay,  this);
14366             }
14367                     this.disabled = false;
14368                 }
14369         },
14370
14371         /**
14372          * Disable this KeyNav
14373          */
14374         disable: function(){
14375                 if(!this.disabled){
14376                     if(this.forceKeyDown || Roo.isIE || Roo.isAir){
14377                 this.el.un("keydown", this.relay);
14378             }else{
14379                 this.el.un("keydown", this.prepareEvent);
14380                 this.el.un("keypress", this.relay);
14381             }
14382                     this.disabled = true;
14383                 }
14384         }
14385 };/*
14386  * Based on:
14387  * Ext JS Library 1.1.1
14388  * Copyright(c) 2006-2007, Ext JS, LLC.
14389  *
14390  * Originally Released Under LGPL - original licence link has changed is not relivant.
14391  *
14392  * Fork - LGPL
14393  * <script type="text/javascript">
14394  */
14395
14396  
14397 /**
14398  * @class Roo.KeyMap
14399  * Handles mapping keys to actions for an element. One key map can be used for multiple actions.
14400  * The constructor accepts the same config object as defined by {@link #addBinding}.
14401  * If you bind a callback function to a KeyMap, anytime the KeyMap handles an expected key
14402  * combination it will call the function with this signature (if the match is a multi-key
14403  * combination the callback will still be called only once): (String key, Roo.EventObject e)
14404  * A KeyMap can also handle a string representation of keys.<br />
14405  * Usage:
14406  <pre><code>
14407 // map one key by key code
14408 var map = new Roo.KeyMap("my-element", {
14409     key: 13, // or Roo.EventObject.ENTER
14410     fn: myHandler,
14411     scope: myObject
14412 });
14413
14414 // map multiple keys to one action by string
14415 var map = new Roo.KeyMap("my-element", {
14416     key: "a\r\n\t",
14417     fn: myHandler,
14418     scope: myObject
14419 });
14420
14421 // map multiple keys to multiple actions by strings and array of codes
14422 var map = new Roo.KeyMap("my-element", [
14423     {
14424         key: [10,13],
14425         fn: function(){ alert("Return was pressed"); }
14426     }, {
14427         key: "abc",
14428         fn: function(){ alert('a, b or c was pressed'); }
14429     }, {
14430         key: "\t",
14431         ctrl:true,
14432         shift:true,
14433         fn: function(){ alert('Control + shift + tab was pressed.'); }
14434     }
14435 ]);
14436 </code></pre>
14437  * <b>Note: A KeyMap starts enabled</b>
14438  * @constructor
14439  * @param {String/HTMLElement/Roo.Element} el The element to bind to
14440  * @param {Object} config The config (see {@link #addBinding})
14441  * @param {String} eventName (optional) The event to bind to (defaults to "keydown")
14442  */
14443 Roo.KeyMap = function(el, config, eventName){
14444     this.el  = Roo.get(el);
14445     this.eventName = eventName || "keydown";
14446     this.bindings = [];
14447     if(config){
14448         this.addBinding(config);
14449     }
14450     this.enable();
14451 };
14452
14453 Roo.KeyMap.prototype = {
14454     /**
14455      * True to stop the event from bubbling and prevent the default browser action if the
14456      * key was handled by the KeyMap (defaults to false)
14457      * @type Boolean
14458      */
14459     stopEvent : false,
14460
14461     /**
14462      * Add a new binding to this KeyMap. The following config object properties are supported:
14463      * <pre>
14464 Property    Type             Description
14465 ----------  ---------------  ----------------------------------------------------------------------
14466 key         String/Array     A single keycode or an array of keycodes to handle
14467 shift       Boolean          True to handle key only when shift is pressed (defaults to false)
14468 ctrl        Boolean          True to handle key only when ctrl is pressed (defaults to false)
14469 alt         Boolean          True to handle key only when alt is pressed (defaults to false)
14470 fn          Function         The function to call when KeyMap finds the expected key combination
14471 scope       Object           The scope of the callback function
14472 </pre>
14473      *
14474      * Usage:
14475      * <pre><code>
14476 // Create a KeyMap
14477 var map = new Roo.KeyMap(document, {
14478     key: Roo.EventObject.ENTER,
14479     fn: handleKey,
14480     scope: this
14481 });
14482
14483 //Add a new binding to the existing KeyMap later
14484 map.addBinding({
14485     key: 'abc',
14486     shift: true,
14487     fn: handleKey,
14488     scope: this
14489 });
14490 </code></pre>
14491      * @param {Object/Array} config A single KeyMap config or an array of configs
14492      */
14493         addBinding : function(config){
14494         if(config instanceof Array){
14495             for(var i = 0, len = config.length; i < len; i++){
14496                 this.addBinding(config[i]);
14497             }
14498             return;
14499         }
14500         var keyCode = config.key,
14501             shift = config.shift, 
14502             ctrl = config.ctrl, 
14503             alt = config.alt,
14504             fn = config.fn,
14505             scope = config.scope;
14506         if(typeof keyCode == "string"){
14507             var ks = [];
14508             var keyString = keyCode.toUpperCase();
14509             for(var j = 0, len = keyString.length; j < len; j++){
14510                 ks.push(keyString.charCodeAt(j));
14511             }
14512             keyCode = ks;
14513         }
14514         var keyArray = keyCode instanceof Array;
14515         var handler = function(e){
14516             if((!shift || e.shiftKey) && (!ctrl || e.ctrlKey) &&  (!alt || e.altKey)){
14517                 var k = e.getKey();
14518                 if(keyArray){
14519                     for(var i = 0, len = keyCode.length; i < len; i++){
14520                         if(keyCode[i] == k){
14521                           if(this.stopEvent){
14522                               e.stopEvent();
14523                           }
14524                           fn.call(scope || window, k, e);
14525                           return;
14526                         }
14527                     }
14528                 }else{
14529                     if(k == keyCode){
14530                         if(this.stopEvent){
14531                            e.stopEvent();
14532                         }
14533                         fn.call(scope || window, k, e);
14534                     }
14535                 }
14536             }
14537         };
14538         this.bindings.push(handler);  
14539         },
14540
14541     /**
14542      * Shorthand for adding a single key listener
14543      * @param {Number/Array/Object} key Either the numeric key code, array of key codes or an object with the
14544      * following options:
14545      * {key: (number or array), shift: (true/false), ctrl: (true/false), alt: (true/false)}
14546      * @param {Function} fn The function to call
14547      * @param {Object} scope (optional) The scope of the function
14548      */
14549     on : function(key, fn, scope){
14550         var keyCode, shift, ctrl, alt;
14551         if(typeof key == "object" && !(key instanceof Array)){
14552             keyCode = key.key;
14553             shift = key.shift;
14554             ctrl = key.ctrl;
14555             alt = key.alt;
14556         }else{
14557             keyCode = key;
14558         }
14559         this.addBinding({
14560             key: keyCode,
14561             shift: shift,
14562             ctrl: ctrl,
14563             alt: alt,
14564             fn: fn,
14565             scope: scope
14566         })
14567     },
14568
14569     // private
14570     handleKeyDown : function(e){
14571             if(this.enabled){ //just in case
14572             var b = this.bindings;
14573             for(var i = 0, len = b.length; i < len; i++){
14574                 b[i].call(this, e);
14575             }
14576             }
14577         },
14578         
14579         /**
14580          * Returns true if this KeyMap is enabled
14581          * @return {Boolean} 
14582          */
14583         isEnabled : function(){
14584             return this.enabled;  
14585         },
14586         
14587         /**
14588          * Enables this KeyMap
14589          */
14590         enable: function(){
14591                 if(!this.enabled){
14592                     this.el.on(this.eventName, this.handleKeyDown, this);
14593                     this.enabled = true;
14594                 }
14595         },
14596
14597         /**
14598          * Disable this KeyMap
14599          */
14600         disable: function(){
14601                 if(this.enabled){
14602                     this.el.removeListener(this.eventName, this.handleKeyDown, this);
14603                     this.enabled = false;
14604                 }
14605         }
14606 };/*
14607  * Based on:
14608  * Ext JS Library 1.1.1
14609  * Copyright(c) 2006-2007, Ext JS, LLC.
14610  *
14611  * Originally Released Under LGPL - original licence link has changed is not relivant.
14612  *
14613  * Fork - LGPL
14614  * <script type="text/javascript">
14615  */
14616
14617  
14618 /**
14619  * @class Roo.util.TextMetrics
14620  * Provides precise pixel measurements for blocks of text so that you can determine exactly how high and
14621  * wide, in pixels, a given block of text will be.
14622  * @singleton
14623  */
14624 Roo.util.TextMetrics = function(){
14625     var shared;
14626     return {
14627         /**
14628          * Measures the size of the specified text
14629          * @param {String/HTMLElement} el The element, dom node or id from which to copy existing CSS styles
14630          * that can affect the size of the rendered text
14631          * @param {String} text The text to measure
14632          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14633          * in order to accurately measure the text height
14634          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14635          */
14636         measure : function(el, text, fixedWidth){
14637             if(!shared){
14638                 shared = Roo.util.TextMetrics.Instance(el, fixedWidth);
14639             }
14640             shared.bind(el);
14641             shared.setFixedWidth(fixedWidth || 'auto');
14642             return shared.getSize(text);
14643         },
14644
14645         /**
14646          * Return a unique TextMetrics instance that can be bound directly to an element and reused.  This reduces
14647          * the overhead of multiple calls to initialize the style properties on each measurement.
14648          * @param {String/HTMLElement} el The element, dom node or id that the instance will be bound to
14649          * @param {Number} fixedWidth (optional) If the text will be multiline, you have to set a fixed width
14650          * in order to accurately measure the text height
14651          * @return {Roo.util.TextMetrics.Instance} instance The new instance
14652          */
14653         createInstance : function(el, fixedWidth){
14654             return Roo.util.TextMetrics.Instance(el, fixedWidth);
14655         }
14656     };
14657 }();
14658
14659  
14660
14661 Roo.util.TextMetrics.Instance = function(bindTo, fixedWidth){
14662     var ml = new Roo.Element(document.createElement('div'));
14663     document.body.appendChild(ml.dom);
14664     ml.position('absolute');
14665     ml.setLeftTop(-1000, -1000);
14666     ml.hide();
14667
14668     if(fixedWidth){
14669         ml.setWidth(fixedWidth);
14670     }
14671      
14672     var instance = {
14673         /**
14674          * Returns the size of the specified text based on the internal element's style and width properties
14675          * @memberOf Roo.util.TextMetrics.Instance#
14676          * @param {String} text The text to measure
14677          * @return {Object} An object containing the text's size {width: (width), height: (height)}
14678          */
14679         getSize : function(text){
14680             ml.update(text);
14681             var s = ml.getSize();
14682             ml.update('');
14683             return s;
14684         },
14685
14686         /**
14687          * Binds this TextMetrics instance to an element from which to copy existing CSS styles
14688          * that can affect the size of the rendered text
14689          * @memberOf Roo.util.TextMetrics.Instance#
14690          * @param {String/HTMLElement} el The element, dom node or id
14691          */
14692         bind : function(el){
14693             ml.setStyle(
14694                 Roo.fly(el).getStyles('font-size','font-style', 'font-weight', 'font-family','line-height')
14695             );
14696         },
14697
14698         /**
14699          * Sets a fixed width on the internal measurement element.  If the text will be multiline, you have
14700          * to set a fixed width in order to accurately measure the text height.
14701          * @memberOf Roo.util.TextMetrics.Instance#
14702          * @param {Number} width The width to set on the element
14703          */
14704         setFixedWidth : function(width){
14705             ml.setWidth(width);
14706         },
14707
14708         /**
14709          * Returns the measured width of the specified text
14710          * @memberOf Roo.util.TextMetrics.Instance#
14711          * @param {String} text The text to measure
14712          * @return {Number} width The width in pixels
14713          */
14714         getWidth : function(text){
14715             ml.dom.style.width = 'auto';
14716             return this.getSize(text).width;
14717         },
14718
14719         /**
14720          * Returns the measured height of the specified text.  For multiline text, be sure to call
14721          * {@link #setFixedWidth} if necessary.
14722          * @memberOf Roo.util.TextMetrics.Instance#
14723          * @param {String} text The text to measure
14724          * @return {Number} height The height in pixels
14725          */
14726         getHeight : function(text){
14727             return this.getSize(text).height;
14728         }
14729     };
14730
14731     instance.bind(bindTo);
14732
14733     return instance;
14734 };
14735
14736 // backwards compat
14737 Roo.Element.measureText = Roo.util.TextMetrics.measure;/*
14738  * Based on:
14739  * Ext JS Library 1.1.1
14740  * Copyright(c) 2006-2007, Ext JS, LLC.
14741  *
14742  * Originally Released Under LGPL - original licence link has changed is not relivant.
14743  *
14744  * Fork - LGPL
14745  * <script type="text/javascript">
14746  */
14747
14748 /**
14749  * @class Roo.state.Provider
14750  * Abstract base class for state provider implementations. This class provides methods
14751  * for encoding and decoding <b>typed</b> variables including dates and defines the 
14752  * Provider interface.
14753  */
14754 Roo.state.Provider = function(){
14755     /**
14756      * @event statechange
14757      * Fires when a state change occurs.
14758      * @param {Provider} this This state provider
14759      * @param {String} key The state key which was changed
14760      * @param {String} value The encoded value for the state
14761      */
14762     this.addEvents({
14763         "statechange": true
14764     });
14765     this.state = {};
14766     Roo.state.Provider.superclass.constructor.call(this);
14767 };
14768 Roo.extend(Roo.state.Provider, Roo.util.Observable, {
14769     /**
14770      * Returns the current value for a key
14771      * @param {String} name The key name
14772      * @param {Mixed} defaultValue A default value to return if the key's value is not found
14773      * @return {Mixed} The state data
14774      */
14775     get : function(name, defaultValue){
14776         return typeof this.state[name] == "undefined" ?
14777             defaultValue : this.state[name];
14778     },
14779     
14780     /**
14781      * Clears a value from the state
14782      * @param {String} name The key name
14783      */
14784     clear : function(name){
14785         delete this.state[name];
14786         this.fireEvent("statechange", this, name, null);
14787     },
14788     
14789     /**
14790      * Sets the value for a key
14791      * @param {String} name The key name
14792      * @param {Mixed} value The value to set
14793      */
14794     set : function(name, value){
14795         this.state[name] = value;
14796         this.fireEvent("statechange", this, name, value);
14797     },
14798     
14799     /**
14800      * Decodes a string previously encoded with {@link #encodeValue}.
14801      * @param {String} value The value to decode
14802      * @return {Mixed} The decoded value
14803      */
14804     decodeValue : function(cookie){
14805         var re = /^(a|n|d|b|s|o)\:(.*)$/;
14806         var matches = re.exec(unescape(cookie));
14807         if(!matches || !matches[1]) return; // non state cookie
14808         var type = matches[1];
14809         var v = matches[2];
14810         switch(type){
14811             case "n":
14812                 return parseFloat(v);
14813             case "d":
14814                 return new Date(Date.parse(v));
14815             case "b":
14816                 return (v == "1");
14817             case "a":
14818                 var all = [];
14819                 var values = v.split("^");
14820                 for(var i = 0, len = values.length; i < len; i++){
14821                     all.push(this.decodeValue(values[i]));
14822                 }
14823                 return all;
14824            case "o":
14825                 var all = {};
14826                 var values = v.split("^");
14827                 for(var i = 0, len = values.length; i < len; i++){
14828                     var kv = values[i].split("=");
14829                     all[kv[0]] = this.decodeValue(kv[1]);
14830                 }
14831                 return all;
14832            default:
14833                 return v;
14834         }
14835     },
14836     
14837     /**
14838      * Encodes a value including type information.  Decode with {@link #decodeValue}.
14839      * @param {Mixed} value The value to encode
14840      * @return {String} The encoded value
14841      */
14842     encodeValue : function(v){
14843         var enc;
14844         if(typeof v == "number"){
14845             enc = "n:" + v;
14846         }else if(typeof v == "boolean"){
14847             enc = "b:" + (v ? "1" : "0");
14848         }else if(v instanceof Date){
14849             enc = "d:" + v.toGMTString();
14850         }else if(v instanceof Array){
14851             var flat = "";
14852             for(var i = 0, len = v.length; i < len; i++){
14853                 flat += this.encodeValue(v[i]);
14854                 if(i != len-1) flat += "^";
14855             }
14856             enc = "a:" + flat;
14857         }else if(typeof v == "object"){
14858             var flat = "";
14859             for(var key in v){
14860                 if(typeof v[key] != "function"){
14861                     flat += key + "=" + this.encodeValue(v[key]) + "^";
14862                 }
14863             }
14864             enc = "o:" + flat.substring(0, flat.length-1);
14865         }else{
14866             enc = "s:" + v;
14867         }
14868         return escape(enc);        
14869     }
14870 });
14871
14872 /*
14873  * Based on:
14874  * Ext JS Library 1.1.1
14875  * Copyright(c) 2006-2007, Ext JS, LLC.
14876  *
14877  * Originally Released Under LGPL - original licence link has changed is not relivant.
14878  *
14879  * Fork - LGPL
14880  * <script type="text/javascript">
14881  */
14882 /**
14883  * @class Roo.state.Manager
14884  * This is the global state manager. By default all components that are "state aware" check this class
14885  * for state information if you don't pass them a custom state provider. In order for this class
14886  * to be useful, it must be initialized with a provider when your application initializes.
14887  <pre><code>
14888 // in your initialization function
14889 init : function(){
14890    Roo.state.Manager.setProvider(new Roo.state.CookieProvider());
14891    ...
14892    // supposed you have a {@link Roo.BorderLayout}
14893    var layout = new Roo.BorderLayout(...);
14894    layout.restoreState();
14895    // or a {Roo.BasicDialog}
14896    var dialog = new Roo.BasicDialog(...);
14897    dialog.restoreState();
14898  </code></pre>
14899  * @singleton
14900  */
14901 Roo.state.Manager = function(){
14902     var provider = new Roo.state.Provider();
14903     
14904     return {
14905         /**
14906          * Configures the default state provider for your application
14907          * @param {Provider} stateProvider The state provider to set
14908          */
14909         setProvider : function(stateProvider){
14910             provider = stateProvider;
14911         },
14912         
14913         /**
14914          * Returns the current value for a key
14915          * @param {String} name The key name
14916          * @param {Mixed} defaultValue The default value to return if the key lookup does not match
14917          * @return {Mixed} The state data
14918          */
14919         get : function(key, defaultValue){
14920             return provider.get(key, defaultValue);
14921         },
14922         
14923         /**
14924          * Sets the value for a key
14925          * @param {String} name The key name
14926          * @param {Mixed} value The state data
14927          */
14928          set : function(key, value){
14929             provider.set(key, value);
14930         },
14931         
14932         /**
14933          * Clears a value from the state
14934          * @param {String} name The key name
14935          */
14936         clear : function(key){
14937             provider.clear(key);
14938         },
14939         
14940         /**
14941          * Gets the currently configured state provider
14942          * @return {Provider} The state provider
14943          */
14944         getProvider : function(){
14945             return provider;
14946         }
14947     };
14948 }();
14949 /*
14950  * Based on:
14951  * Ext JS Library 1.1.1
14952  * Copyright(c) 2006-2007, Ext JS, LLC.
14953  *
14954  * Originally Released Under LGPL - original licence link has changed is not relivant.
14955  *
14956  * Fork - LGPL
14957  * <script type="text/javascript">
14958  */
14959 /**
14960  * @class Roo.state.CookieProvider
14961  * @extends Roo.state.Provider
14962  * The default Provider implementation which saves state via cookies.
14963  * <br />Usage:
14964  <pre><code>
14965    var cp = new Roo.state.CookieProvider({
14966        path: "/cgi-bin/",
14967        expires: new Date(new Date().getTime()+(1000*60*60*24*30)); //30 days
14968        domain: "roojs.com"
14969    })
14970    Roo.state.Manager.setProvider(cp);
14971  </code></pre>
14972  * @cfg {String} path The path for which the cookie is active (defaults to root '/' which makes it active for all pages in the site)
14973  * @cfg {Date} expires The cookie expiration date (defaults to 7 days from now)
14974  * @cfg {String} domain The domain to save the cookie for.  Note that you cannot specify a different domain than
14975  * your page is on, but you can specify a sub-domain, or simply the domain itself like 'roojs.com' to include
14976  * all sub-domains if you need to access cookies across different sub-domains (defaults to null which uses the same
14977  * domain the page is running on including the 'www' like 'www.roojs.com')
14978  * @cfg {Boolean} secure True if the site is using SSL (defaults to false)
14979  * @constructor
14980  * Create a new CookieProvider
14981  * @param {Object} config The configuration object
14982  */
14983 Roo.state.CookieProvider = function(config){
14984     Roo.state.CookieProvider.superclass.constructor.call(this);
14985     this.path = "/";
14986     this.expires = new Date(new Date().getTime()+(1000*60*60*24*7)); //7 days
14987     this.domain = null;
14988     this.secure = false;
14989     Roo.apply(this, config);
14990     this.state = this.readCookies();
14991 };
14992
14993 Roo.extend(Roo.state.CookieProvider, Roo.state.Provider, {
14994     // private
14995     set : function(name, value){
14996         if(typeof value == "undefined" || value === null){
14997             this.clear(name);
14998             return;
14999         }
15000         this.setCookie(name, value);
15001         Roo.state.CookieProvider.superclass.set.call(this, name, value);
15002     },
15003
15004     // private
15005     clear : function(name){
15006         this.clearCookie(name);
15007         Roo.state.CookieProvider.superclass.clear.call(this, name);
15008     },
15009
15010     // private
15011     readCookies : function(){
15012         var cookies = {};
15013         var c = document.cookie + ";";
15014         var re = /\s?(.*?)=(.*?);/g;
15015         var matches;
15016         while((matches = re.exec(c)) != null){
15017             var name = matches[1];
15018             var value = matches[2];
15019             if(name && name.substring(0,3) == "ys-"){
15020                 cookies[name.substr(3)] = this.decodeValue(value);
15021             }
15022         }
15023         return cookies;
15024     },
15025
15026     // private
15027     setCookie : function(name, value){
15028         document.cookie = "ys-"+ name + "=" + this.encodeValue(value) +
15029            ((this.expires == null) ? "" : ("; expires=" + this.expires.toGMTString())) +
15030            ((this.path == null) ? "" : ("; path=" + this.path)) +
15031            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15032            ((this.secure == true) ? "; secure" : "");
15033     },
15034
15035     // private
15036     clearCookie : function(name){
15037         document.cookie = "ys-" + name + "=null; expires=Thu, 01-Jan-70 00:00:01 GMT" +
15038            ((this.path == null) ? "" : ("; path=" + this.path)) +
15039            ((this.domain == null) ? "" : ("; domain=" + this.domain)) +
15040            ((this.secure == true) ? "; secure" : "");
15041     }
15042 });/*
15043  * Based on:
15044  * Ext JS Library 1.1.1
15045  * Copyright(c) 2006-2007, Ext JS, LLC.
15046  *
15047  * Originally Released Under LGPL - original licence link has changed is not relivant.
15048  *
15049  * Fork - LGPL
15050  * <script type="text/javascript">
15051  */
15052  
15053
15054 /**
15055  * @class Roo.ComponentMgr
15056  * Provides a common registry of all components on a page so that they can be easily accessed by component id (see {@link Roo.getCmp}).
15057  * @singleton
15058  */
15059 Roo.ComponentMgr = function(){
15060     var all = new Roo.util.MixedCollection();
15061
15062     return {
15063         /**
15064          * Registers a component.
15065          * @param {Roo.Component} c The component
15066          */
15067         register : function(c){
15068             all.add(c);
15069         },
15070
15071         /**
15072          * Unregisters a component.
15073          * @param {Roo.Component} c The component
15074          */
15075         unregister : function(c){
15076             all.remove(c);
15077         },
15078
15079         /**
15080          * Returns a component by id
15081          * @param {String} id The component id
15082          */
15083         get : function(id){
15084             return all.get(id);
15085         },
15086
15087         /**
15088          * Registers a function that will be called when a specified component is added to ComponentMgr
15089          * @param {String} id The component id
15090          * @param {Funtction} fn The callback function
15091          * @param {Object} scope The scope of the callback
15092          */
15093         onAvailable : function(id, fn, scope){
15094             all.on("add", function(index, o){
15095                 if(o.id == id){
15096                     fn.call(scope || o, o);
15097                     all.un("add", fn, scope);
15098                 }
15099             });
15100         }
15101     };
15102 }();/*
15103  * Based on:
15104  * Ext JS Library 1.1.1
15105  * Copyright(c) 2006-2007, Ext JS, LLC.
15106  *
15107  * Originally Released Under LGPL - original licence link has changed is not relivant.
15108  *
15109  * Fork - LGPL
15110  * <script type="text/javascript">
15111  */
15112  
15113 /**
15114  * @class Roo.Component
15115  * @extends Roo.util.Observable
15116  * Base class for all major Roo components.  All subclasses of Component can automatically participate in the standard
15117  * Roo component lifecycle of creation, rendering and destruction.  They also have automatic support for basic hide/show
15118  * and enable/disable behavior.  Component allows any subclass to be lazy-rendered into any {@link Roo.Container} and
15119  * to be automatically registered with the {@link Roo.ComponentMgr} so that it can be referenced at any time via {@link Roo.getCmp}.
15120  * All visual components (widgets) that require rendering into a layout should subclass Component.
15121  * @constructor
15122  * @param {Roo.Element/String/Object} config The configuration options.  If an element is passed, it is set as the internal
15123  * 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
15124  * and is used as the component id.  Otherwise, it is assumed to be a standard config object and is applied to the component.
15125  */
15126 Roo.Component = function(config){
15127     config = config || {};
15128     if(config.tagName || config.dom || typeof config == "string"){ // element object
15129         config = {el: config, id: config.id || config};
15130     }
15131     this.initialConfig = config;
15132
15133     Roo.apply(this, config);
15134     this.addEvents({
15135         /**
15136          * @event disable
15137          * Fires after the component is disabled.
15138              * @param {Roo.Component} this
15139              */
15140         disable : true,
15141         /**
15142          * @event enable
15143          * Fires after the component is enabled.
15144              * @param {Roo.Component} this
15145              */
15146         enable : true,
15147         /**
15148          * @event beforeshow
15149          * Fires before the component is shown.  Return false to stop the show.
15150              * @param {Roo.Component} this
15151              */
15152         beforeshow : true,
15153         /**
15154          * @event show
15155          * Fires after the component is shown.
15156              * @param {Roo.Component} this
15157              */
15158         show : true,
15159         /**
15160          * @event beforehide
15161          * Fires before the component is hidden. Return false to stop the hide.
15162              * @param {Roo.Component} this
15163              */
15164         beforehide : true,
15165         /**
15166          * @event hide
15167          * Fires after the component is hidden.
15168              * @param {Roo.Component} this
15169              */
15170         hide : true,
15171         /**
15172          * @event beforerender
15173          * Fires before the component is rendered. Return false to stop the render.
15174              * @param {Roo.Component} this
15175              */
15176         beforerender : true,
15177         /**
15178          * @event render
15179          * Fires after the component is rendered.
15180              * @param {Roo.Component} this
15181              */
15182         render : true,
15183         /**
15184          * @event beforedestroy
15185          * Fires before the component is destroyed. Return false to stop the destroy.
15186              * @param {Roo.Component} this
15187              */
15188         beforedestroy : true,
15189         /**
15190          * @event destroy
15191          * Fires after the component is destroyed.
15192              * @param {Roo.Component} this
15193              */
15194         destroy : true
15195     });
15196     if(!this.id){
15197         this.id = "roo-comp-" + (++Roo.Component.AUTO_ID);
15198     }
15199     Roo.ComponentMgr.register(this);
15200     Roo.Component.superclass.constructor.call(this);
15201     this.initComponent();
15202     if(this.renderTo){ // not supported by all components yet. use at your own risk!
15203         this.render(this.renderTo);
15204         delete this.renderTo;
15205     }
15206 };
15207
15208 /** @private */
15209 Roo.Component.AUTO_ID = 1000;
15210
15211 Roo.extend(Roo.Component, Roo.util.Observable, {
15212     /**
15213      * @scope Roo.Component.prototype
15214      * @type {Boolean}
15215      * true if this component is hidden. Read-only.
15216      */
15217     hidden : false,
15218     /**
15219      * @type {Boolean}
15220      * true if this component is disabled. Read-only.
15221      */
15222     disabled : false,
15223     /**
15224      * @type {Boolean}
15225      * true if this component has been rendered. Read-only.
15226      */
15227     rendered : false,
15228     
15229     /** @cfg {String} disableClass
15230      * CSS class added to the component when it is disabled (defaults to "x-item-disabled").
15231      */
15232     disabledClass : "x-item-disabled",
15233         /** @cfg {Boolean} allowDomMove
15234          * Whether the component can move the Dom node when rendering (defaults to true).
15235          */
15236     allowDomMove : true,
15237     /** @cfg {String} hideMode (display|visibility)
15238      * How this component should hidden. Supported values are
15239      * "visibility" (css visibility), "offsets" (negative offset position) and
15240      * "display" (css display) - defaults to "display".
15241      */
15242     hideMode: 'display',
15243
15244     /** @private */
15245     ctype : "Roo.Component",
15246
15247     /**
15248      * @cfg {String} actionMode 
15249      * which property holds the element that used for  hide() / show() / disable() / enable()
15250      * default is 'el' 
15251      */
15252     actionMode : "el",
15253
15254     /** @private */
15255     getActionEl : function(){
15256         return this[this.actionMode];
15257     },
15258
15259     initComponent : Roo.emptyFn,
15260     /**
15261      * If this is a lazy rendering component, render it to its container element.
15262      * @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.
15263      */
15264     render : function(container, position){
15265         if(!this.rendered && this.fireEvent("beforerender", this) !== false){
15266             if(!container && this.el){
15267                 this.el = Roo.get(this.el);
15268                 container = this.el.dom.parentNode;
15269                 this.allowDomMove = false;
15270             }
15271             this.container = Roo.get(container);
15272             this.rendered = true;
15273             if(position !== undefined){
15274                 if(typeof position == 'number'){
15275                     position = this.container.dom.childNodes[position];
15276                 }else{
15277                     position = Roo.getDom(position);
15278                 }
15279             }
15280             this.onRender(this.container, position || null);
15281             if(this.cls){
15282                 this.el.addClass(this.cls);
15283                 delete this.cls;
15284             }
15285             if(this.style){
15286                 this.el.applyStyles(this.style);
15287                 delete this.style;
15288             }
15289             this.fireEvent("render", this);
15290             this.afterRender(this.container);
15291             if(this.hidden){
15292                 this.hide();
15293             }
15294             if(this.disabled){
15295                 this.disable();
15296             }
15297         }
15298         return this;
15299     },
15300
15301     /** @private */
15302     // default function is not really useful
15303     onRender : function(ct, position){
15304         if(this.el){
15305             this.el = Roo.get(this.el);
15306             if(this.allowDomMove !== false){
15307                 ct.dom.insertBefore(this.el.dom, position);
15308             }
15309         }
15310     },
15311
15312     /** @private */
15313     getAutoCreate : function(){
15314         var cfg = typeof this.autoCreate == "object" ?
15315                       this.autoCreate : Roo.apply({}, this.defaultAutoCreate);
15316         if(this.id && !cfg.id){
15317             cfg.id = this.id;
15318         }
15319         return cfg;
15320     },
15321
15322     /** @private */
15323     afterRender : Roo.emptyFn,
15324
15325     /**
15326      * Destroys this component by purging any event listeners, removing the component's element from the DOM,
15327      * removing the component from its {@link Roo.Container} (if applicable) and unregistering it from {@link Roo.ComponentMgr}.
15328      */
15329     destroy : function(){
15330         if(this.fireEvent("beforedestroy", this) !== false){
15331             this.purgeListeners();
15332             this.beforeDestroy();
15333             if(this.rendered){
15334                 this.el.removeAllListeners();
15335                 this.el.remove();
15336                 if(this.actionMode == "container"){
15337                     this.container.remove();
15338                 }
15339             }
15340             this.onDestroy();
15341             Roo.ComponentMgr.unregister(this);
15342             this.fireEvent("destroy", this);
15343         }
15344     },
15345
15346         /** @private */
15347     beforeDestroy : function(){
15348
15349     },
15350
15351         /** @private */
15352         onDestroy : function(){
15353
15354     },
15355
15356     /**
15357      * Returns the underlying {@link Roo.Element}.
15358      * @return {Roo.Element} The element
15359      */
15360     getEl : function(){
15361         return this.el;
15362     },
15363
15364     /**
15365      * Returns the id of this component.
15366      * @return {String}
15367      */
15368     getId : function(){
15369         return this.id;
15370     },
15371
15372     /**
15373      * Try to focus this component.
15374      * @param {Boolean} selectText True to also select the text in this component (if applicable)
15375      * @return {Roo.Component} this
15376      */
15377     focus : function(selectText){
15378         if(this.rendered){
15379             this.el.focus();
15380             if(selectText === true){
15381                 this.el.dom.select();
15382             }
15383         }
15384         return this;
15385     },
15386
15387     /** @private */
15388     blur : function(){
15389         if(this.rendered){
15390             this.el.blur();
15391         }
15392         return this;
15393     },
15394
15395     /**
15396      * Disable this component.
15397      * @return {Roo.Component} this
15398      */
15399     disable : function(){
15400         if(this.rendered){
15401             this.onDisable();
15402         }
15403         this.disabled = true;
15404         this.fireEvent("disable", this);
15405         return this;
15406     },
15407
15408         // private
15409     onDisable : function(){
15410         this.getActionEl().addClass(this.disabledClass);
15411         this.el.dom.disabled = true;
15412     },
15413
15414     /**
15415      * Enable this component.
15416      * @return {Roo.Component} this
15417      */
15418     enable : function(){
15419         if(this.rendered){
15420             this.onEnable();
15421         }
15422         this.disabled = false;
15423         this.fireEvent("enable", this);
15424         return this;
15425     },
15426
15427         // private
15428     onEnable : function(){
15429         this.getActionEl().removeClass(this.disabledClass);
15430         this.el.dom.disabled = false;
15431     },
15432
15433     /**
15434      * Convenience function for setting disabled/enabled by boolean.
15435      * @param {Boolean} disabled
15436      */
15437     setDisabled : function(disabled){
15438         this[disabled ? "disable" : "enable"]();
15439     },
15440
15441     /**
15442      * Show this component.
15443      * @return {Roo.Component} this
15444      */
15445     show: function(){
15446         if(this.fireEvent("beforeshow", this) !== false){
15447             this.hidden = false;
15448             if(this.rendered){
15449                 this.onShow();
15450             }
15451             this.fireEvent("show", this);
15452         }
15453         return this;
15454     },
15455
15456     // private
15457     onShow : function(){
15458         var ae = this.getActionEl();
15459         if(this.hideMode == 'visibility'){
15460             ae.dom.style.visibility = "visible";
15461         }else if(this.hideMode == 'offsets'){
15462             ae.removeClass('x-hidden');
15463         }else{
15464             ae.dom.style.display = "";
15465         }
15466     },
15467
15468     /**
15469      * Hide this component.
15470      * @return {Roo.Component} this
15471      */
15472     hide: function(){
15473         if(this.fireEvent("beforehide", this) !== false){
15474             this.hidden = true;
15475             if(this.rendered){
15476                 this.onHide();
15477             }
15478             this.fireEvent("hide", this);
15479         }
15480         return this;
15481     },
15482
15483     // private
15484     onHide : function(){
15485         var ae = this.getActionEl();
15486         if(this.hideMode == 'visibility'){
15487             ae.dom.style.visibility = "hidden";
15488         }else if(this.hideMode == 'offsets'){
15489             ae.addClass('x-hidden');
15490         }else{
15491             ae.dom.style.display = "none";
15492         }
15493     },
15494
15495     /**
15496      * Convenience function to hide or show this component by boolean.
15497      * @param {Boolean} visible True to show, false to hide
15498      * @return {Roo.Component} this
15499      */
15500     setVisible: function(visible){
15501         if(visible) {
15502             this.show();
15503         }else{
15504             this.hide();
15505         }
15506         return this;
15507     },
15508
15509     /**
15510      * Returns true if this component is visible.
15511      */
15512     isVisible : function(){
15513         return this.getActionEl().isVisible();
15514     },
15515
15516     cloneConfig : function(overrides){
15517         overrides = overrides || {};
15518         var id = overrides.id || Roo.id();
15519         var cfg = Roo.applyIf(overrides, this.initialConfig);
15520         cfg.id = id; // prevent dup id
15521         return new this.constructor(cfg);
15522     }
15523 });/*
15524  * Based on:
15525  * Ext JS Library 1.1.1
15526  * Copyright(c) 2006-2007, Ext JS, LLC.
15527  *
15528  * Originally Released Under LGPL - original licence link has changed is not relivant.
15529  *
15530  * Fork - LGPL
15531  * <script type="text/javascript">
15532  */
15533
15534 /**
15535  * @class Roo.BoxComponent
15536  * @extends Roo.Component
15537  * Base class for any visual {@link Roo.Component} that uses a box container.  BoxComponent provides automatic box
15538  * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model.  All
15539  * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext
15540  * layout containers.
15541  * @constructor
15542  * @param {Roo.Element/String/Object} config The configuration options.
15543  */
15544 Roo.BoxComponent = function(config){
15545     Roo.Component.call(this, config);
15546     this.addEvents({
15547         /**
15548          * @event resize
15549          * Fires after the component is resized.
15550              * @param {Roo.Component} this
15551              * @param {Number} adjWidth The box-adjusted width that was set
15552              * @param {Number} adjHeight The box-adjusted height that was set
15553              * @param {Number} rawWidth The width that was originally specified
15554              * @param {Number} rawHeight The height that was originally specified
15555              */
15556         resize : true,
15557         /**
15558          * @event move
15559          * Fires after the component is moved.
15560              * @param {Roo.Component} this
15561              * @param {Number} x The new x position
15562              * @param {Number} y The new y position
15563              */
15564         move : true
15565     });
15566 };
15567
15568 Roo.extend(Roo.BoxComponent, Roo.Component, {
15569     // private, set in afterRender to signify that the component has been rendered
15570     boxReady : false,
15571     // private, used to defer height settings to subclasses
15572     deferHeight: false,
15573     /** @cfg {Number} width
15574      * width (optional) size of component
15575      */
15576      /** @cfg {Number} height
15577      * height (optional) size of component
15578      */
15579      
15580     /**
15581      * Sets the width and height of the component.  This method fires the resize event.  This method can accept
15582      * either width and height as separate numeric arguments, or you can pass a size object like {width:10, height:20}.
15583      * @param {Number/Object} width The new width to set, or a size object in the format {width, height}
15584      * @param {Number} height The new height to set (not required if a size object is passed as the first arg)
15585      * @return {Roo.BoxComponent} this
15586      */
15587     setSize : function(w, h){
15588         // support for standard size objects
15589         if(typeof w == 'object'){
15590             h = w.height;
15591             w = w.width;
15592         }
15593         // not rendered
15594         if(!this.boxReady){
15595             this.width = w;
15596             this.height = h;
15597             return this;
15598         }
15599
15600         // prevent recalcs when not needed
15601         if(this.lastSize && this.lastSize.width == w && this.lastSize.height == h){
15602             return this;
15603         }
15604         this.lastSize = {width: w, height: h};
15605
15606         var adj = this.adjustSize(w, h);
15607         var aw = adj.width, ah = adj.height;
15608         if(aw !== undefined || ah !== undefined){ // this code is nasty but performs better with floaters
15609             var rz = this.getResizeEl();
15610             if(!this.deferHeight && aw !== undefined && ah !== undefined){
15611                 rz.setSize(aw, ah);
15612             }else if(!this.deferHeight && ah !== undefined){
15613                 rz.setHeight(ah);
15614             }else if(aw !== undefined){
15615                 rz.setWidth(aw);
15616             }
15617             this.onResize(aw, ah, w, h);
15618             this.fireEvent('resize', this, aw, ah, w, h);
15619         }
15620         return this;
15621     },
15622
15623     /**
15624      * Gets the current size of the component's underlying element.
15625      * @return {Object} An object containing the element's size {width: (element width), height: (element height)}
15626      */
15627     getSize : function(){
15628         return this.el.getSize();
15629     },
15630
15631     /**
15632      * Gets the current XY position of the component's underlying element.
15633      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15634      * @return {Array} The XY position of the element (e.g., [100, 200])
15635      */
15636     getPosition : function(local){
15637         if(local === true){
15638             return [this.el.getLeft(true), this.el.getTop(true)];
15639         }
15640         return this.xy || this.el.getXY();
15641     },
15642
15643     /**
15644      * Gets the current box measurements of the component's underlying element.
15645      * @param {Boolean} local (optional) If true the element's left and top are returned instead of page XY (defaults to false)
15646      * @returns {Object} box An object in the format {x, y, width, height}
15647      */
15648     getBox : function(local){
15649         var s = this.el.getSize();
15650         if(local){
15651             s.x = this.el.getLeft(true);
15652             s.y = this.el.getTop(true);
15653         }else{
15654             var xy = this.xy || this.el.getXY();
15655             s.x = xy[0];
15656             s.y = xy[1];
15657         }
15658         return s;
15659     },
15660
15661     /**
15662      * Sets the current box measurements of the component's underlying element.
15663      * @param {Object} box An object in the format {x, y, width, height}
15664      * @returns {Roo.BoxComponent} this
15665      */
15666     updateBox : function(box){
15667         this.setSize(box.width, box.height);
15668         this.setPagePosition(box.x, box.y);
15669         return this;
15670     },
15671
15672     // protected
15673     getResizeEl : function(){
15674         return this.resizeEl || this.el;
15675     },
15676
15677     // protected
15678     getPositionEl : function(){
15679         return this.positionEl || this.el;
15680     },
15681
15682     /**
15683      * Sets the left and top of the component.  To set the page XY position instead, use {@link #setPagePosition}.
15684      * This method fires the move event.
15685      * @param {Number} left The new left
15686      * @param {Number} top The new top
15687      * @returns {Roo.BoxComponent} this
15688      */
15689     setPosition : function(x, y){
15690         this.x = x;
15691         this.y = y;
15692         if(!this.boxReady){
15693             return this;
15694         }
15695         var adj = this.adjustPosition(x, y);
15696         var ax = adj.x, ay = adj.y;
15697
15698         var el = this.getPositionEl();
15699         if(ax !== undefined || ay !== undefined){
15700             if(ax !== undefined && ay !== undefined){
15701                 el.setLeftTop(ax, ay);
15702             }else if(ax !== undefined){
15703                 el.setLeft(ax);
15704             }else if(ay !== undefined){
15705                 el.setTop(ay);
15706             }
15707             this.onPosition(ax, ay);
15708             this.fireEvent('move', this, ax, ay);
15709         }
15710         return this;
15711     },
15712
15713     /**
15714      * Sets the page XY position of the component.  To set the left and top instead, use {@link #setPosition}.
15715      * This method fires the move event.
15716      * @param {Number} x The new x position
15717      * @param {Number} y The new y position
15718      * @returns {Roo.BoxComponent} this
15719      */
15720     setPagePosition : function(x, y){
15721         this.pageX = x;
15722         this.pageY = y;
15723         if(!this.boxReady){
15724             return;
15725         }
15726         if(x === undefined || y === undefined){ // cannot translate undefined points
15727             return;
15728         }
15729         var p = this.el.translatePoints(x, y);
15730         this.setPosition(p.left, p.top);
15731         return this;
15732     },
15733
15734     // private
15735     onRender : function(ct, position){
15736         Roo.BoxComponent.superclass.onRender.call(this, ct, position);
15737         if(this.resizeEl){
15738             this.resizeEl = Roo.get(this.resizeEl);
15739         }
15740         if(this.positionEl){
15741             this.positionEl = Roo.get(this.positionEl);
15742         }
15743     },
15744
15745     // private
15746     afterRender : function(){
15747         Roo.BoxComponent.superclass.afterRender.call(this);
15748         this.boxReady = true;
15749         this.setSize(this.width, this.height);
15750         if(this.x || this.y){
15751             this.setPosition(this.x, this.y);
15752         }
15753         if(this.pageX || this.pageY){
15754             this.setPagePosition(this.pageX, this.pageY);
15755         }
15756     },
15757
15758     /**
15759      * Force the component's size to recalculate based on the underlying element's current height and width.
15760      * @returns {Roo.BoxComponent} this
15761      */
15762     syncSize : function(){
15763         delete this.lastSize;
15764         this.setSize(this.el.getWidth(), this.el.getHeight());
15765         return this;
15766     },
15767
15768     /**
15769      * Called after the component is resized, this method is empty by default but can be implemented by any
15770      * subclass that needs to perform custom logic after a resize occurs.
15771      * @param {Number} adjWidth The box-adjusted width that was set
15772      * @param {Number} adjHeight The box-adjusted height that was set
15773      * @param {Number} rawWidth The width that was originally specified
15774      * @param {Number} rawHeight The height that was originally specified
15775      */
15776     onResize : function(adjWidth, adjHeight, rawWidth, rawHeight){
15777
15778     },
15779
15780     /**
15781      * Called after the component is moved, this method is empty by default but can be implemented by any
15782      * subclass that needs to perform custom logic after a move occurs.
15783      * @param {Number} x The new x position
15784      * @param {Number} y The new y position
15785      */
15786     onPosition : function(x, y){
15787
15788     },
15789
15790     // private
15791     adjustSize : function(w, h){
15792         if(this.autoWidth){
15793             w = 'auto';
15794         }
15795         if(this.autoHeight){
15796             h = 'auto';
15797         }
15798         return {width : w, height: h};
15799     },
15800
15801     // private
15802     adjustPosition : function(x, y){
15803         return {x : x, y: y};
15804     }
15805 });/*
15806  * Original code for Roojs - LGPL
15807  * <script type="text/javascript">
15808  */
15809  
15810 /**
15811  * @class Roo.XComponent
15812  * A delayed Element creator...
15813  * Or a way to group chunks of interface together.
15814  * technically this is a wrapper around a tree of Roo elements (which defines a 'module'),
15815  *  used in conjunction with XComponent.build() it will create an instance of each element,
15816  *  then call addxtype() to build the User interface.
15817  * 
15818  * Mypart.xyx = new Roo.XComponent({
15819
15820     parent : 'Mypart.xyz', // empty == document.element.!!
15821     order : '001',
15822     name : 'xxxx'
15823     region : 'xxxx'
15824     disabled : function() {} 
15825      
15826     tree : function() { // return an tree of xtype declared components
15827         var MODULE = this;
15828         return 
15829         {
15830             xtype : 'NestedLayoutPanel',
15831             // technicall
15832         }
15833      ]
15834  *})
15835  *
15836  *
15837  * It can be used to build a big heiracy, with parent etc.
15838  * or you can just use this to render a single compoent to a dom element
15839  * MYPART.render(Roo.Element | String(id) | dom_element )
15840  *
15841  *
15842  * Usage patterns.
15843  *
15844  * Classic Roo
15845  *
15846  * Roo is designed primarily as a single page application, so the UI build for a standard interface will
15847  * expect a single 'TOP' level module normally indicated by the 'parent' of the XComponent definition being defined as false.
15848  *
15849  * Each sub module is expected to have a parent pointing to the class name of it's parent module.
15850  *
15851  * When the top level is false, a 'Roo.BorderLayout' is created and the element is flagged as 'topModule'
15852  * - if mulitple topModules exist, the last one is defined as the top module.
15853  *
15854  * Embeded Roo
15855  * 
15856  * When the top level or multiple modules are to embedded into a existing HTML page,
15857  * the parent element can container '#id' of the element where the module will be drawn.
15858  *
15859  * Bootstrap Roo
15860  *
15861  * Unlike classic Roo, the bootstrap tends not to be used as a single page.
15862  * it relies more on a include mechanism, where sub modules are included into an outer page.
15863  * This is normally managed by the builder tools using Roo.apply( options, Included.Sub.Module )
15864  * 
15865  * Bootstrap Roo Included elements
15866  *
15867  * Our builder application needs the ability to preview these sub compoennts. They will normally have parent=false set,
15868  * hence confusing the component builder as it thinks there are multiple top level elements. 
15869  *
15870  * 
15871  * 
15872  * @extends Roo.util.Observable
15873  * @constructor
15874  * @param cfg {Object} configuration of component
15875  * 
15876  */
15877 Roo.XComponent = function(cfg) {
15878     Roo.apply(this, cfg);
15879     this.addEvents({ 
15880         /**
15881              * @event built
15882              * Fires when this the componnt is built
15883              * @param {Roo.XComponent} c the component
15884              */
15885         'built' : true
15886         
15887     });
15888     this.region = this.region || 'center'; // default..
15889     Roo.XComponent.register(this);
15890     this.modules = false;
15891     this.el = false; // where the layout goes..
15892     
15893     
15894 }
15895 Roo.extend(Roo.XComponent, Roo.util.Observable, {
15896     /**
15897      * @property el
15898      * The created element (with Roo.factory())
15899      * @type {Roo.Layout}
15900      */
15901     el  : false,
15902     
15903     /**
15904      * @property el
15905      * for BC  - use el in new code
15906      * @type {Roo.Layout}
15907      */
15908     panel : false,
15909     
15910     /**
15911      * @property layout
15912      * for BC  - use el in new code
15913      * @type {Roo.Layout}
15914      */
15915     layout : false,
15916     
15917      /**
15918      * @cfg {Function|boolean} disabled
15919      * If this module is disabled by some rule, return true from the funtion
15920      */
15921     disabled : false,
15922     
15923     /**
15924      * @cfg {String} parent 
15925      * Name of parent element which it get xtype added to..
15926      */
15927     parent: false,
15928     
15929     /**
15930      * @cfg {String} order
15931      * Used to set the order in which elements are created (usefull for multiple tabs)
15932      */
15933     
15934     order : false,
15935     /**
15936      * @cfg {String} name
15937      * String to display while loading.
15938      */
15939     name : false,
15940     /**
15941      * @cfg {String} region
15942      * Region to render component to (defaults to center)
15943      */
15944     region : 'center',
15945     
15946     /**
15947      * @cfg {Array} items
15948      * A single item array - the first element is the root of the tree..
15949      * It's done this way to stay compatible with the Xtype system...
15950      */
15951     items : false,
15952     
15953     /**
15954      * @property _tree
15955      * The method that retuns the tree of parts that make up this compoennt 
15956      * @type {function}
15957      */
15958     _tree  : false,
15959     
15960      /**
15961      * render
15962      * render element to dom or tree
15963      * @param {Roo.Element|String|DomElement} optional render to if parent is not set.
15964      */
15965     
15966     render : function(el)
15967     {
15968         
15969         el = el || false;
15970         var hp = this.parent ? 1 : 0;
15971         Roo.debug &&  Roo.log(this);
15972         
15973         if (!el && typeof(this.parent) == 'string' && this.parent.substring(0,1) == '#') {
15974             // if parent is a '#.....' string, then let's use that..
15975             var ename = this.parent.substr(1);
15976             this.parent = false;
15977             Roo.debug && Roo.log(ename);
15978             switch (ename) {
15979                 case 'bootstrap-body' :
15980                     if (typeof(Roo.bootstrap.Body) != 'undefined') {
15981                         this.parent = { el :  new  Roo.bootstrap.Body() };
15982                         Roo.debug && Roo.log("setting el to doc body");
15983                          
15984                     } else {
15985                         throw "Container is bootstrap body, but Roo.bootstrap.Body is not defined";
15986                     }
15987                     break;
15988                 case 'bootstrap':
15989                     this.parent = { el : true};
15990                     // fall through
15991                 default:
15992                     el = Roo.get(ename);
15993                     break;
15994             }
15995                 
15996             
15997             if (!el && !this.parent) {
15998                 Roo.debug && Roo.log("Warning - element can not be found :#" + ename );
15999                 return;
16000             }
16001         }
16002         Roo.debug && Roo.log("EL:");
16003         Roo.debug && Roo.log(el);
16004         Roo.debug && Roo.log("this.parent.el:");
16005         Roo.debug && Roo.log(this.parent.el);
16006         
16007         var tree = this._tree ? this._tree() : this.tree();
16008
16009         // altertive root elements ??? - we need a better way to indicate these.
16010         var is_alt = (typeof(Roo.bootstrap) != 'undefined' && tree.xns == Roo.bootstrap) ||
16011                         (typeof(Roo.mailer) != 'undefined' && tree.xns == Roo.mailer) ;
16012         
16013         if (!this.parent && is_alt) {
16014             //el = Roo.get(document.body);
16015             this.parent = { el : true };
16016         }
16017             
16018             
16019         
16020         if (!this.parent) {
16021             
16022             Roo.debug && Roo.log("no parent - creating one");
16023             
16024             el = el ? Roo.get(el) : false;      
16025             
16026             // it's a top level one..
16027             this.parent =  {
16028                 el : new Roo.BorderLayout(el || document.body, {
16029                 
16030                      center: {
16031                          titlebar: false,
16032                          autoScroll:false,
16033                          closeOnTab: true,
16034                          tabPosition: 'top',
16035                           //resizeTabs: true,
16036                          alwaysShowTabs: el && hp? false :  true,
16037                          hideTabs: el || !hp ? true :  false,
16038                          minTabWidth: 140
16039                      }
16040                  })
16041             }
16042         }
16043         
16044         if (!this.parent.el) {
16045                 // probably an old style ctor, which has been disabled.
16046                 return;
16047
16048         }
16049                 // The 'tree' method is  '_tree now' 
16050             
16051         tree.region = tree.region || this.region;
16052         
16053         if (this.parent.el === true) {
16054             // bootstrap... - body..
16055             this.parent.el = Roo.factory(tree);
16056         }
16057         
16058         this.el = this.parent.el.addxtype(tree);
16059         this.fireEvent('built', this);
16060         
16061         this.panel = this.el;
16062         this.layout = this.panel.layout;
16063         this.parentLayout = this.parent.layout  || false;  
16064          
16065     }
16066     
16067 });
16068
16069 Roo.apply(Roo.XComponent, {
16070     /**
16071      * @property  hideProgress
16072      * true to disable the building progress bar.. usefull on single page renders.
16073      * @type Boolean
16074      */
16075     hideProgress : false,
16076     /**
16077      * @property  buildCompleted
16078      * True when the builder has completed building the interface.
16079      * @type Boolean
16080      */
16081     buildCompleted : false,
16082      
16083     /**
16084      * @property  topModule
16085      * the upper most module - uses document.element as it's constructor.
16086      * @type Object
16087      */
16088      
16089     topModule  : false,
16090       
16091     /**
16092      * @property  modules
16093      * array of modules to be created by registration system.
16094      * @type {Array} of Roo.XComponent
16095      */
16096     
16097     modules : [],
16098     /**
16099      * @property  elmodules
16100      * array of modules to be created by which use #ID 
16101      * @type {Array} of Roo.XComponent
16102      */
16103      
16104     elmodules : [],
16105
16106      /**
16107      * @property  build_from_html
16108      * Build elements from html - used by bootstrap HTML stuff 
16109      *    - this is cleared after build is completed
16110      * @type {boolean} true  (default false)
16111      */
16112      
16113     build_from_html : false,
16114
16115     /**
16116      * Register components to be built later.
16117      *
16118      * This solves the following issues
16119      * - Building is not done on page load, but after an authentication process has occured.
16120      * - Interface elements are registered on page load
16121      * - Parent Interface elements may not be loaded before child, so this handles that..
16122      * 
16123      *
16124      * example:
16125      * 
16126      * MyApp.register({
16127           order : '000001',
16128           module : 'Pman.Tab.projectMgr',
16129           region : 'center',
16130           parent : 'Pman.layout',
16131           disabled : false,  // or use a function..
16132         })
16133      
16134      * * @param {Object} details about module
16135      */
16136     register : function(obj) {
16137                 
16138         Roo.XComponent.event.fireEvent('register', obj);
16139         switch(typeof(obj.disabled) ) {
16140                 
16141             case 'undefined':
16142                 break;
16143             
16144             case 'function':
16145                 if ( obj.disabled() ) {
16146                         return;
16147                 }
16148                 break;
16149             
16150             default:
16151                 if (obj.disabled) {
16152                         return;
16153                 }
16154                 break;
16155         }
16156                 
16157         this.modules.push(obj);
16158          
16159     },
16160     /**
16161      * convert a string to an object..
16162      * eg. 'AAA.BBB' -> finds AAA.BBB
16163
16164      */
16165     
16166     toObject : function(str)
16167     {
16168         if (!str || typeof(str) == 'object') {
16169             return str;
16170         }
16171         if (str.substring(0,1) == '#') {
16172             return str;
16173         }
16174
16175         var ar = str.split('.');
16176         var rt, o;
16177         rt = ar.shift();
16178             /** eval:var:o */
16179         try {
16180             eval('if (typeof ' + rt + ' == "undefined"){ o = false;} o = ' + rt + ';');
16181         } catch (e) {
16182             throw "Module not found : " + str;
16183         }
16184         
16185         if (o === false) {
16186             throw "Module not found : " + str;
16187         }
16188         Roo.each(ar, function(e) {
16189             if (typeof(o[e]) == 'undefined') {
16190                 throw "Module not found : " + str;
16191             }
16192             o = o[e];
16193         });
16194         
16195         return o;
16196         
16197     },
16198     
16199     
16200     /**
16201      * move modules into their correct place in the tree..
16202      * 
16203      */
16204     preBuild : function ()
16205     {
16206         var _t = this;
16207         Roo.each(this.modules , function (obj)
16208         {
16209             Roo.XComponent.event.fireEvent('beforebuild', obj);
16210             
16211             var opar = obj.parent;
16212             try { 
16213                 obj.parent = this.toObject(opar);
16214             } catch(e) {
16215                 Roo.debug && Roo.log("parent:toObject failed: " + e.toString());
16216                 return;
16217             }
16218             
16219             if (!obj.parent) {
16220                 Roo.debug && Roo.log("GOT top level module");
16221                 Roo.debug && Roo.log(obj);
16222                 obj.modules = new Roo.util.MixedCollection(false, 
16223                     function(o) { return o.order + '' }
16224                 );
16225                 this.topModule = obj;
16226                 return;
16227             }
16228                         // parent is a string (usually a dom element name..)
16229             if (typeof(obj.parent) == 'string') {
16230                 this.elmodules.push(obj);
16231                 return;
16232             }
16233             if (obj.parent.constructor != Roo.XComponent) {
16234                 Roo.debug && Roo.log("Warning : Object Parent is not instance of XComponent:" + obj.name)
16235             }
16236             if (!obj.parent.modules) {
16237                 obj.parent.modules = new Roo.util.MixedCollection(false, 
16238                     function(o) { return o.order + '' }
16239                 );
16240             }
16241             if (obj.parent.disabled) {
16242                 obj.disabled = true;
16243             }
16244             obj.parent.modules.add(obj);
16245         }, this);
16246     },
16247     
16248      /**
16249      * make a list of modules to build.
16250      * @return {Array} list of modules. 
16251      */ 
16252     
16253     buildOrder : function()
16254     {
16255         var _this = this;
16256         var cmp = function(a,b) {   
16257             return String(a).toUpperCase() > String(b).toUpperCase() ? 1 : -1;
16258         };
16259         if ((!this.topModule || !this.topModule.modules) && !this.elmodules.length) {
16260             throw "No top level modules to build";
16261         }
16262         
16263         // make a flat list in order of modules to build.
16264         var mods = this.topModule ? [ this.topModule ] : [];
16265                 
16266         
16267         // elmodules (is a list of DOM based modules )
16268         Roo.each(this.elmodules, function(e) {
16269             mods.push(e);
16270             if (!this.topModule &&
16271                 typeof(e.parent) == 'string' &&
16272                 e.parent.substring(0,1) == '#' &&
16273                 Roo.get(e.parent.substr(1))
16274                ) {
16275                 
16276                 _this.topModule = e;
16277             }
16278             
16279         });
16280
16281         
16282         // add modules to their parents..
16283         var addMod = function(m) {
16284             Roo.debug && Roo.log("build Order: add: " + m.name);
16285                 
16286             mods.push(m);
16287             if (m.modules && !m.disabled) {
16288                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules");
16289                 m.modules.keySort('ASC',  cmp );
16290                 Roo.debug && Roo.log("build Order: " + m.modules.length + " child modules (after sort)");
16291     
16292                 m.modules.each(addMod);
16293             } else {
16294                 Roo.debug && Roo.log("build Order: no child modules");
16295             }
16296             // not sure if this is used any more..
16297             if (m.finalize) {
16298                 m.finalize.name = m.name + " (clean up) ";
16299                 mods.push(m.finalize);
16300             }
16301             
16302         }
16303         if (this.topModule && this.topModule.modules) { 
16304             this.topModule.modules.keySort('ASC',  cmp );
16305             this.topModule.modules.each(addMod);
16306         } 
16307         return mods;
16308     },
16309     
16310      /**
16311      * Build the registered modules.
16312      * @param {Object} parent element.
16313      * @param {Function} optional method to call after module has been added.
16314      * 
16315      */ 
16316    
16317     build : function(opts) 
16318     {
16319         
16320         if (typeof(opts) != 'undefined') {
16321             Roo.apply(this,opts);
16322         }
16323         
16324         this.preBuild();
16325         var mods = this.buildOrder();
16326       
16327         //this.allmods = mods;
16328         //Roo.debug && Roo.log(mods);
16329         //return;
16330         if (!mods.length) { // should not happen
16331             throw "NO modules!!!";
16332         }
16333         
16334         
16335         var msg = "Building Interface...";
16336         // flash it up as modal - so we store the mask!?
16337         if (!this.hideProgress && Roo.MessageBox) {
16338             Roo.MessageBox.show({ title: 'loading' });
16339             Roo.MessageBox.show({
16340                title: "Please wait...",
16341                msg: msg,
16342                width:450,
16343                progress:true,
16344                closable:false,
16345                modal: false
16346               
16347             });
16348         }
16349         var total = mods.length;
16350         
16351         var _this = this;
16352         var progressRun = function() {
16353             if (!mods.length) {
16354                 Roo.debug && Roo.log('hide?');
16355                 if (!this.hideProgress && Roo.MessageBox) {
16356                     Roo.MessageBox.hide();
16357                 }
16358                 Roo.XComponent.build_from_html = false; // reset, so dialogs will be build from javascript
16359                 
16360                 Roo.XComponent.event.fireEvent('buildcomplete', _this.topModule);
16361                 
16362                 // THE END...
16363                 return false;   
16364             }
16365             
16366             var m = mods.shift();
16367             
16368             
16369             Roo.debug && Roo.log(m);
16370             // not sure if this is supported any more.. - modules that are are just function
16371             if (typeof(m) == 'function') { 
16372                 m.call(this);
16373                 return progressRun.defer(10, _this);
16374             } 
16375             
16376             
16377             msg = "Building Interface " + (total  - mods.length) + 
16378                     " of " + total + 
16379                     (m.name ? (' - ' + m.name) : '');
16380                         Roo.debug && Roo.log(msg);
16381             if (!this.hideProgress &&  Roo.MessageBox) { 
16382                 Roo.MessageBox.updateProgress(  (total  - mods.length)/total, msg  );
16383             }
16384             
16385          
16386             // is the module disabled?
16387             var disabled = (typeof(m.disabled) == 'function') ?
16388                 m.disabled.call(m.module.disabled) : m.disabled;    
16389             
16390             
16391             if (disabled) {
16392                 return progressRun(); // we do not update the display!
16393             }
16394             
16395             // now build 
16396             
16397                         
16398                         
16399             m.render();
16400             // it's 10 on top level, and 1 on others??? why...
16401             return progressRun.defer(10, _this);
16402              
16403         }
16404         progressRun.defer(1, _this);
16405      
16406         
16407         
16408     },
16409         
16410         
16411         /**
16412          * Event Object.
16413          *
16414          *
16415          */
16416         event: false, 
16417     /**
16418          * wrapper for event.on - aliased later..  
16419          * Typically use to register a event handler for register:
16420          *
16421          * eg. Roo.XComponent.on('register', function(comp) { comp.disable = true } );
16422          *
16423          */
16424     on : false
16425    
16426     
16427     
16428 });
16429
16430 Roo.XComponent.event = new Roo.util.Observable({
16431                 events : { 
16432                         /**
16433                          * @event register
16434                          * Fires when an Component is registered,
16435                          * set the disable property on the Component to stop registration.
16436                          * @param {Roo.XComponent} c the component being registerd.
16437                          * 
16438                          */
16439                         'register' : true,
16440             /**
16441                          * @event beforebuild
16442                          * Fires before each Component is built
16443                          * can be used to apply permissions.
16444                          * @param {Roo.XComponent} c the component being registerd.
16445                          * 
16446                          */
16447                         'beforebuild' : true,
16448                         /**
16449                          * @event buildcomplete
16450                          * Fires on the top level element when all elements have been built
16451                          * @param {Roo.XComponent} the top level component.
16452                          */
16453                         'buildcomplete' : true
16454                         
16455                 }
16456 });
16457
16458 Roo.XComponent.on = Roo.XComponent.event.on.createDelegate(Roo.XComponent.event); 
16459